diff --git a/toonz/sources/include/tools/modifiers/modifierjitter.h b/toonz/sources/include/tools/modifiers/modifierjitter.h index d67994d..b2ee006 100644 --- a/toonz/sources/include/tools/modifiers/modifierjitter.h +++ b/toonz/sources/include/tools/modifiers/modifierjitter.h @@ -32,7 +32,14 @@ public: const unsigned int seedY; const double frequency; const double amplitude; - Interpolator(TTrack &track, double period, double amplitude); + const bool keepFirstPoint; + const bool keepLastPoint; + Interpolator( + TTrack &track, + double period, + double amplitude, + bool keepFirstPoint, + bool keepLastPoint ); TTrackPoint interpolateFromOriginal(double originalIndex); TTrackPoint interpolate(double index) override; }; @@ -42,12 +49,16 @@ public: double amplitude; int skipFirst; int skipLast; + bool keepFirstPoint; + bool keepLastPoint; explicit TModifierJitter( double period = 30, double amplitude = 10, int skipFirst = 0, - int skipLast = 0 ); + int skipLast = 0, + bool keepFirstPoint = false, + bool keepLastPoint = false ); void modifyTrack( const TTrack &track, diff --git a/toonz/sources/include/tools/replicator.h b/toonz/sources/include/tools/replicator.h index e0b159f..71c89b4 100644 --- a/toonz/sources/include/tools/replicator.h +++ b/toonz/sources/include/tools/replicator.h @@ -42,6 +42,11 @@ public: inline int getSkipLast() const { return std::max(0, (int)data()[m_idSkipLast].getDouble()); } + inline void setSkipFirst(int x) + { if (getSkipFirst() != (double)x) data()[m_idSkipFirst].setDouble((double)x); } + inline void setSkipLast(int x) + { if (getSkipLast() != (double)x) data()[m_idSkipLast].setDouble((double)x); } + virtual int getMultipler() const; virtual void getPoints(const TAffine &toTool, PointList &points) const; virtual void getModifiers(const TAffine &toTool, TInputModifier::List &outModifiers) const; @@ -61,11 +66,6 @@ public: TImage *skipImage ); protected: - inline void setSkipFirst(int x) - { if (getSkipFirst() != (double)x) data()[m_idSkipFirst].setDouble((double)x); } - inline void setSkipLast(int x) - { if (getSkipLast() != (double)x) data()[m_idSkipLast].setDouble((double)x); } - TIntProperty* createCountProperty(const TStringId &id, int def = 1, int min = 1, int max = 0); }; diff --git a/toonz/sources/tnztools/assistants/replicatorjitter.cpp b/toonz/sources/tnztools/assistants/replicatorjitter.cpp index 4daeb4b..433a432 100644 --- a/toonz/sources/tnztools/assistants/replicatorjitter.cpp +++ b/toonz/sources/tnztools/assistants/replicatorjitter.cpp @@ -18,6 +18,8 @@ class TReplicatorJitter final : public TReplicator { public: const TStringId m_idPeriod; const TStringId m_idAmplitude; + const TStringId m_idKeepFirstPoint; + const TStringId m_idKeepLastPoint; protected: TAssistantPoint &m_center; @@ -26,7 +28,9 @@ public: TReplicatorJitter(TMetaObject &object): TReplicator(object), m_idPeriod("period"), - m_idAmplitude("m_idAmplitude"), + m_idAmplitude("amplitude"), + m_idKeepFirstPoint("keepFirstPoint"), + m_idKeepLastPoint("keepLastPoint"), m_center( addPoint("center", TAssistantPoint::CircleCross) ) { TDoubleProperty *p; @@ -38,6 +42,9 @@ public: p = new TDoubleProperty(m_idAmplitude.str(), 0.0, 1000, getAmplitude()); p->setNonLinearSlider(); addProperty(p); + + addProperty( new TBoolProperty(m_idKeepFirstPoint.str(), getKeepFirstPoint()) ); + addProperty( new TBoolProperty(m_idKeepLastPoint.str(), getKeepLastPoint()) ); } @@ -49,6 +56,8 @@ public: TReplicator::updateTranslation(); setTranslation(m_idPeriod, tr("Period")); setTranslation(m_idAmplitude, tr("Amplitude")); + setTranslation(m_idKeepFirstPoint, tr("Fix First Point")); + setTranslation(m_idKeepLastPoint, tr("Fix Last Point")); } @@ -56,6 +65,10 @@ public: { return data()[m_idPeriod].getDouble(); } inline double getAmplitude() const { return data()[m_idAmplitude].getDouble(); } + inline bool getKeepFirstPoint() const + { return data()[m_idKeepFirstPoint].getBool(); } + inline bool getKeepLastPoint() const + { return data()[m_idKeepLastPoint].getBool(); } protected: inline void setPeriod(double x) @@ -100,8 +113,8 @@ public: int seedX = 0; int seedY = 7722441; for(int i = i0; i < i1; ++i) { - points[i].x += TModifierJitter::func(seedX, 0)*amplitude; - points[i].y += TModifierJitter::func(seedY, 0)*amplitude; + points[i].x += TModifierJitter::func(seedX, points[i].x/period)*amplitude; + points[i].y += TModifierJitter::func(seedY, points[i].y/period)*amplitude; ++seedX, ++seedY; } } @@ -117,7 +130,9 @@ public: getPeriod()*scale, getAmplitude()*scale, getSkipFirst(), - getSkipLast() )); + getSkipLast(), + getKeepFirstPoint(), + getKeepLastPoint() )); } diff --git a/toonz/sources/tnztools/editassistantstool.cpp b/toonz/sources/tnztools/editassistantstool.cpp index 0a9186a..67cd997 100644 --- a/toonz/sources/tnztools/editassistantstool.cpp +++ b/toonz/sources/tnztools/editassistantstool.cpp @@ -502,7 +502,7 @@ protected: m_currentImage.set(m_readImage); if (index < (*m_reader)->size()) if (const TMetaObjectPC &obj = (**m_reader)[index]) - if (const TAssistant *assistant = obj->getHandler()) { + if (const TAssistantBase *assistant = obj->getHandler()) { assistant->deselectAll(); m_currentAssistant.set(obj); m_currentAssistantIndex = index; diff --git a/toonz/sources/tnztools/modifiers/modifierjitter.cpp b/toonz/sources/tnztools/modifiers/modifierjitter.cpp index 0a8eee5..61a5c72 100644 --- a/toonz/sources/tnztools/modifiers/modifierjitter.cpp +++ b/toonz/sources/tnztools/modifiers/modifierjitter.cpp @@ -81,20 +81,46 @@ static inline unsigned int trackSeedY(const TTrack &track) { //***************************************************************************************** -TModifierJitter::Interpolator::Interpolator(TTrack &track, double period, double amplitude): +TModifierJitter::Interpolator::Interpolator( + TTrack &track, + double period, + double amplitude, + bool keepFirstPoint, + bool keepLastPoint +): TTrackInterpolator(track), seedX(trackSeedX(track)), seedY(trackSeedY(track)), frequency(fabs(period) > TConsts::epsilon ? 1/period : 0), - amplitude(fabs(period) > TConsts::epsilon ? amplitude : 0) + amplitude(fabs(period) > TConsts::epsilon ? amplitude : 0), + keepFirstPoint(keepFirstPoint), + keepLastPoint(keepLastPoint) { } TTrackPoint TModifierJitter::Interpolator::interpolateFromOriginal(double originalIndex) { TTrackPoint p = track.calcPointFromOriginal(originalIndex); + double a = amplitude; double l = p.length*frequency; - p.position.x += Jitter::func(seedX, l)*amplitude; - p.position.y += Jitter::func(seedY, l)*amplitude; + if (frequency && a && track.original && (keepFirstPoint || keepLastPoint)) { + double ll = track.original->back().length*frequency; + if (l < 0) l = 0; + if (l > ll) l = ll; + if (ll < TConsts::epsilon) { + a = 0; + } else + if (keepFirstPoint && keepLastPoint && ll < 2) { + a *= 0.5 - 0.5*cos(l/ll*M_2PI); + } else + if (keepFirstPoint && l < 1) { + a *= 0.5 - 0.5*cos(l*M_PI); + } else + if (keepLastPoint && (ll - l) < 1) { + a *= 0.5 - 0.5*cos((ll - l)*M_PI); + } + } + p.position.x += Jitter::func(seedX, l)*a; + p.position.y += Jitter::func(seedY, l)*a; return p; } @@ -109,8 +135,21 @@ TTrackPoint TModifierJitter::Interpolator::interpolate(double index) //***************************************************************************************** -TModifierJitter::TModifierJitter(double period, double amplitude, int skipFirst, int skipLast): - period(period), amplitude(amplitude), skipFirst(skipFirst), skipLast(skipLast) { } +TModifierJitter::TModifierJitter( + double period, + double amplitude, + int skipFirst, + int skipLast, + bool keepFirstPoint, + bool keepLastPoint +): + period(period), + amplitude(amplitude), + skipFirst(skipFirst), + skipLast(skipLast), + keepFirstPoint(keepFirstPoint), + keepLastPoint(keepLastPoint) +{ } void TModifierJitter::modifyTrack(const TTrack &track, @@ -120,7 +159,7 @@ void TModifierJitter::modifyTrack(const TTrack &track, Handler *handler = new Handler(); track.handler = handler; handler->track = new TTrack(track); - new Interpolator(*handler->track, period, amplitude); + new Interpolator(*handler->track, period, amplitude, keepFirstPoint, keepLastPoint); } Handler *handler = dynamic_cast(track.handler.getPointer()); @@ -137,8 +176,14 @@ void TModifierJitter::modifyTrack(const TTrack &track, if (!intr) return; + bool preview = intr->keepLastPoint && intr->frequency && intr->amplitude; + int start = track.size() - track.pointsAdded; if (start < 0) start = 0; + if (preview) { + double l = track[start].length - 1/intr->frequency; + start = track.floorIndex( track.indexByLength(l) ); + } // process sub-track subTrack.truncate(start); @@ -146,7 +191,13 @@ void TModifierJitter::modifyTrack(const TTrack &track, subTrack.push_back(intr->interpolateFromOriginal(i), false); // fit points - subTrack.fix_to(track.fixedSize()); + if (track.fixedFinished() || !preview) { + subTrack.fix_to(track.fixedSize()); + } else + if (track.fixedSize()) { + double l = track[track.fixedSize() - 1].length - 1/intr->frequency; + subTrack.fix_to(subTrack.floorIndex( track.indexByLength(l) )); + } track.resetChanges(); }