diff --git a/toonz/sources/include/tgeometry.h b/toonz/sources/include/tgeometry.h
index f5c9a81..f5887cb 100644
--- a/toonz/sources/include/tgeometry.h
+++ b/toonz/sources/include/tgeometry.h
@@ -202,6 +202,16 @@ inline TPointD normalize(const TPointD &p) {
 
 /*!
 \relates TPointT
+This helper function returns the normalized version of the specified point
+or zero if it is not possible
+*/
+inline TPointD normalizeOrZero(const TPointD &p) {
+  double n = norm2(p);
+  return fabs(n) > TConsts::epsilon*TConsts::epsilon ? p*(1/sqrt(n)) : TPointD();
+}
+
+/*!
+\relates TPointT
 This helper function converts a TPoint (TPointT<int>) into a TPointD
 */
 inline TPointD convert(const TPoint &p) { return TPointD(p.x, p.y); }
diff --git a/toonz/sources/include/tools/modifiers/modifierassistants.h b/toonz/sources/include/tools/modifiers/modifierassistants.h
index 0ba8059..a040a8c 100644
--- a/toonz/sources/include/tools/modifiers/modifierassistants.h
+++ b/toonz/sources/include/tools/modifiers/modifierassistants.h
@@ -26,13 +26,16 @@
 
 class DVAPI TModifierAssistants: public TInputModifier {
 public:
-  class DVAPI Modifier: public TTrackModifier {
+  typedef TSubTrackHandler Handler;
+  class DVAPI Interpolator: public TTrackInterpolator {
   public:
-    bool initialized;
+    const double magnetism;
     TGuidelineList guidelines;
-
-    Modifier(TTrackHandler &handler);
-    TTrackPoint calcPoint(double originalIndex) override;
+    inline Interpolator(TTrack &track, double magnetism):
+      TTrackInterpolator(track),
+      magnetism(magnetism > 0 ? (magnetism < 1 ? magnetism : 1) : 0)
+      { }
+    TTrackPoint interpolate(double index) override;
   };
 
 private:
@@ -44,10 +47,10 @@ private:
     bool enabledOnly ) const;
 
 public:
-  bool drawOnly;
+  double magnetism;
   double sensitiveLength;
 
-  explicit TModifierAssistants(bool drawOnly = false);
+  explicit TModifierAssistants(double magnetism = 1);
 
   void modifyTrack(
     const TTrack &track,
diff --git a/toonz/sources/include/tools/modifiers/modifierline.h b/toonz/sources/include/tools/modifiers/modifierline.h
index 495f711..622e2ae 100644
--- a/toonz/sources/include/tools/modifiers/modifierline.h
+++ b/toonz/sources/include/tools/modifiers/modifierline.h
@@ -24,17 +24,12 @@
 //    TModifierLine definition
 //*****************************************************************************************
 
-class TModifierLine: public TInputModifier {
+class DVAPI TModifierLine: public TInputModifier {
 public:
-  class Modifier: public TTrackModifier {
+  class DVAPI Handler: public TSubTrackHandler {
   public:
-    explicit Modifier(TTrackHandler &handler):
-      TTrackModifier(handler), fixAngle(), maxPressure() { }
-
-    bool fixAngle;
     double maxPressure;
-    
-    TTrackPoint calcPoint(double originalIndex) override;
+    inline Handler(): maxPressure() { }
   };
 
   void modifyTrack(
diff --git a/toonz/sources/include/tools/modifiers/modifiersegmentation.h b/toonz/sources/include/tools/modifiers/modifiersegmentation.h
index e706d5c..acfb76b 100644
--- a/toonz/sources/include/tools/modifiers/modifiersegmentation.h
+++ b/toonz/sources/include/tools/modifiers/modifiersegmentation.h
@@ -25,6 +25,10 @@
 //*****************************************************************************************
 
 class DVAPI TModifierSegmentation: public TInputModifier {
+public:
+  typedef TSubTrackHandler Handler;
+  typedef TTrackIntrOrig Interpolator;
+  
 private:
   TPointD m_step;
   int m_maxLevel;
diff --git a/toonz/sources/include/tools/modifiers/modifiersimplify.h b/toonz/sources/include/tools/modifiers/modifiersimplify.h
index 6f353b8..155dd4a 100644
--- a/toonz/sources/include/tools/modifiers/modifiersimplify.h
+++ b/toonz/sources/include/tools/modifiers/modifiersimplify.h
@@ -25,15 +25,14 @@
 //*****************************************************************************************
 
 class DVAPI TModifierSimplify: public TInputModifier {
-private:
+public:
+  typedef TSubTrackHandler Handler;
+  typedef TTrackIntrOrig Interpolator;
+  
   double step;
   
-public:
   explicit TModifierSimplify(double step = 1.0);
 
-  void setStep(double step);
-  inline double getStep() const { return step; }
-
   void modifyTrack(
     const TTrack &track,
     TTrackList &outTracks ) override;
diff --git a/toonz/sources/include/tools/modifiers/modifiersmooth.h b/toonz/sources/include/tools/modifiers/modifiersmooth.h
index 193db53..e814b73 100644
--- a/toonz/sources/include/tools/modifiers/modifiersmooth.h
+++ b/toonz/sources/include/tools/modifiers/modifiersmooth.h
@@ -26,23 +26,15 @@
 
 class DVAPI TModifierSmooth: public TInputModifier {
 public:
-  class DVAPI Modifier: public TTrackModifier {
+  class DVAPI Handler: public TSubTrackHandler {
   public:
     const int radius;
-    TTrack *smoothedTrack;
-
-    Modifier(TTrackHandler &handler, int radius);
-    TTrackPoint calcPoint(double originalIndex) override;
+    inline explicit Handler(int radius): radius(radius) { }
   };
 
-private:
-  int m_radius;
-  
-public:
-  explicit TModifierSmooth(int radius = 10);
+  int radius;
 
-  void setRadius(int radius);
-  int getRadius() const { return m_radius; }
+  explicit TModifierSmooth(int radius = 10);
   
   void modifyTrack(
     const TTrack &track,
diff --git a/toonz/sources/include/tools/modifiers/modifiertangents.h b/toonz/sources/include/tools/modifiers/modifiertangents.h
index a7e6232..960564e 100644
--- a/toonz/sources/include/tools/modifiers/modifiertangents.h
+++ b/toonz/sources/include/tools/modifiers/modifiertangents.h
@@ -26,17 +26,15 @@
 
 class DVAPI TModifierTangents: public TInputModifier {
 public:
-  class DVAPI Modifier: public TTrackModifier {
+  typedef TSubTrackHandler Handler;
+  class DVAPI Interpolator: public TTrackInterpolator {
   public:
-    explicit Modifier(TTrackHandler &handler):
-      TTrackModifier(handler) { }
-
     TTrackTangentList tangents;
-
-    TTrackPoint calcPoint(double originalIndex) override;
+    using TTrackInterpolator::TTrackInterpolator;
+    TTrackPoint interpolate(double index) override;
   };
 
-  TTrackTangent calcTangent(const TTrack &track, int index) const;
+  static TTrackTangent calcTangent(const TTrack &track, int index);
 
   void modifyTrack(
     const TTrack &track,
diff --git a/toonz/sources/include/tools/modifiers/modifiertest.h b/toonz/sources/include/tools/modifiers/modifiertest.h
index e410547..4732695 100644
--- a/toonz/sources/include/tools/modifiers/modifiertest.h
+++ b/toonz/sources/include/tools/modifiers/modifiertest.h
@@ -26,28 +26,31 @@
 
 class DVAPI TModifierTest : public TInputModifier {
 public:
-  class DVAPI Handler : public TTrackHandler {
+  class DVAPI Handler : public TMultiTrackHandler {
   public:
+    const double radius;
     std::vector<double> angles;
-    Handler(const TTrack &original) : TTrackHandler(original) {}
+    inline explicit Handler(double radius):
+      radius(std::max(TConsts::epsilon, radius)) { }
   };
 
-  class DVAPI Modifier : public TTrackModifier {
+  class DVAPI Interpolator : public TTrackInterpolator {
   public:
-    double angle;
-    double radius;
-    double speed;
-
-    Modifier(TTrackHandler &handler, double angle, double radius,
-             double speed = 0.25);
-    TTrackPoint calcPoint(double originalIndex) override;
+    const double angle;
+    const double radius;
+    const double speed;
+    inline Interpolator(TTrack &track, double angle, double radius, double speed):
+      TTrackInterpolator(track), angle(angle), radius(radius), speed(speed) { }
+    TTrackPoint interpolateFromOriginal(double originalIndex);
+    TTrackPoint interpolate(double index) override;
   };
 
 public:
-  const int count;
-  const double radius;
+  int count;
+  double radius;
+  double speed;
 
-  TModifierTest(int count, double radius);
+  TModifierTest(int count = 3, double radius = 40, double speed = 0.25);
 
   void modifyTrack(const TTrack &track,
                    TTrackList &outTracks) override;
diff --git a/toonz/sources/include/tools/track.h b/toonz/sources/include/tools/track.h
index c9268d4..a8177b3 100644
--- a/toonz/sources/include/tools/track.h
+++ b/toonz/sources/include/tools/track.h
@@ -37,13 +37,15 @@ class TTrack;
 class TTrackPoint;
 class TTrackTangent;
 class TTrackHandler;
-class TTrackToolHandler;
-class TTrackModifier;
+class TSubTrackHandler;
+class TMultiTrackHandler;
+class TTrackInterpolator;
 
 typedef TSmartPointerT<TTrack> TTrackP;
 typedef TSmartPointerT<TTrackHandler> TTrackHandlerP;
-typedef TSmartPointerT<TTrackToolHandler> TTrackToolHandlerP;
-typedef TSmartPointerT<TTrackModifier> TTrackModifierP;
+typedef TSmartPointerT<TSubTrackHandler> TSubTrackHandlerP;
+typedef TSmartPointerT<TMultiTrackHandler> TMultiTrackHandlerP;
+typedef TSmartPointerT<TTrackInterpolator> TTrackInterpolatorP;
 
 typedef std::vector<TTrackPoint> TTrackPointList;
 typedef std::vector<TTrackTangent> TTrackTangentList;
@@ -53,21 +55,15 @@ typedef std::vector<TTrackP> TTrackList;
 
 
 //*****************************************************************************************
-//    TTrackToolHandler definition
-//*****************************************************************************************
-
-class DVAPI TTrackToolHandler : public TSmartObject { };
-
-
-//*****************************************************************************************
 //    export template implementations for win32
 //*****************************************************************************************
 
 #ifdef _WIN32
 template class DVAPI TSmartPointerT<TTrack>;
 template class DVAPI TSmartPointerT<TTrackHandler>;
-template class DVAPI TSmartPointerT<TTrackToolHandler>;
-template class DVAPI TSmartPointerT<TTrackModifier>;
+template class DVAPI TSmartPointerT<TSubTrackHandler>;
+template class DVAPI TSmartPointerT<TMultiTrackHandler>;
+template class DVAPI TSmartPointerT<TTrackInterpolator>;
 #endif
 
 
@@ -133,28 +129,38 @@ public:
 //    TTrackHandler definition
 //*****************************************************************************************
 
-class DVAPI TTrackHandler : public TSmartObject {
+class DVAPI TTrackHandler : public TSmartObject { };
+
+
+//*****************************************************************************************
+//    TSubTrackHandler definition
+//*****************************************************************************************
+
+class DVAPI TSubTrackHandler: public TTrackHandler {
 public:
-  const TTrack &original;
-  std::vector<TTrackP> tracks;
-  TTrackHandler(const TTrack &original):
-    original(original) { }
+  TTrackP track;
 };
 
 
 //*****************************************************************************************
-//    TTrackModifier definition
+//    TMultiTrackHandler definition
 //*****************************************************************************************
 
-class DVAPI TTrackModifier : public TSmartObject {
+class DVAPI TMultiTrackHandler: public TTrackHandler {
 public:
-    TTrackHandler &handler;
-    const TTrack &original;
-    const double timeOffset;
+  std::vector<TTrackP> tracks;
+};
+
+
+//*****************************************************************************************
+//    TTrackInterpolator definition
+//*****************************************************************************************
 
-    explicit TTrackModifier(TTrackHandler &handler, double timeOffset = 0.0):
-      handler(handler), original(handler.original), timeOffset(timeOffset) { }
-    virtual TTrackPoint calcPoint(double originalIndex);
+class DVAPI TTrackInterpolator : public TSmartObject {
+public:
+  TTrack &track;
+  inline explicit TTrackInterpolator(TTrack &track);
+  virtual TTrackPoint interpolate(double index) = 0;
 };
 
 
@@ -177,15 +183,19 @@ public:
   const TInputState::ButtonHistory::Holder buttonHistory;
   const bool hasPressure;
   const bool hasTilt;
-  const TTrackModifierP modifier;
 
+  const TTrack* const original;
+  const double timeOffset;
+  const double rootTimeOffset;
+  
   mutable TTrackHandlerP handler;
-  mutable TTrackToolHandlerP toolHandler;
   mutable int pointsRemoved;
   mutable int pointsAdded;
   mutable int fixedPointsAdded;
 
 private:
+  friend class TTrackInterpolator;
+  TTrackInterpolatorP interpolator;
   TTrackPointList m_points;
   const TTrackPoint m_none;
   int m_pointsFixed;
@@ -198,15 +208,17 @@ public:
     const TInputState::KeyHistory::Holder &keyHistory = TInputState::KeyHistory::Holder(),
     const TInputState::ButtonHistory::Holder &buttonHistory = TInputState::ButtonHistory::Holder(),
     bool hasPressure = false,
-    bool hasTilt = false
+    bool hasTilt = false,
+    double timeOffset = 0
   );
 
-  explicit TTrack(const TTrackModifierP &modifier);
+  explicit TTrack(const TTrack &original, double timeOffset = 0);
+
+  const TTrackInterpolatorP& getInterpolator() const
+    { return interpolator; }
+  void removeInterpolator()
+    { interpolator.reset(); }
 
-  inline const TTrack* original() const
-    { return modifier ? &modifier->original : NULL; }
-  inline double timeOffset() const
-    { return modifier ? modifier->timeOffset : 0.0; }
   inline TTimerTicks ticks() const
     { return keyHistory.ticks(); }
   inline bool changed() const
@@ -217,12 +229,14 @@ public:
 
   inline int clampIndex(int index) const
     { return std::min(std::max(index, 0), size() - 1); }
+  inline double clampIndexFloat(double index) const
+    { return std::min(std::max(index, 0.0), (double)(size() - 1)); }
   inline int floorIndexNoClamp(double index) const
     { return (int)floor(index + TConsts::epsilon); }
   inline int floorIndex(double index) const
     { return clampIndex(floorIndexNoClamp(index)); }
   inline int ceilIndexNoClamp(double index) const
-    { return (int)ceil(index - TConsts::epsilon); }
+    { return floorIndexNoClamp(index) + 1; }
   inline int ceilIndex(double index) const
     { return clampIndex(ceilIndexNoClamp(index)); }
 
@@ -287,15 +301,15 @@ public:
   inline TInputState::KeyState::Holder getKeyState(double time) const
     { return keyHistory.get(time); }
   inline TInputState::KeyState::Holder getKeyState(const TTrackPoint &point) const
-    { return getKeyState(timeOffset() + point.time); }
+    { return getKeyState(rootTimeOffset + point.time); }
   inline TInputState::KeyState::Holder getCurrentKeyState() const
-    { return getKeyState(timeOffset() + current().time); }
+    { return getKeyState(rootTimeOffset + current().time); }
   inline TInputState::ButtonState::Holder getButtonState(double time) const
     { return buttonHistory.get(time); }
   inline TInputState::ButtonState::Holder getButtonState(const TTrackPoint &point) const
-    { return getButtonState(timeOffset() + point.time); }
+    { return getButtonState(rootTimeOffset + point.time); }
   inline TInputState::ButtonState::Holder getCurrentButtonState() const
-    { return getButtonState(timeOffset() + current().time); }
+    { return getButtonState(rootTimeOffset + current().time); }
 
 private:
   template<double TTrackPoint::*Field>
@@ -345,11 +359,25 @@ public:
     return interpolationLinear(p0.length, p1.length, frac);
   }
 
-  TTrackPoint calcPoint(double index) const;
+  inline TTrackPoint calcPoint(double index) const
+    { return interpolator ? interpolator->interpolate(index) : interpolateLinear(index); }
   TPointD calcTangent(double index, double distance = 0.1) const;
   double rootIndexByIndex(double index) const;
   TTrackPoint calcRootPoint(double index) const;
 
+  inline TTrackPoint pointFromOriginal(const TTrackPoint &originalPoint, double originalIndex) const {
+    TTrackPoint p = originalPoint;
+    p.originalIndex = original ? original->clampIndexFloat(originalIndex) : originalIndex;
+    p.time -= timeOffset;
+    return p;
+  }
+  
+  inline TTrackPoint pointFromOriginal(int originalIndex) const
+    { return original ? pointFromOriginal(original->point(originalIndex), originalIndex) : TTrackPoint(); }
+  
+  inline TTrackPoint calcPointFromOriginal(double originalIndex) const
+    { return original ? pointFromOriginal(original->calcPoint(originalIndex), originalIndex) : TTrackPoint(); }
+
   inline TTrackPoint interpolateLinear(double index) const {
     double frac;
     const TTrackPoint &p0 = floorPoint(index, &frac);
@@ -407,4 +435,24 @@ public:
 };
 
 
+
+//*****************************************************************************************
+//    TTrackInterpolator implemantation
+//*****************************************************************************************
+
+inline TTrackInterpolator::TTrackInterpolator(TTrack &track):
+  track(track) { track.interpolator = this; }
+
+
+//*****************************************************************************************
+//    TTrackIntrOrig definition
+//*****************************************************************************************
+
+class DVAPI TTrackIntrOrig : public TTrackInterpolator {
+public:
+  using TTrackInterpolator::TTrackInterpolator;
+  TTrackPoint interpolate(double index) override;
+};
+
+
 #endif
diff --git a/toonz/sources/tnztools/fullcolorbrushtool.cpp b/toonz/sources/tnztools/fullcolorbrushtool.cpp
index c89c0ad..91b0aad 100644
--- a/toonz/sources/tnztools/fullcolorbrushtool.cpp
+++ b/toonz/sources/tnztools/fullcolorbrushtool.cpp
@@ -150,7 +150,7 @@ FullColorBrushTool::FullColorBrushTool(std::string name)
 
   m_inputmanager.setHandler(this);
 #ifndef NDEBUG
-  m_modifierTest = new TModifierTest(5, 40);
+  m_modifierTest = new TModifierTest();
 #endif
   m_modifierLine         = new TModifierLine();
   m_modifierTangents     = new TModifierTangents();
@@ -305,8 +305,8 @@ bool FullColorBrushTool::askWrite(const TRect &rect) {
 //--------------------------------------------------------------------------------------------------
 
 bool FullColorBrushTool::preLeftButtonDown() {
-  m_modifierAssistants->drawOnly = !m_assistants.getValue();
-  m_inputmanager.drawPreview     = false; //!m_modifierAssistants->drawOnly;
+  m_modifierAssistants->magnetism = m_assistants.getValue() ? 1 : 0;
+  m_inputmanager.drawPreview      = false; //!m_modifierAssistants->drawOnly;
 
   m_inputmanager.clearModifiers();
   m_inputmanager.addModifier(TInputModifierP(m_modifierTangents.getPointer()));
@@ -342,7 +342,7 @@ void FullColorBrushTool::handleMouseEvent(MouseEventType type,
   bool control  = e.getModifiersMask() & TMouseEvent::CTRL_KEY;
 
   if (shift && type == ME_DOWN && e.button() == Qt::LeftButton && !m_started) {
-    m_modifierAssistants->drawOnly = true;
+    m_modifierAssistants->magnetism = 0;
     m_inputmanager.clearModifiers();
     m_inputmanager.addModifier(TInputModifierP(m_modifierLine.getPointer()));
     m_inputmanager.addModifier(
@@ -519,14 +519,14 @@ void FullColorBrushTool::inputPaintTrackPoint(const TTrackPoint &point,
 
   // init brush
   TrackHandler *handler;
-  if (track.size() == track.pointsAdded && !track.toolHandler && m_workRaster) {
+  if (track.size() == track.pointsAdded && !track.handler && m_workRaster) {
     mypaint::Brush mypaintBrush;
     applyToonzBrushSettings(mypaintBrush);
     handler = new TrackHandler(m_workRaster, *this, mypaintBrush);
     handler->brush.beginStroke();
-    track.toolHandler = handler;
+    track.handler = handler;
   }
-  handler = dynamic_cast<TrackHandler *>(track.toolHandler.getPointer());
+  handler = dynamic_cast<TrackHandler *>(track.handler.getPointer());
   if (!handler) return;
 
   // paint stroke
diff --git a/toonz/sources/tnztools/fullcolorbrushtool.h b/toonz/sources/tnztools/fullcolorbrushtool.h
index cdb8450..903ccbd 100644
--- a/toonz/sources/tnztools/fullcolorbrushtool.h
+++ b/toonz/sources/tnztools/fullcolorbrushtool.h
@@ -42,7 +42,7 @@ class FullColorBrushTool final : public TTool,
                                  public TInputHandler {
   Q_DECLARE_TR_FUNCTIONS(FullColorBrushTool)
 public:
-  class TrackHandler : public TTrackToolHandler {
+  class TrackHandler : public TTrackHandler {
   public:
     MyPaintToonzBrush brush;
 
diff --git a/toonz/sources/tnztools/inputmanager.cpp b/toonz/sources/tnztools/inputmanager.cpp
index 06b7f8d..8e05e3b 100644
--- a/toonz/sources/tnztools/inputmanager.cpp
+++ b/toonz/sources/tnztools/inputmanager.cpp
@@ -33,27 +33,28 @@ TInputModifier::modifyTrack(
   TTrackList &outTracks )
 {
   if (!track.handler) {
-      track.handler = new TTrackHandler(track);
-      track.handler->tracks.push_back(
-        new TTrack(
-          new TTrackModifier(*track.handler) ));
+    TSubTrackHandler *handler = new TSubTrackHandler();
+    track.handler = handler;
+    handler->track = new TTrack(track);
+    new TTrackIntrOrig(*handler->track);
   }
 
-  outTracks.insert(
-    outTracks.end(),
-    track.handler->tracks.begin(),
-    track.handler->tracks.end() );
-  if (!track.changed())
+  TSubTrackHandler *handler = dynamic_cast<TSubTrackHandler*>(track.handler.getPointer());
+  if (!handler)
     return;
+  
+  outTracks.push_back(handler->track);
+  TTrack &subTrack = *handler->track;
 
+  if (!track.changed())
+    return;
+  
   int start = std::max(0, track.size() - track.pointsAdded);
-  for(TTrackList::const_iterator ti = track.handler->tracks.begin(); ti != track.handler->tracks.end(); ++ti) {
-    TTrack &subTrack = **ti;
-    subTrack.truncate(start);
-    for(int i = start; i < track.size(); ++i)
-      subTrack.push_back( subTrack.modifier->calcPoint(i), false );
-    subTrack.fix_to(track.fixedSize());
-  }
+  subTrack.truncate(start);
+  for(int i = start; i < track.size(); ++i)
+    subTrack.push_back(subTrack.pointFromOriginal(i), false);
+  subTrack.fix_to(track.fixedSize());
+  
   track.resetChanges();
 }
 
@@ -190,7 +191,7 @@ TInputHandler::inputPaintTracks(const TTrackList &tracks) {
       const TTrack &t = **i;
       if (t.pointsAdded > 0) {
         TTimerTicks ticks = t.ticks();
-        double timeOffset = t.timeOffset() + t.current().time;
+        double timeOffset = t.rootTimeOffset + t.current().time;
         if (!track || (ticks - minTicks)*TToolTimer::frequency + timeOffset - minTimeOffset < 0.0) {
           track = *i;
           minTicks = ticks;
@@ -494,7 +495,7 @@ TInputManager::trackEvent(
   TTrackP track = getTrack(deviceId, touchId, ticks, (bool)pressure, (bool)tilt);
   if (!track->finished()) {
     ticks = fixTicks(ticks);
-    double time = (double)(ticks - track->ticks())*TToolTimer::step - track->timeOffset();
+    double time = (double)(ticks - track->ticks())*TToolTimer::step - track->rootTimeOffset;
     addTrackPoint(
       track,
       position,
diff --git a/toonz/sources/tnztools/modifiers/modifierassistants.cpp b/toonz/sources/tnztools/modifiers/modifierassistants.cpp
index 597e97d..c6fec6f 100644
--- a/toonz/sources/tnztools/modifiers/modifierassistants.cpp
+++ b/toonz/sources/tnztools/modifiers/modifierassistants.cpp
@@ -20,20 +20,15 @@
 
 
 //*****************************************************************************************
-//    TModifierAssistants::Modifier implementation
+//    TModifierAssistants::Interpolator implementation
 //*****************************************************************************************
 
 
-TModifierAssistants::Modifier::Modifier(TTrackHandler &handler):
-  TTrackModifier(handler),
-  initialized()
-{ }
-
-
 TTrackPoint
-TModifierAssistants::Modifier::calcPoint(double originalIndex) {
-  TTrackPoint p = TTrackModifier::calcPoint(originalIndex);
-  return guidelines.empty() ? p : guidelines.front()->smoothTransformPoint(p);
+TModifierAssistants::Interpolator::interpolate(double index) {
+  TTrackPoint p = track.original ? track.calcPointFromOriginal(index)
+                                 : track.interpolateLinear(index);
+  return guidelines.empty() ? p : guidelines.front()->smoothTransformPoint(p, magnetism);
 }
 
 
@@ -42,8 +37,8 @@ TModifierAssistants::Modifier::calcPoint(double originalIndex) {
 //*****************************************************************************************
 
 
-TModifierAssistants::TModifierAssistants(bool drawOnly):
-  drawOnly(drawOnly),
+TModifierAssistants::TModifierAssistants(double magnetism):
+  magnetism(magnetism),
   sensitiveLength(50.0) { }
 
 
@@ -99,7 +94,7 @@ TModifierAssistants::scanAssistants(
             if (findGuidelines)
               for(int i = 0; i < positionsCount; ++i)
                 assistant->getGuidelines(positions[i], imageToTrack, *outGuidelines);
-            if (draw) assistant->draw(viewer, !drawOnly);
+            if (draw) assistant->draw(viewer, magnetism > 0);
             if (!doSomething) return true;
           }
 
@@ -116,29 +111,35 @@ TModifierAssistants::modifyTrack(
   TTrackList &outTracks )
 {
   if (!track.handler) {
-    track.handler = new TTrackHandler(track);
-    Modifier *modifier = new Modifier(*track.handler);
-    track.handler->tracks.push_back(new TTrack(modifier));
+    Handler *handler = new Handler();
+    track.handler = handler;
+    handler->track = new TTrack(track);
+    new Interpolator(*handler->track, magnetism);
   }
-
-  outTracks.push_back(track.handler->tracks.front());
-  TTrack &subTrack = *track.handler->tracks.front();
-  if (!track.changed())
+  
+  Handler *handler = dynamic_cast<Handler*>(track.handler.getPointer());
+  if (!handler)
     return;
-  Modifier *modifier = dynamic_cast<Modifier*>(subTrack.modifier.getPointer());
-  if (!modifier)
+  
+  outTracks.push_back(handler->track);
+  TTrack &subTrack = *handler->track;
+  Interpolator *intr = dynamic_cast<Interpolator*>(subTrack.getInterpolator().getPointer());
+  if (!intr)
     return;
-    
+  
+  if (!track.changed())
+    return;
+  
   // remove points
   int start = track.size() - track.pointsAdded;
   if (start < 0) start = 0;
 
-  if (!drawOnly && start <= 0) {
-    modifier->guidelines.clear();
-    scanAssistants(&track[0].position, 1, &modifier->guidelines, false, true);
+  if (intr->magnetism && start <= 0) {
+    intr->guidelines.clear();
+    scanAssistants(&track[0].position, 1, &intr->guidelines, false, true);
   }
   
-  bool fixed = subTrack.fixedSize() || modifier->guidelines.size() <= 1;
+  bool fixed = subTrack.fixedSize() || intr->guidelines.size() <= 1;
 
   // select guideline
   if (!fixed)
@@ -152,11 +153,11 @@ TModifierAssistants::modifyTrack(
         if (!objHandle->isSpline())
           trackToScreen *= TScale(viewer->getDpiScale().x, viewer->getDpiScale().y);
     trackToScreen *= viewer->get3dViewMatrix().get2d();
-    TGuidelineP guideline = TGuideline::findBest(modifier->guidelines, track, trackToScreen, fixed);
-    if (guideline != modifier->guidelines.front())
-      for(int i = 1; i < (int)modifier->guidelines.size(); ++i)
-        if (modifier->guidelines[i] == guideline) {
-          std::swap(modifier->guidelines[i], modifier->guidelines.front());
+    TGuidelineP guideline = TGuideline::findBest(intr->guidelines, track, trackToScreen, fixed);
+    if (guideline != intr->guidelines.front())
+      for(int i = 1; i < (int)intr->guidelines.size(); ++i)
+        if (intr->guidelines[i] == guideline) {
+          std::swap(intr->guidelines[i], intr->guidelines.front());
           start = 0;
           break;
         }
@@ -165,7 +166,7 @@ TModifierAssistants::modifyTrack(
   // add points
   subTrack.truncate(start);
   for(int i = start; i < track.size(); ++i)
-    subTrack.push_back( modifier->calcPoint(i), false );
+    subTrack.push_back( intr->interpolate(i), false );
   
   // fix points
   if (fixed || track.fixedFinished())
@@ -185,16 +186,20 @@ TModifierAssistants::calcDrawBounds(const TTrackList&, const THoverList&) {
 
 void
 TModifierAssistants::drawTrack(const TTrack &track) {
-  if (!track.handler) return;
-  TTrack &subTrack = *track.handler->tracks.front();
-  if (Modifier *modifier = dynamic_cast<Modifier*>(subTrack.modifier.getPointer())) {
-    const TGuidelineList &guidelines = modifier->guidelines;
-    if (!guidelines.empty()) {
-      guidelines.front()->draw(true);
-      for(TGuidelineList::const_iterator i = guidelines.begin() + 1; i != guidelines.end(); ++i)
-        (*i)->draw();
-    }
-  }
+  Handler *handler = dynamic_cast<Handler*>(track.handler.getPointer());
+  if (!handler) return;
+  
+  TTrack &subTrack = *handler->track;
+  Interpolator *intr = dynamic_cast<Interpolator*>(subTrack.getInterpolator().getPointer());
+  if (!intr) return;
+  
+  const TGuidelineList &guidelines = intr->guidelines;
+  if (guidelines.empty())
+    return;
+  
+  guidelines.front()->draw(true);
+  for(TGuidelineList::const_iterator i = guidelines.begin() + 1; i != guidelines.end(); ++i)
+    (*i)->draw();
 }
 
 
@@ -205,8 +210,8 @@ TModifierAssistants::draw(const TTrackList &tracks, const THoverList &hovers) {
   if (tracks.empty()) // hide hovers if track exists
     allHovers.insert(allHovers.end(), hovers.begin(), hovers.end());
   for(TTrackList::const_iterator i = tracks.begin(); i != tracks.end(); ++i)
-    if ((*i)->handler && !(*i)->handler->tracks.empty() && !(*i)->handler->tracks.front()->empty())
-      allHovers.push_back( (*i)->handler->tracks.front()->back().position );
+    if (Handler *handler = dynamic_cast<Handler*>((*i)->handler.getPointer()))
+      allHovers.push_back( handler->track->back().position );
   
   // draw assistants
   TGuidelineList guidelines;
@@ -219,7 +224,7 @@ TModifierAssistants::draw(const TTrackList &tracks, const THoverList &hovers) {
 
   // draw guidelines
   for(TGuidelineList::const_iterator i = guidelines.begin(); i != guidelines.end(); ++i)
-    (*i)->draw(false, !drawOnly);
+    (*i)->draw(false, magnetism > 0);
 
   // draw tracks
   TInputModifier::drawTracks(tracks);
diff --git a/toonz/sources/tnztools/modifiers/modifierline.cpp b/toonz/sources/tnztools/modifiers/modifierline.cpp
index e678914..382589a 100644
--- a/toonz/sources/tnztools/modifiers/modifierline.cpp
+++ b/toonz/sources/tnztools/modifiers/modifierline.cpp
@@ -2,10 +2,13 @@
 
 #include <tools/modifiers/modifierline.h>
 
+
+
 //*****************************************************************************************
 //    TModifierLine implementation
 //*****************************************************************************************
 
+
 static inline void calcFixedAngle(const TTrackPoint &p0, TTrackPoint &p1) {
   TPointD p = p1.position - p0.position;
   double l  = sqrt(p.x * p.x + p.y * p.y);
@@ -20,70 +23,51 @@ static inline void calcFixedAngle(const TTrackPoint &p0, TTrackPoint &p1) {
   p1.position = p0.position + p;
 }
 
-TTrackPoint TModifierLine::Modifier::calcPoint(double originalIndex) {
-  if (original.empty()) return TTrackPoint();
-  if (original.size() < 2) return original.front();
-  TTrackPoint p0 = original.front();
-  TTrackPoint p1 = original.back();
-  if (fixAngle) calcFixedAngle(p0, p1);
-  return TTrack::interpolationLinear(p0, p1,
-                                     originalIndex / (original.size() - 1));
-}
 
 void TModifierLine::modifyTrack(const TTrack &track,
                                 TTrackList &outTracks) {
   if (!track.handler) {
-    track.handler       = new TTrackHandler(track);
-    Modifier *modifier  = new Modifier(*track.handler);
-    track.handler->tracks.push_back(new TTrack(modifier));
+    Handler *handler  = new Handler();
+    track.handler     = handler;
+    handler->track    = new TTrack(track);
   }
 
-  if (!track.changed()) return;
-  if (track.handler->tracks.empty()) return;
-
-  TTrack &subTrack   = *track.handler->tracks.front();
-  Modifier *modifier = dynamic_cast<Modifier *>(subTrack.modifier.getPointer());
-  if (!modifier) {
-    track.resetChanges();
+  Handler *handler = dynamic_cast<Handler*>(track.handler.getPointer());
+  if (!handler)
+    return;
+  
+  outTracks.push_back(handler->track);
+  TTrack &subTrack = *handler->track;
+  
+  if (!track.changed())
     return;
-  }
 
-  bool fixAngle = track.getKeyState(track.back()).isPressed(TKey::control);
-  outTracks.push_back(track.handler->tracks.front());
+  subTrack.truncate(0);
 
+  // calc max pressure
   int i1             = track.size();
   int i0             = i1 - track.pointsAdded;
-  double maxPressure = modifier->maxPressure;
+  double maxPressure = handler->maxPressure;
   if (track.pointsRemoved) {
     maxPressure = 0;
     i0          = 0;
   }
-  for (int i = i0; i < i1; ++i) {
+  for(int i = i0; i < i1; ++i) {
     double p = track[i].pressure;
     if (maxPressure < p) maxPressure = p;
   }
-  modifier->maxPressure = maxPressure;
-  modifier->fixAngle    = fixAngle;
-
-  subTrack.truncate(0);
-
-  if (track.size() > 0) {
-    TTrackPoint p   = track.front();
-    p.originalIndex = 0;
-    p.pressure      = maxPressure;
-    p.tilt          = TPointD();
-    subTrack.push_back(p, false);
-  }
-
+  handler->maxPressure = maxPressure;
+  
+  if (track.size() > 0)
+    subTrack.push_back(subTrack.pointFromOriginal(0), false);
+  
   if (track.size() > 1) {
-    TTrackPoint p   = track.back();
-    p.originalIndex = track.size() - 1;
-    p.pressure      = maxPressure;
-    p.tilt          = TPointD();
-    if (fixAngle) calcFixedAngle(subTrack.front(), p);
+    TTrackPoint p = subTrack.pointFromOriginal(track.size() - 1);
+    if (track.getKeyState(track.back()).isPressed(TKey::control))
+      calcFixedAngle(subTrack.front(), p);
     subTrack.push_back(p, false);
   }
-
+    
   if (track.fixedFinished())
     subTrack.fix_all();
 
diff --git a/toonz/sources/tnztools/modifiers/modifiersegmentation.cpp b/toonz/sources/tnztools/modifiers/modifiersegmentation.cpp
index ba1232e..4718afc 100644
--- a/toonz/sources/tnztools/modifiers/modifiersegmentation.cpp
+++ b/toonz/sources/tnztools/modifiers/modifiersegmentation.cpp
@@ -42,7 +42,7 @@ TModifierSegmentation::addSegments(
   }
 
   --level;
-  TTrackPoint p = track.modifier->calcPoint(0.5*(p0.originalIndex + p1.originalIndex));
+  TTrackPoint p = track.calcPointFromOriginal(0.5*(p0.originalIndex + p1.originalIndex));
   addSegments(track, p0, p, level);
   addSegments(track, p, p1, level);
 }
@@ -54,21 +54,22 @@ TModifierSegmentation::modifyTrack(
   TTrackList &outTracks )
 {
   if (!track.handler) {
-    track.handler = new TTrackHandler(track);
-    track.handler->tracks.push_back(
-      new TTrack(
-        new TTrackModifier(*track.handler) ));
+    Handler *handler = new Handler();
+    track.handler = handler;
+    handler->track = new TTrack(track);
+    new Interpolator(*handler->track);
   }
 
-  if (track.handler->tracks.empty())
+  Handler *handler = dynamic_cast<Handler*>(track.handler.getPointer());
+  if (!handler)
     return;
-
-  TTrack &subTrack = *track.handler->tracks.front();
-  outTracks.push_back(track.handler->tracks.front());
-
+  
+  outTracks.push_back(handler->track);
+  TTrack &subTrack = *handler->track;
+  
   if (!track.changed())
     return;
-
+  
   // remove points
   int start = track.size() - track.pointsAdded;
   if (start < 0) start = 0;
@@ -76,9 +77,9 @@ TModifierSegmentation::modifyTrack(
   subTrack.truncate(subStart);
 
   // add points
-  TTrackPoint p0 = subTrack.modifier->calcPoint(start - 1);
+  TTrackPoint p0 = subTrack.pointFromOriginal(start - 1);
   for(int i = start; i < track.size(); ++i) {
-    TTrackPoint p1 = subTrack.modifier->calcPoint(i);
+    TTrackPoint p1 = subTrack.pointFromOriginal(i);
     addSegments(subTrack, p0, p1, m_maxLevel);
     p0 = p1;
   }
diff --git a/toonz/sources/tnztools/modifiers/modifiersimplify.cpp b/toonz/sources/tnztools/modifiers/modifiersimplify.cpp
index df889c0..612af0b 100644
--- a/toonz/sources/tnztools/modifiers/modifiersimplify.cpp
+++ b/toonz/sources/tnztools/modifiers/modifiersimplify.cpp
@@ -10,12 +10,7 @@
 
 
 TModifierSimplify::TModifierSimplify(double step):
-  step() { setStep(step); }
-
-
-void
-TModifierSimplify::setStep(double step)
-  { this->step = std::max(0.0, step); }
+  step(step) { }
 
 
 void
@@ -24,21 +19,22 @@ TModifierSimplify::modifyTrack(
   TTrackList &outTracks )
 {
   if (!track.handler) {
-    track.handler = new TTrackHandler(track);
-    track.handler->tracks.push_back(
-      new TTrack(
-        new TTrackModifier(*track.handler) ));
+    Handler *handler = new Handler();
+    track.handler = handler;
+    handler->track = new TTrack(track);
+    new Interpolator(*handler->track);
   }
 
-  if (track.handler->tracks.empty())
+  Handler *handler = dynamic_cast<Handler*>(track.handler.getPointer());
+  if (!handler)
     return;
-
-  TTrack &subTrack = *track.handler->tracks.front();
-  outTracks.push_back(track.handler->tracks.front());
+  
+  outTracks.push_back(handler->track);
+  TTrack &subTrack = *handler->track;
 
   if (!track.changed())
     return;
-
+  
   // remove points
   int start = track.size() - track.pointsAdded;
   if (start < 0) start = 0;
@@ -52,7 +48,7 @@ TModifierSimplify::modifyTrack(
   double step2 = step*step;
   TTrackPoint p0 = subTrack.back();
   for(int i = start; i < track.size(); ++i) {
-    const TTrackPoint &p1 = track[i];
+    const TTrackPoint &p1 = subTrack.pointFromOriginal(i);
     if (!subTrack.empty() && tdistance2(p1.position, p0.position) < step2) {
       if (p0.pressure < p1.pressure) p0.pressure = p1.pressure;
       if (i == track.size() - 1) p0.position = p1.position;
@@ -63,7 +59,6 @@ TModifierSimplify::modifyTrack(
       subTrack.push_back(p0, false);
     } else {
       p0 = p1;
-      p0.originalIndex = i;
       subTrack.push_back(p0, false);
     }
   }
diff --git a/toonz/sources/tnztools/modifiers/modifiersmooth.cpp b/toonz/sources/tnztools/modifiers/modifiersmooth.cpp
index 953ea68..ac0b212 100644
--- a/toonz/sources/tnztools/modifiers/modifiersmooth.cpp
+++ b/toonz/sources/tnztools/modifiers/modifiersmooth.cpp
@@ -4,38 +4,14 @@
 #include <algorithm>
 
 
-//*****************************************************************************************
-//    TModifierSmooth::Modifier implementation
-//*****************************************************************************************
-
-
-TModifierSmooth::Modifier::Modifier(TTrackHandler &handler, int radius):
-  TTrackModifier(handler),
-  radius(std::max(radius, 0)),
-  smoothedTrack()
-{ }
-
-
-TTrackPoint
-TModifierSmooth::Modifier::calcPoint(double originalIndex) {
-  return smoothedTrack
-       ? smoothedTrack->interpolateLinear(originalIndex + radius)
-       : TTrackModifier::calcPoint(originalIndex);
-}
-
 
 //*****************************************************************************************
 //    TModifierSmooth implementation
 //*****************************************************************************************
 
 
-TModifierSmooth::TModifierSmooth(int radius): m_radius()
-  { setRadius(radius); }
-
-
-void
-TModifierSmooth::setRadius(int radius)
-  { m_radius = std::max(0, radius); }
+TModifierSmooth::TModifierSmooth(int radius):
+  radius(radius) { }
 
 
 void
@@ -43,32 +19,25 @@ TModifierSmooth::modifyTrack(
   const TTrack &track,
   TTrackList &outTracks )
 {
-  if (!m_radius) {
-    TInputModifier::modifyTrack(track, outTracks);
-    return;
-  }
+  int radius = abs(this->radius);
   
-  if (!track.handler) {
-    track.handler = new TTrackHandler(track);
-    Modifier *modifier = new Modifier(*track.handler, m_radius);
-    modifier->smoothedTrack = new TTrack(modifier);
-    track.handler->tracks.push_back(modifier->smoothedTrack);
+  if (!track.handler && radius) {
+    Handler *handler = new Handler(radius);
+    track.handler = handler;
+    handler->track = new TTrack(track);
   }
 
-  if (track.handler->tracks.empty())
-    return;
-
-  TTrack &subTrack = *track.handler->tracks.front();
-  outTracks.push_back(track.handler->tracks.front());
-
+  Handler *handler = dynamic_cast<Handler*>(track.handler.getPointer());
+  if (!handler)
+    return TInputModifier::modifyTrack(track, outTracks);
+  
+  radius = handler->radius;
+  outTracks.push_back(handler->track);
+  TTrack &subTrack = *handler->track;
+  
   if (!track.changed())
     return;
   
-  Modifier *modifier = dynamic_cast<Modifier*>(subTrack.modifier.getPointer());
-  if (!modifier)
-    return;
-  int radius = modifier->radius;
-
   // remove points
   int start = std::max(0, track.size() - track.pointsAdded);
   subTrack.truncate(start);
@@ -87,18 +56,23 @@ TModifierSmooth::modifyTrack(
     if (i < start)
       continue;
 
-    int oi = track.clampIndex(i - radius);
-    const TTrackPoint &p = track[oi];
-    subTrack.push_back(
-      TTrackPoint(
-        accum.position*k,
-        accum.pressure*k,
-        accum.tilt*k,
-        oi,
-        p.time,
-        0,
-        p.final ),
-      false );
+    double originalIndex;
+    if (i <= radius) {
+      originalIndex = i/(double)(radius + 1);
+    } else
+    if (i >= size - radius - 1) {
+      originalIndex = track.size() - 1 - (size - i - 1)/(double)(radius + 1);
+    } else {
+      originalIndex = i - radius;
+    }
+    
+    TTrackPoint p = subTrack.pointFromOriginal(i - radius);
+    p.position = accum.position*k;
+    p.pressure = accum.pressure*k;
+    p.tilt = accum.tilt*k;
+    p.originalIndex = originalIndex;
+    p.final = p.final && i == size - 1;
+    subTrack.push_back(p, false);
     
     const TTrackPoint &p0 = track[i - 2*radius];
     accum.position -= p0.position;
diff --git a/toonz/sources/tnztools/modifiers/modifiertangents.cpp b/toonz/sources/tnztools/modifiers/modifiertangents.cpp
index 60a8704..e1cfcd7 100644
--- a/toonz/sources/tnztools/modifiers/modifiertangents.cpp
+++ b/toonz/sources/tnztools/modifiers/modifiertangents.cpp
@@ -4,22 +4,22 @@
 
 
 //*****************************************************************************************
-//    TModifierTangents::Modifier implementation
+//    TModifierTangents::Interpolator implementation
 //*****************************************************************************************
 
 
 TTrackPoint
-TModifierTangents::Modifier::calcPoint(double originalIndex) {
+TModifierTangents::Interpolator::interpolate(double index) {
   double frac;
-  int i0 = original.floorIndex(originalIndex, &frac);
+  int i0 = track.floorIndex(index, &frac);
   int i1 = i0 + 1;
 
   TTrackPoint p;
 
   // calculate tangent length to make monotonic subdivisions,
   // (because we don't have valid input time)
-  const TTrackPoint &p0 = original[i0];
-  const TTrackPoint &p1 = original[i1];
+  const TTrackPoint &p0 = track[i0];
+  const TTrackPoint &p1 = track[i1];
   TTrackTangent t0 = i0 >= 0 && i0 < (int)tangents.size() ? tangents[i0] : TTrackTangent();
   TTrackTangent t1 = i1 >= 0 && i1 < (int)tangents.size() ? tangents[i1] : TTrackTangent();
   double l = p1.length - p0.length;
@@ -36,9 +36,7 @@ TModifierTangents::Modifier::calcPoint(double originalIndex) {
   t1.tilt.x *= l;
   t1.tilt.y *= l;
   
-  p = TTrack::interpolationSpline(p0, p1, t0, t1, frac);
-  p.originalIndex = originalIndex;
-  return p;
+  return TTrack::interpolationSpline(p0, p1, t0, t1, frac);
 }
 
 
@@ -48,7 +46,7 @@ TModifierTangents::Modifier::calcPoint(double originalIndex) {
 
 
 TTrackTangent
-TModifierTangents::calcTangent(const TTrack &track, int index) const {
+TModifierTangents::calcTangent(const TTrack &track, int index) {
   if (index <= 0 || index >= track.size() - 1)
     return TTrackTangent();
   
@@ -60,7 +58,7 @@ TModifierTangents::calcTangent(const TTrack &track, int index) const {
   // instead of time when message dispatched
   //double k = p2.time - p0.time;
   
-  // calculate tangent based on length, util we have no valid times
+  // calculate tangent based on length, until we have no valid times
   double k = p2.length - p0.length;
   
   k = k > TConsts::epsilon ? 1/k : 0;
@@ -77,39 +75,39 @@ TModifierTangents::modifyTrack(
   TTrackList &outTracks )
 {
   if (!track.handler) {
-    track.handler = new TTrackHandler(track);
-    track.handler->tracks.push_back(
-      new TTrack(
-        new Modifier(*track.handler) ));
+    Handler *handler = new Handler();
+    track.handler = handler;
+    handler->track = new TTrack(track);
+    new Interpolator(*handler->track);
   }
-
-  if (track.handler->tracks.empty())
+  
+  Handler *handler = dynamic_cast<Handler*>(track.handler.getPointer());
+  if (!handler)
     return;
-
-  TTrack &subTrack = *track.handler->tracks.front();
-  Modifier *modifier = dynamic_cast<Modifier*>(subTrack.modifier.getPointer());
-  if (!modifier)
+  
+  outTracks.push_back(handler->track);
+  TTrack &subTrack = *handler->track;
+  Interpolator *intr = dynamic_cast<Interpolator*>(subTrack.getInterpolator().getPointer());
+  if (!intr)
     return;
-
-  outTracks.push_back(track.handler->tracks.front());
+  
   if (!track.changed())
     return;
   
-  // update subTrack
   int start = track.size() - track.pointsAdded;
-  if (start > 1) --start;
   if (start < 0) start = 0;
-  subTrack.truncate(start);
-  for(int i = start; i < track.size(); ++i) {
-    TTrackPoint p = track[i];
-    p.originalIndex = i;
-    subTrack.push_back(p, false);
-  }
   
   // update tangents
-  modifier->tangents.resize(start);
+  int tangentStart = start - 1;
+  if (tangentStart < 0) tangentStart = 0;
+  intr->tangents.resize(tangentStart);
+  for(int i = tangentStart; i < track.size(); ++i)
+    intr->tangents.push_back(calcTangent(track, i));
+
+  // update subTrack
+  subTrack.truncate(start);
   for(int i = start; i < track.size(); ++i)
-    modifier->tangents.push_back(calcTangent(track, i));
+    subTrack.push_back(subTrack.pointFromOriginal(i), false);
   
   // fix points
   if (track.fixedFinished()) {
diff --git a/toonz/sources/tnztools/modifiers/modifiertest.cpp b/toonz/sources/tnztools/modifiers/modifiertest.cpp
index 7801f3b..72f4774 100644
--- a/toonz/sources/tnztools/modifiers/modifiertest.cpp
+++ b/toonz/sources/tnztools/modifiers/modifiertest.cpp
@@ -6,111 +6,117 @@
 // std includes
 #include <cmath>
 
+
 //*****************************************************************************************
-//    TModifierTest::Modifier implementation
+//    TModifierTest::Interpolator implementation
 //*****************************************************************************************
 
-TModifierTest::Modifier::Modifier(TTrackHandler &handler, double angle,
-                                  double radius, double speed)
-    : TTrackModifier(handler), angle(angle), radius(radius), speed(speed) {}
-
-TTrackPoint TModifierTest::Modifier::calcPoint(double originalIndex) {
-  TTrackPoint p = TTrackModifier::calcPoint(originalIndex);
-
-  if (p.length > TConsts::epsilon) {
-    double frac;
-    int i0 = original.floorIndex(originalIndex, &frac);
-    int i1 = original.ceilIndex(originalIndex);
-    if (i0 < 0) return p;
-
-    if (Handler *handler = dynamic_cast<Handler *>(&this->handler)) {
-      double angle = this->angle + speed * TTrack::interpolationLinear(
-                                               handler->angles[i0],
-                                               handler->angles[i1], frac);
-      double radius = 2.0 * this->radius * p.pressure;
-      double s      = sin(angle);
-      double c      = cos(angle);
-
-      TPointD tangent =
-          original.calcTangent(originalIndex, fabs(2.0 * this->radius / speed));
-      p.position.x -= tangent.y * s * radius;
-      p.position.y += tangent.x * s * radius;
-      p.pressure *= 1.0 - 0.5 * c;
-    }
-  } else {
-    p.pressure = 0.0;
-  }
+TTrackPoint TModifierTest::Interpolator::interpolateFromOriginal(double originalIndex) {
+  Handler *handler = track.original
+                   ? dynamic_cast<Handler*>(track.original->handler.getPointer())
+                   : nullptr;
+  if (!handler)
+    return track.interpolateLinear(track.indexByOriginalIndex(originalIndex));
+  
+  TTrackPoint p = track.calcPointFromOriginal(originalIndex);
+
+  double frac;
+  int i0 = track.original->floorIndex(originalIndex, &frac);
+  int i1 = track.original->ceilIndex(originalIndex);
+
+  double angle = TTrack::interpolationLinear(
+    handler->angles[i0], handler->angles[i1], frac );
+  angle = angle*speed + this->angle;
+  
+  double r = radius*p.pressure;
+  double s = sin(angle);
+  
+  double d = fabs(2.0*radius);
+  if (fabs(speed) > TConsts::epsilon)
+    d /= fabs(speed);
+
+  TPointD tangent = track.original->calcTangent(originalIndex, d);
+  p.position.x -= tangent.y * s * r;
+  p.position.y += tangent.x * s * r;
+  p.pressure *= fabs(s);
 
   return p;
 }
 
+
+TTrackPoint TModifierTest::Interpolator::interpolate(double index) {
+  return interpolateFromOriginal(track.originalIndexByIndex(index));
+}
+
+
 //*****************************************************************************************
 //    TModifierTest implementation
 //*****************************************************************************************
 
-TModifierTest::TModifierTest(int count, double radius)
-    : count(count), radius(radius) {}
+TModifierTest::TModifierTest(int count, double radius, double speed)
+    : count(count), radius(radius), speed(speed) {}
 
 void TModifierTest::modifyTrack(const TTrack &track,
                                 TTrackList &outTracks) {
   const double segmentSize = 2.0 * M_PI / 10.0;
 
-  if (!track.handler) {
-    if (track.getKeyState(track.front().time).isPressed(TKey(Qt::Key_Alt))) {
-      // TModifierTest::Handler for spiro
-      track.handler = new Handler(track);
-      for (int i = 0; i < count; ++i)
-        track.handler->tracks.push_back(new TTrack(new Modifier(
-            *track.handler, i * 2.0 * M_PI / (double)count, radius, 0.25)));
+  if ( !track.handler
+    && track.getKeyState(track.front().time).isPressed(TKey::alt) )
+  {
+    Handler *handler = new Handler(this->radius);
+    track.handler = handler;
+    for (int i = 0; i < count; ++i) {
+      handler->tracks.push_back(new TTrack(track));
+      TTrack &subTrack = *handler->tracks.back();
+      new Interpolator(subTrack, i*2*M_PI/(double)count, radius, 0.25);
     }
   }
-
-  Handler *handler = dynamic_cast<Handler *>(track.handler.getPointer());
-  if (!handler) {
-    TInputModifier::modifyTrack(track, outTracks);
+  
+  Handler *handler = dynamic_cast<Handler*>(track.handler.getPointer());
+  if (!handler)
+    return TInputModifier::modifyTrack(track, outTracks);
+  
+  outTracks.insert(outTracks.end(), handler->tracks.begin(), handler->tracks.end());
+  if (!track.changed())
     return;
-  }
-
-  outTracks.insert(outTracks.end(), track.handler->tracks.begin(),
-                   track.handler->tracks.end());
-  if (!track.changed()) return;
 
+  double radius = handler->radius;
   int start = track.size() - track.pointsAdded;
   if (start < 0) start = 0;
 
   // remove angles
-  double lastAngle = start < (int)handler->angles.size()
-                         ? handler->angles[start]
-                     : handler->angles.empty() ? 0.0
-                                               : handler->angles.back();
-  handler->angles.resize(start, lastAngle);
-
+  handler->angles.resize(start);
+  
   // add angles
-  for (int i = start; i < track.size(); ++i) {
-    if (i > 0) {
-      double dl = track[i].length - track[i - 1].length;
-      double da = track[i].pressure > TConsts::epsilon
-                      ? dl / (radius * track[i].pressure)
-                      : 0.0;
-      handler->angles.push_back(handler->angles[i - 1] + da);
+  for(int i = start; i < track.size(); ++i) {
+    if (i) {
+      const TTrackPoint &p0 = track[i - 1];
+      const TTrackPoint &p1 = track[i];
+      double dl = p1.length - p0.length;
+      double da = p1.pressure > TConsts::epsilon
+                ? dl / (radius * p1.pressure)
+                : 0.0;
+      handler->angles.push_back(handler->angles.back() + da);
     } else {
       handler->angles.push_back(0.0);
     }
   }
-
+  
   // process sub-tracks
-  for (TTrackList::const_iterator ti = handler->tracks.begin();
-       ti != handler->tracks.end(); ++ti) {
-    TTrack &subTrack          = **ti;
+  for(TTrackList::const_iterator ti = handler->tracks.begin(); ti != handler->tracks.end(); ++ti) {
+    TTrack &subTrack = **ti;
+    Interpolator *intr = dynamic_cast<Interpolator*>(subTrack.getInterpolator().getPointer());
+    if (!intr)
+      continue;
+    
     double currentSegmentSize = segmentSize;
-    if (const Modifier *modifier =
-            dynamic_cast<const Modifier *>(subTrack.modifier.getPointer()))
-      if (fabs(modifier->speed) > TConsts::epsilon)
-        currentSegmentSize = segmentSize / fabs(modifier->speed);
+    if (fabs(intr->speed) > TConsts::epsilon)
+      currentSegmentSize /= fabs(intr->speed);
 
     // remove points
-    int subStart =
-        subTrack.floorIndex(subTrack.indexByOriginalIndex(start - 1)) + 1;
+    int subStart = start > 0
+                 ? subTrack.floorIndex(subTrack.indexByOriginalIndex(start - 1)) + 1
+                 : 0;
     subTrack.truncate(subStart);
 
     // add points
@@ -123,18 +129,20 @@ void TModifierTest::modifyTrack(const TTrack &track,
           double end  = 1.0 - 0.5 * step;
           for (double frac = step; frac < end; frac += step)
             subTrack.push_back(
-                subTrack.modifier->calcPoint((double)i - 1.0 + frac), false);
+                intr->interpolateFromOriginal(i - 1 + frac), false );
         }
       }
-      subTrack.push_back(subTrack.modifier->calcPoint(i), false);
+      subTrack.push_back(intr->interpolateFromOriginal(i), false);
     }
     
     // fix points
+    if (track.fixedFinished())
+      subTrack.fix_all();
     if (track.fixedSize())
       subTrack.fix_to(
         subTrack.floorIndex(subTrack.indexByOriginalIndex(track.fixedSize() - 1)) + 1 );
   }
-
+  
   track.resetChanges();
 }
 
diff --git a/toonz/sources/tnztools/toonzrasterbrushtool.cpp b/toonz/sources/tnztools/toonzrasterbrushtool.cpp
index 9bfafd6..c3935bc 100644
--- a/toonz/sources/tnztools/toonzrasterbrushtool.cpp
+++ b/toonz/sources/tnztools/toonzrasterbrushtool.cpp
@@ -782,7 +782,7 @@ ToonzRasterBrushTool::ToonzRasterBrushTool(std::string name, int targetType)
   for(int i = 0; i < 3; ++i)
     m_modifierSmooth[i]        = new TModifierSmooth();
 #ifndef NDEBUG
-  m_modifierTest = new TModifierTest(5, 40);
+  m_modifierTest = new TModifierTest();
 #endif
 
   m_inputmanager.addModifier(
@@ -1040,15 +1040,15 @@ bool ToonzRasterBrushTool::askWrite(const TRect &rect) {
 
 bool ToonzRasterBrushTool::preLeftButtonDown() {
   int smoothRadius = (int)round(m_smooth.getValue());
-  m_modifierAssistants->drawOnly = !m_assistants.getValue();
-  m_inputmanager.drawPreview     = false; //!m_modifierAssistants->drawOnly;
+  m_modifierAssistants->magnetism = m_assistants.getValue() ? 1 : 0;
+  m_inputmanager.drawPreview      = false; //!m_modifierAssistants->drawOnly;
 
   m_inputmanager.clearModifiers();
   m_inputmanager.addModifier(TInputModifierP(m_modifierTangents.getPointer()));
   if (smoothRadius > 0) {
     m_inputmanager.addModifier(TInputModifierP(m_modifierSmoothSegmentation.getPointer()));
     for(int i = 0; i < 3; ++i) {
-      m_modifierSmooth[i]->setRadius(smoothRadius);
+      m_modifierSmooth[i]->radius = smoothRadius;
       m_inputmanager.addModifier(TInputModifierP(m_modifierSmooth[i].getPointer()));
     }
   }
@@ -1080,7 +1080,7 @@ void ToonzRasterBrushTool::handleMouseEvent(MouseEventType type,
   bool control  = e.getModifiersMask() & TMouseEvent::CTRL_KEY;
 
   if (shift && type == ME_DOWN && e.button() == Qt::LeftButton && !m_painting.active) {
-    m_modifierAssistants->drawOnly = true;
+    m_modifierAssistants->magnetism = 0;
     m_inputmanager.clearModifiers();
     m_inputmanager.addModifier(TInputModifierP(m_modifierLine.getPointer()));
     m_inputmanager.addModifier(TInputModifierP(m_modifierAssistants.getPointer()));
@@ -1265,8 +1265,8 @@ void ToonzRasterBrushTool::inputPaintTrackPoint(const TTrackPoint &point, const 
   
   // first point must be without handler, following points must be with handler
   // other behaviour is possible bug and must be ignored
-  assert(firstPoint == !track.toolHandler);
-  if (firstPoint != !track.toolHandler)
+  assert(firstPoint == !track.handler);
+  if (firstPoint != !track.handler)
     return;
   
   if (m_painting.myPaint.isActive) {
@@ -1277,9 +1277,9 @@ void ToonzRasterBrushTool::inputPaintTrackPoint(const TTrackPoint &point, const 
     if (firstPoint) {
       handler = new MyPaintStroke(m_workRas, *this, m_painting.myPaint.baseBrush, false);
       handler->brush.beginStroke();
-      track.toolHandler = handler;
+      track.handler = handler;
     }
-    handler = dynamic_cast<MyPaintStroke*>(track.toolHandler.getPointer());
+    handler = dynamic_cast<MyPaintStroke*>(track.handler.getPointer());
     if (!handler) return;
     
     // paint stroke
@@ -1323,9 +1323,9 @@ void ToonzRasterBrushTool::inputPaintTrackPoint(const TTrackPoint &point, const 
         getAboveStyleIdSet(m_painting.styleId, ri->getPalette(), aboveStyleIds);
         handler->brush.setAboveStyleIds(aboveStyleIds);
       }
-      track.toolHandler = handler;
+      track.handler = handler;
     }
-    handler = dynamic_cast<PencilStroke*>(track.toolHandler.getPointer());
+    handler = dynamic_cast<PencilStroke*>(track.handler.getPointer());
     if (!handler) return;
 
     // paint stroke
@@ -1358,9 +1358,9 @@ void ToonzRasterBrushTool::inputPaintTrackPoint(const TTrackPoint &point, const 
         getAboveStyleIdSet(m_painting.styleId, ri->getPalette(), aboveStyleIds);
         handler->brush.setAboveStyleIds(aboveStyleIds);
       }
-      track.toolHandler = handler;
+      track.handler = handler;
     }
-    handler = dynamic_cast<BluredStroke*>(track.toolHandler.getPointer());
+    handler = dynamic_cast<BluredStroke*>(track.handler.getPointer());
     if (!handler) return;
 
     // paint stroke
diff --git a/toonz/sources/tnztools/toonzrasterbrushtool.h b/toonz/sources/tnztools/toonzrasterbrushtool.h
index 370649e..7bbe6b5 100644
--- a/toonz/sources/tnztools/toonzrasterbrushtool.h
+++ b/toonz/sources/tnztools/toonzrasterbrushtool.h
@@ -175,7 +175,7 @@ protected:
   TSmartPointerT<TModifierTest> m_modifierTest;
 #endif
 
-  class MyPaintStroke: public TTrackToolHandler {
+  class MyPaintStroke: public TTrackHandler {
   public:
     MyPaintToonzBrush brush;
     
@@ -189,7 +189,7 @@ protected:
     { }
   };
   
-  class PencilStroke: public TTrackToolHandler {
+  class PencilStroke: public TTrackHandler {
   public:
     RasterStrokeGenerator brush;
     
@@ -202,7 +202,7 @@ protected:
     { }
   };
 
-  class BluredStroke: public TTrackToolHandler {
+  class BluredStroke: public TTrackHandler {
   public:
     BluredBrush brush;
     
diff --git a/toonz/sources/tnztools/toonzvectorbrushtool.cpp b/toonz/sources/tnztools/toonzvectorbrushtool.cpp
index edd576d..11645f6 100644
--- a/toonz/sources/tnztools/toonzvectorbrushtool.cpp
+++ b/toonz/sources/tnztools/toonzvectorbrushtool.cpp
@@ -592,7 +592,7 @@ ToonzVectorBrushTool::ToonzVectorBrushTool(std::string name, int targetType)
     m_modifierSmooth[i]        = new TModifierSmooth();
   m_modifierSimplify           = new TModifierSimplify();
 #ifndef NDEBUG
-  m_modifierTest = new TModifierTest(5, 40);
+  m_modifierTest = new TModifierTest();
 #endif
 
   m_inputmanager.addModifier(
@@ -957,7 +957,7 @@ void ToonzVectorBrushTool::inputSetBusy(bool busy) {
 //--------------------------------------------------------------------------------------------------
 
 void ToonzVectorBrushTool::inputPaintTracks(const TTrackList &tracks) {
-  if (tracks.size() != 1 || !tracks.front()) return;
+  if (tracks.empty()) return;
 
   TRectD invalidateRect;
   
@@ -996,11 +996,12 @@ void ToonzVectorBrushTool::inputPaintTracks(const TTrackList &tracks) {
 bool ToonzVectorBrushTool::preLeftButtonDown() {
   if (getViewer() && getViewer()->getGuidedStrokePickerMode()) return false;
 
+  m_pixelSize = getPixelSize();
   int smoothRadius = (int)round(m_smooth.getValue());
-  m_modifierAssistants->drawOnly = !m_assistants.getValue();
+  m_modifierAssistants->magnetism = m_assistants.getValue() ? 1 : 0;
   m_modifierSegmentation->setStep(TPointD(m_pixelSize, m_pixelSize));
   m_modifierSmoothSegmentation->setStep(TPointD(2*m_pixelSize, 2*m_pixelSize));
-  m_modifierSimplify->setStep(2*m_pixelSize);
+  m_modifierSimplify->step = 2*m_pixelSize;
   m_inputmanager.drawPreview = false;
 
   m_inputmanager.clearModifiers();
@@ -1008,7 +1009,7 @@ bool ToonzVectorBrushTool::preLeftButtonDown() {
   if (smoothRadius > 0) {
     m_inputmanager.addModifier(TInputModifierP(m_modifierSmoothSegmentation.getPointer()));
     for(int i = 0; i < 3; ++i) {
-      m_modifierSmooth[i]->setRadius(smoothRadius);
+      m_modifierSmooth[i]->radius = smoothRadius;
       m_inputmanager.addModifier(TInputModifierP(m_modifierSmooth[i].getPointer()));
     }
   }
@@ -1041,7 +1042,7 @@ void ToonzVectorBrushTool::handleMouseEvent(MouseEventType type,
   bool control  = e.getModifiersMask() & TMouseEvent::CTRL_KEY;
 
   if (shift && type == ME_DOWN && e.button() == Qt::LeftButton && !m_active) {
-    m_modifierAssistants->drawOnly = true;
+    m_modifierAssistants->magnetism = 0;
     m_inputmanager.clearModifiers();
     m_inputmanager.addModifier(TInputModifierP(m_modifierLine.getPointer()));
     m_inputmanager.addModifier(TInputModifierP(m_modifierAssistants.getPointer()));
diff --git a/toonz/sources/tnztools/track.cpp b/toonz/sources/tnztools/track.cpp
index 5af347a..2637216 100644
--- a/toonz/sources/tnztools/track.cpp
+++ b/toonz/sources/tnztools/track.cpp
@@ -11,14 +11,13 @@ TTrack::Id TTrack::m_lastId = 0;
 
 
 //*****************************************************************************************
-//    TTrackModifier implemantation
+//    TTrackIntrOrig implemantation
 //*****************************************************************************************
 
 TTrackPoint
-TTrackModifier::calcPoint(double originalIndex) {
-  TTrackPoint p = original.calcPoint(originalIndex);
-  p.originalIndex = originalIndex;
-  return p;
+TTrackIntrOrig::interpolate(double index) {
+  return track.original ? track.calcPointFromOriginal(track.originalIndexByIndex(index))
+                        : track.interpolateLinear(index);
 }
 
 
@@ -32,7 +31,8 @@ TTrack::TTrack(
   const TInputState::KeyHistory::Holder &keyHistory,
   const TInputState::ButtonHistory::Holder &buttonHistory,
   bool hasPressure,
-  bool hasTilt
+  bool hasTilt,
+  double timeOffset
 ):
   id(++m_lastId),
   deviceId(deviceId),
@@ -41,21 +41,26 @@ TTrack::TTrack(
   buttonHistory(buttonHistory),
   hasPressure(hasPressure),
   hasTilt(hasTilt),
+  original(),
+  timeOffset(timeOffset),
+  rootTimeOffset(timeOffset),
   pointsRemoved(),
   pointsAdded(),
   fixedPointsAdded(),
   m_pointsFixed()
   { }
 
-TTrack::TTrack(const TTrackModifierP &modifier):
+TTrack::TTrack(const TTrack &original, double timeOffset):
   id(++m_lastId),
-  deviceId(modifier->original.deviceId),
-  touchId(modifier->original.touchId),
-  keyHistory(modifier->original.keyHistory),
-  buttonHistory(modifier->original.buttonHistory),
-  hasPressure(modifier->original.hasPressure),
-  hasTilt(modifier->original.hasTilt),
-  modifier(modifier),
+  deviceId(original.deviceId),
+  touchId(original.touchId),
+  keyHistory(original.keyHistory),
+  buttonHistory(original.buttonHistory),
+  hasPressure(original.hasPressure),
+  hasTilt(original.hasTilt),
+  original(&original),
+  timeOffset(timeOffset),
+  rootTimeOffset(original.rootTimeOffset + timeOffset),
   pointsRemoved(),
   pointsAdded(),
   fixedPointsAdded(),
@@ -64,15 +69,15 @@ TTrack::TTrack(const TTrackModifierP &modifier):
 
 const TTrack*
 TTrack::root() const
-  { return original() ? original()->root() : this; }
+  { return original ? original->root() : this; }
 
 int
 TTrack::level() const
-  { return original() ? original()->level() + 1 : 0; }
+  { return original ? original->level() + 1 : 0; }
 
 int
 TTrack::floorIndex(double index, double *outFrac) const {
-  int i = (int)floor(index + TConsts::epsilon);
+  int i = floorIndexNoClamp(index);
   if (i > size() - 1) {
     if (outFrac) *outFrac = 0.0;
     return size() - 1;
@@ -87,10 +92,13 @@ TTrack::floorIndex(double index, double *outFrac) const {
 
 void
 TTrack::push_back(const TTrackPoint &point, bool fixed) {
+  assert(m_points.empty() || !m_points.back().final);
   m_points.push_back(point);
-  if (size() > 1) {
+  TTrackPoint &p = m_points.back();
+  if (m_points.size() <= 1) {
+    p.length = 0;
+  } else {
     const TTrackPoint &prev = *(m_points.rbegin() + 1);
-    TTrackPoint &p = m_points.back();
 
     // fix originalIndex
     if (p.originalIndex < prev.originalIndex)
@@ -100,8 +108,7 @@ TTrack::push_back(const TTrackPoint &point, bool fixed) {
     p.time = std::max(p.time, prev.time + TToolTimer::step);
 
     // calculate length
-    TPointD d = p.position - prev.position;
-    p.length = prev.length + sqrt(d.x*d.x + d.y*d.y);
+    p.length = prev.length + tdistance(p.position, prev.position);
   }
   ++pointsAdded;
   if (fixed) fix_all();
@@ -130,13 +137,6 @@ TTrack::fix_points(int count) {
 }
 
 
-TTrackPoint
-TTrack::calcPoint(double index) const {
-  return modifier
-       ? modifier->calcPoint( originalIndexByIndex(index) )
-       : interpolateLinear(index);
-}
-
 TPointD
 TTrack::calcTangent(double index, double distance) const {
   double minDistance = 10.0*TConsts::epsilon;
@@ -150,14 +150,14 @@ TTrack::calcTangent(double index, double distance) const {
 
 double
 TTrack::rootIndexByIndex(double index) const {
-  return modifier
-       ? modifier->original.rootIndexByIndex( originalIndexByIndex(index) )
+  return original
+       ? original->rootIndexByIndex( originalIndexByIndex(index) )
        : index;
 }
 
 TTrackPoint
 TTrack::calcRootPoint(double index) const {
-  return modifier
-       ? modifier->original.calcRootPoint( originalIndexByIndex(index) )
+  return original
+       ? original->calcRootPoint( originalIndexByIndex(index) )
        : calcPoint(index);
 }
diff --git a/toonz/sources/toonzlib/strokegenerator.cpp b/toonz/sources/toonzlib/strokegenerator.cpp
index 755a928..cac636b 100644
--- a/toonz/sources/toonzlib/strokegenerator.cpp
+++ b/toonz/sources/toonzlib/strokegenerator.cpp
@@ -159,10 +159,10 @@ void StrokeGenerator::drawFragments(int first, int last) {
       if (b.thick == 0) b.thick = 0.1;
     }
     // m_p0 = m_p1 = b;
-    v          = a.thick * normalize(rotate90(b - a));
+    v          = a.thick * normalizeOrZero(rotate90(b - a));
     m_p0       = a + v;
     m_p1       = a - v;
-    v          = b.thick * normalize(rotate90(b - a));
+    v          = b.thick * normalizeOrZero(rotate90(b - a));
     TPointD p0 = b + v;
     TPointD p1 = b - v;
     glBegin(GL_POLYGON);
@@ -190,11 +190,11 @@ void StrokeGenerator::drawFragments(int first, int last) {
       if (c.thick == 0) c.thick = 0.1;
     }
     if (i - 1 == 0) {
-      v    = a.thick * normalize(rotate90(b - a));
+      v    = a.thick * normalizeOrZero(rotate90(b - a));
       m_p0 = a + v;
       m_p1 = a - v;
     }
-    v          = b.thick * normalize(rotate90(c - a));
+    v          = b.thick * normalizeOrZero(rotate90(c - a));
     TPointD p0 = b + v;
     TPointD p1 = b - v;
     glBegin(GL_POLYGON);
@@ -214,7 +214,7 @@ void StrokeGenerator::drawFragments(int first, int last) {
   }
   if (last < 2) return;
   v = m_points[last].thick *
-      normalize(rotate90(m_points[last] - m_points[last - 1]));
+      normalizeOrZero(rotate90(m_points[last] - m_points[last - 1]));
   TPointD p0 = m_points[last] + v;
   TPointD p1 = m_points[last] - v;
   glBegin(GL_POLYGON);