|
|
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 |
|