00b1a0
00b1a0
#include <tools modifierjitter.h="" modifiers=""></tools>
00b1a0
00b1a0
00b1a0
00b1a0
//*****************************************************************************************
00b1a0
//    static functions
00b1a0
//*****************************************************************************************
00b1a0
00b1a0
00b1a0
namespace {
00b1a0
00b1a0
class Jitter {
00b1a0
public:
00b1a0
  static inline double randomNext(unsigned int &seed) {
00b1a0
    static const unsigned int max = 32767;
00b1a0
    static const double k = 1.0/max;
00b1a0
    seed = ((1103515245*seed + 12345) >> 16) & max;
00b1a0
    return seed*k;
00b1a0
  }
00b1a0
00b1a0
  static TPointD getPoint(unsigned int seed, int i, double *prevX = nullptr) {
00b1a0
    unsigned int pseed = seed^i;
00b1a0
    double dx = randomNext(pseed);
00b1a0
    double dy = randomNext(pseed)*2 - 1;
00b1a0
    if (dx < 0.5) {
00b1a0
      double px = prevX ? *prevX : getPoint(seed, i-1).x;
00b1a0
      px += 0.5 - i;
00b1a0
      if (dx < px)
00b1a0
        dx = randomNext(pseed)*(1 - px) + px;
00b1a0
    }
00b1a0
    return TPointD(dx + i, dy);
00b1a0
  }
00b1a0
00b1a0
  static inline double spline(double x, TPointD *points) {
00b1a0
    double x0 = points[1].x;
00b1a0
    double y0 = points[1].y;
00b1a0
    double x1 = points[2].x;
00b1a0
    double y1 = points[2].y;
00b1a0
    double t0 = (y1 - points[0].y)/(x1 - points[0].x)*(x1 - x0);
00b1a0
    double t1 = (points[3].y - y0)/(points[3].x - x0)*(x1 - x0);
00b1a0
00b1a0
    double l = (x - x0)/(x1 - x0);
00b1a0
    double ll = l*l;
00b1a0
    double lll = ll*l;
00b1a0
00b1a0
    return y0*( 2*lll - 3*ll + 1)
00b1a0
         + y1*(-2*lll + 3*ll    )
00b1a0
         + t0*(   lll - 2*ll + l)
00b1a0
         + t1*(   lll -   ll    );
00b1a0
  }
00b1a0
00b1a0
  static inline double func(unsigned int seed, double x) {
00b1a0
    int i = (int)floor(x);
00b1a0
    TPointD points[5];
00b1a0
    points[0] = getPoint(seed, i-2);
00b1a0
    for(int j = 1; j < 5; ++j)
00b1a0
      points[j] = getPoint(seed, i-2+j, &points[j-1].x);
00b1a0
    return spline(x, &points[ x < points[2].x ? 0 : 1 ]);
00b1a0
  }
00b1a0
};
00b1a0
00b1a0
static inline unsigned int trackSeedX(const TTrack &track) {
00b1a0
  unsigned int seed = track.id;
00b1a0
  Jitter::randomNext(seed);
00b1a0
  return seed;
00b1a0
}
00b1a0
00b1a0
static inline unsigned int trackSeedY(const TTrack &track) {
00b1a0
  unsigned int seed = track.id^32143;
00b1a0
  Jitter::randomNext(seed);
00b1a0
  return seed;
00b1a0
}
00b1a0
00b1a0
} // namespace
00b1a0
00b1a0
00b1a0
00b1a0
//*****************************************************************************************
00b1a0
//    TModifierJitter::Interpolator implementation
00b1a0
//*****************************************************************************************
00b1a0
00b1a0
00b1a0
TModifierJitter::Interpolator::Interpolator(TTrack &track, double period, double amplitude):
00b1a0
  TTrackInterpolator(track),
00b1a0
  seedX(trackSeedX(track)),
00b1a0
  seedY(trackSeedY(track)),
00b1a0
  frequency(fabs(period) > TConsts::epsilon ? 1/period : 0),
00b1a0
  amplitude(fabs(period) > TConsts::epsilon ? amplitude : 0)
00b1a0
  { }
00b1a0
00b1a0
00b1a0
TTrackPoint TModifierJitter::Interpolator::interpolateFromOriginal(double originalIndex) {
00b1a0
  TTrackPoint p = track.calcPointFromOriginal(originalIndex);
00b1a0
  double l = p.length*frequency;
00b1a0
  p.position.x += Jitter::func(seedX, l)*amplitude;
00b1a0
  p.position.y += Jitter::func(seedY, l)*amplitude;
00b1a0
  return p;
00b1a0
}
00b1a0
00b1a0
00b1a0
TTrackPoint TModifierJitter::Interpolator::interpolate(double index)
00b1a0
  { return interpolateFromOriginal(track.originalIndexByIndex(index)); }
00b1a0
00b1a0
00b1a0
 
00b1a0
//*****************************************************************************************
00b1a0
//    TModifierJitter implementation
00b1a0
//*****************************************************************************************
00b1a0
00b1a0
00b1a0
TModifierJitter::TModifierJitter(double period, double amplitude, int skipFirst):
00b1a0
  period(period), amplitude(amplitude), skipFirst(skipFirst) { }
00b1a0
00b1a0
00b1a0
void TModifierJitter::modifyTrack(const TTrack &track,
00b1a0
                                  TTrackList &outTracks)
00b1a0
{
00b1a0
  if (!track.handler && fabs(period) > TConsts::epsilon) {
00b1a0
    Handler *handler = new Handler();
00b1a0
    track.handler = handler;
00b1a0
    handler->track = new TTrack(track);
00b1a0
    new Interpolator(*handler->track, period, amplitude);
00b1a0
  }
00b1a0
  
00b1a0
  Handler *handler = dynamic_cast<handler*>(track.handler.getPointer());</handler*>
00b1a0
  if (!handler)
00b1a0
    return TInputModifier::modifyTrack(track, outTracks);
00b1a0
  
00b1a0
  outTracks.push_back(handler->track);
00b1a0
  TTrack &subTrack = *handler->track;
00b1a0
  
00b1a0
  if (!track.changed())
00b1a0
    return;
00b1a0
00b1a0
  Interpolator *intr = dynamic_cast<interpolator*>(subTrack.getInterpolator().getPointer());</interpolator*>
00b1a0
  if (!intr)
00b1a0
    return;
00b1a0
00b1a0
  int start = track.size() - track.pointsAdded;
00b1a0
  if (start < 0) start = 0;
00b1a0
00b1a0
  // process sub-track
00b1a0
  subTrack.truncate(start);
00b1a0
  for (int i = start; i < track.size(); ++i)
00b1a0
    subTrack.push_back(intr->interpolateFromOriginal(i), false);
00b1a0
  
00b1a0
  // fit points
00b1a0
  subTrack.fix_to(track.fixedSize());
00b1a0
  
00b1a0
  track.resetChanges();
00b1a0
}
00b1a0
00b1a0
00b1a0
void
00b1a0
TModifierJitter::modifyTracks(
00b1a0
    const TTrackList &tracks,
00b1a0
    TTrackList &outTracks )
00b1a0
{
00b1a0
  int cnt = std::min( std::max(0, skipFirst), (int)tracks.size() );
00b1a0
  TTrackList::const_iterator split = tracks.begin() + cnt;
00b1a0
  for(TTrackList::const_iterator i = tracks.begin(); i != split; ++i)
00b1a0
    TInputModifier::modifyTrack(**i, outTracks);
00b1a0
  for(TTrackList::const_iterator i = split; i != tracks.end(); ++i)
00b1a0
    modifyTrack(**i, outTracks);
00b1a0
}
00b1a0
00b1a0
00b1a0
double TModifierJitter::func(unsigned int seed, double x)
00b1a0
  { return Jitter::func(seed, x); }
00b1a0
00b1a0