diff --git a/toonz/sources/include/tools/assistant.h b/toonz/sources/include/tools/assistant.h
index 3ec9c7f..448f53f 100644
--- a/toonz/sources/include/tools/assistant.h
+++ b/toonz/sources/include/tools/assistant.h
@@ -46,7 +46,7 @@ class TGuideline;
 
 typedef TSmartPointerT<TGuideline> TGuidelineP;
 typedef std::vector<TGuidelineP> TGuidelineList;
-typedef std::vector<TAssistantPoint> TAssistantPointList;
+typedef std::map<TStringId, TAssistantPoint> TAssistantPointMap;
 
 //===================================================================
 
@@ -97,16 +97,19 @@ public:
   enum Type {
     Circle,
     CircleFill,
-    CircleCross
+    CircleCross,
+    CircleGrid
   };
 
+  const TStringId name;
   Type type;
   TPointD position;
-  mutable bool selected;
   double radius;
+  bool visible;
+
+  mutable bool selected;
 
-  explicit TAssistantPoint(Type type = Circle, const TPointD &position = TPointD());
-  TAssistantPoint(Type type, const TPointD &position, double radius);
+  explicit TAssistantPoint(const TStringId &name);
 };
 
 
@@ -189,26 +192,29 @@ protected:
   const TStringId m_idY;
   const TStringId m_idMagnetism;
 
-  TAssistantPointList m_points;
+  TAssistantPointMap m_points;
+  TAssistantPoint* m_basePoint;
 
   mutable TPropertyGroup m_properties;
 
 public:
   TAssistant(TMetaObject &object);
 
-  static const TPointD& blank();
-
   static QString getLocalName()
     { return QString(); }
 
-  inline const TAssistantPointList& points() const
+  inline const TAssistantPointMap& points() const
     { return m_points; }
-  inline const int pointsCount() const
-    { return (int)m_points.size(); }
+
+  inline const TAssistantPoint* findPoint(const TStringId &name) const {
+    TAssistantPointMap::const_iterator i = points().find(name);
+    return i == points().end() ? 0 : &i->second;
+  }
 
   void fixPoints();
-  void movePoint(int index, const TPointD &position);
-  void setPointSelection(int index, bool selected) const;
+  void movePoint(const TStringId &name, const TPointD &position);
+  void setPointSelection(const TStringId &name, bool selected) const;
+  void setAllPointsSelection(bool selected) const;
 
   bool getEnabled() const
     { return data()[m_idEnabled].getBool(); }
@@ -220,21 +226,51 @@ public:
   void setMagnetism(double x)
     { if (getMagnetism() != x) data()[m_idMagnetism].setDouble(x); }
 
-  inline void selectPoint(int index) const
-    { setPointSelection(index, true); }
-  inline void deselectPoint(int index) const
-    { setPointSelection(index, false); }
+  inline void selectPoint(const TStringId &name) const
+    { setPointSelection(name, true); }
+  inline void deselectPoint(const TStringId &name) const
+    { setPointSelection(name, false); }
   inline void selectAll() const
-    { for(int i = 0; i < pointsCount(); ++i) setPointSelection(i, true); }
+    { setAllPointsSelection(true); }
   inline void deselectAll() const
-    { for(int i = 0; i < pointsCount(); ++i) setPointSelection(i, false); }
+  { setAllPointsSelection(false); }
 
   TPropertyGroup& getProperties() const
     { return m_properties; }
   void propertyChanged(const TStringId &name)
     { LockEvents lock(*this); onPropertyChanged(name); }
 
+  const TAssistantPoint& getBasePoint() const;
+
 protected:
+  TAssistantPoint& addPoint(
+    const TStringId &name,
+    TAssistantPoint::Type type,
+    const TPointD &position,
+    bool visible,
+    double radius );
+
+  TAssistantPoint& addPoint(
+    const TStringId &name,
+    TAssistantPoint::Type type = TAssistantPoint::Circle,
+    const TPointD &position    = TPointD(),
+    bool visible               = true );
+
+  inline TAssistantPoint& addPoint(
+    const std::string &name,
+    TAssistantPoint::Type type,
+    const TPointD &position,
+    bool visible,
+    double radius )
+      { return addPoint(TStringId(name), type, position, visible, radius); }
+
+  inline TAssistantPoint& addPoint(
+    const std::string &name,
+    TAssistantPoint::Type type = TAssistantPoint::Circle,
+    const TPointD &position    = TPointD(),
+    bool visible               = true )
+      { return addPoint(TStringId(name), type, position, visible); }
+
   //! usually called when meta-object created
   void onSetDefaults() override;
   //! called when part of variant data changed
@@ -244,7 +280,7 @@ protected:
   //! fix positions of all points (as like as all points moved)
   virtual void onFixPoints();
   //! try to move point
-  virtual void onMovePoint(int index, const TPointD &position);
+  virtual void onMovePoint(TAssistantPoint &point, const TPointD &position);
   //! save object data to variant
   virtual void onFixData();
   //! load all properties from variant
diff --git a/toonz/sources/tnztools/assistant.cpp b/toonz/sources/tnztools/assistant.cpp
index b4f669f..a7a4451 100644
--- a/toonz/sources/tnztools/assistant.cpp
+++ b/toonz/sources/tnztools/assistant.cpp
@@ -5,6 +5,7 @@
 #include <tproperty.h>
 
 #include <limits>
+#include <cassert>
 
 
 //************************************************************************
@@ -105,25 +106,12 @@ TGuideline::findBest(const TGuidelineList &guidelines, const TTrack &track, cons
 //    TAssistantPoint implementation
 //************************************************************************
 
-TAssistantPoint::TAssistantPoint(
-  Type type,
-  const TPointD &position
-):
-  type(type),
+TAssistantPoint::TAssistantPoint(const TStringId &name):
+  name(name),
+  type(Circle),
   position(position),
   radius(10.0),
-  selected() { }
-
-//---------------------------------------------------------------------------------------------------
-
-TAssistantPoint::TAssistantPoint(
-  Type type,
-  const TPointD &position,
-  double radius
-):
-  type(type),
-  position(position),
-  radius(radius),
+  visible(true),
   selected() { }
 
 
@@ -146,7 +134,8 @@ TAssistant::TAssistant(TMetaObject &object):
   m_idPoints("points"),
   m_idX("x"),
   m_idY("y"),
-  m_idMagnetism("magnetism")
+  m_idMagnetism("magnetism"),
+  m_basePoint()
 {
   addProperty( new TBoolProperty(m_idEnabled.str(), getEnabled()) );
   addProperty( new TDoubleProperty(m_idMagnetism.str(), 0.0, 1.0, getMagnetism()) );
@@ -154,6 +143,43 @@ TAssistant::TAssistant(TMetaObject &object):
 
 //---------------------------------------------------------------------------------------------------
 
+TAssistantPoint&
+TAssistant::addPoint(
+  const TStringId &name,
+  TAssistantPoint::Type type,
+  const TPointD &position,
+  bool visible,
+  double radius )
+{
+  assert(!m_points.count(name));
+  TAssistantPoint &p = m_points.insert(
+    TAssistantPointMap::value_type(name, TAssistantPoint(name)) ).first->second;
+  p.type     = type;
+  p.position = position;
+  p.radius   = radius;
+  p.visible  = visible;
+  if (!m_basePoint) m_basePoint = &p;
+  return p;
+}
+
+//---------------------------------------------------------------------------------------------------
+
+TAssistantPoint&
+TAssistant::addPoint(
+  const TStringId &name,
+  TAssistantPoint::Type type,
+  const TPointD &position,
+  bool visible )
+    { return addPoint(name, type, position, visible, 10.0); }
+
+//---------------------------------------------------------------------------------------------------
+
+const TAssistantPoint&
+TAssistant::getBasePoint() const
+  { assert(m_basePoint); return *m_basePoint; }
+
+//---------------------------------------------------------------------------------------------------
+
 void
 TAssistant::addProperty(TProperty *p)
   { m_properties.add(p); }
@@ -182,30 +208,33 @@ TAssistant::onSetDefaults() {
 
 //---------------------------------------------------------------------------------------------------
 
-const TPointD&
-TAssistant::blank() {
-  static TPointD point;
-  return point;
-}
+void
+TAssistant::fixPoints()
+  { onFixPoints(); }
 
 //---------------------------------------------------------------------------------------------------
 
 void
-TAssistant::fixPoints()
-  { onFixPoints(); }
+TAssistant::movePoint(const TStringId &name, const TPointD &position) {
+  TAssistantPointMap::iterator i = m_points.find(name);
+  if (i != m_points.end())
+    onMovePoint(i->second, position);
+}
 
 //---------------------------------------------------------------------------------------------------
 
 void
-TAssistant::movePoint(int index, const TPointD &position)
-  { if (index >= 0 && index < (int)m_points.size()) onMovePoint(index, position); }
+TAssistant::setPointSelection(const TStringId &name, bool selected)  const {
+  if (const TAssistantPoint *p = findPoint(name))
+    p->selected = selected;
+}
 
 //---------------------------------------------------------------------------------------------------
 
 void
-TAssistant::setPointSelection(int index, bool selected)  const {
-  if (index >= 0 && index < pointsCount())
-    m_points[index].selected = selected;
+TAssistant::setAllPointsSelection(bool selected) const {
+  for(TAssistantPointMap::const_iterator i = points().begin(); i != points().end(); ++i)
+    i->second.selected = selected;
 }
 
 //---------------------------------------------------------------------------------------------------
@@ -218,12 +247,12 @@ TAssistant::onDataChanged(const TVariant &value) {
   if (&value == &data() || &value == &pointsData)
     onAllDataChanged();
   else
-  if (pointsData.getChildPathEntry(value, entry) && entry.isIndex()) {
+  if (pointsData.getChildPathEntry(value, entry) && entry.isField()) {
     const TVariant& pointData = pointsData[entry];
     TPointD position = TPointD(
       pointData[m_idX].getDouble(),
       pointData[m_idY].getDouble() );
-    movePoint(entry.index(), position);
+    movePoint(entry.field(), position);
   } else
   if (data().getChildPathEntry(value, entry) && entry.isField()) {
     updateProperty(entry.field(), data()[entry.field()]);
@@ -235,9 +264,9 @@ TAssistant::onDataChanged(const TVariant &value) {
 void
 TAssistant::onAllDataChanged() {
   const TVariant& pointsData = data()[m_idPoints];
-  for(int i = 0; i < pointsCount(); ++i) {
-    const TVariant& pointData = pointsData[i];
-    m_points[i].position = TPointD(
+  for(TAssistantPointMap::iterator i = m_points.begin(); i != m_points.end(); ++i) {
+    const TVariant& pointData = pointsData[i->first];
+    i->second.position = TPointD(
       pointData[m_idX].getDouble(),
       pointData[m_idY].getDouble() );
   }
@@ -254,18 +283,18 @@ TAssistant::onFixPoints()
 //---------------------------------------------------------------------------------------------------
 
 void
-TAssistant::onMovePoint(int index, const TPointD &position)
-  { m_points[index].position = position; }
+TAssistant::onMovePoint(TAssistantPoint &point, const TPointD &position)
+  { point.position = position; }
 
 //---------------------------------------------------------------------------------------------------
 
 void
 TAssistant::onFixData() {
   TVariant& pointsData = data()[m_idPoints];
-  for(int i = 0; i < pointsCount(); ++i) {
-    TVariant& pointData = pointsData[i];
-    pointData[m_idX].setDouble( m_points[i].position.x );
-    pointData[m_idY].setDouble( m_points[i].position.y );
+  for(TAssistantPointMap::const_iterator i = points().begin(); i != points().end(); ++i) {
+    TVariant& pointData = pointsData[i->first];
+    pointData[m_idX].setDouble( i->second.position.x );
+    pointData[m_idY].setDouble( i->second.position.y );
   }
   setMagnetism( std::max(0.0, std::min(1.0, getMagnetism())) );
 }
@@ -356,6 +385,8 @@ TAssistant::drawSegment(const TPointD &p0, const TPointD &p1, double pixelSize, 
 
 void
 TAssistant::drawPoint(const TAssistantPoint &point, double pixelSize) const {
+  if (!point.visible) return;
+
   double radius = point.radius;
   double crossSize = 1.2*radius;
 
@@ -422,8 +453,8 @@ TAssistant::drawEdit(TToolViewer *viewer) const {
   // paint all points
   draw(viewer);
   double pixelSize = sqrt(tglGetPixelSize2());
-  for(int i = 0; i < pointsCount(); ++i)
-    drawPoint(m_points[i], pixelSize);
+  for(TAssistantPointMap::const_iterator i = points().begin(); i != points().end(); ++i)
+    drawPoint(i->second, pixelSize);
 }
 
 //---------------------------------------------------------------------------------------------------
diff --git a/toonz/sources/tnztools/assistants/assistantvanishingpoint.cpp b/toonz/sources/tnztools/assistants/assistantvanishingpoint.cpp
index 0c4a3f9..0e7887b 100644
--- a/toonz/sources/tnztools/assistants/assistantvanishingpoint.cpp
+++ b/toonz/sources/tnztools/assistants/assistantvanishingpoint.cpp
@@ -15,13 +15,14 @@
 
 class DVAPI TAssistantVanishingPoint final : public TAssistant {
   Q_DECLARE_TR_FUNCTIONS(TAssistantVanishingPoint)
+protected:
+  TAssistantPoint &m_pointCenter;
+
 public:
   TAssistantVanishingPoint(TMetaObject &object):
-    TAssistant(object)
-  {
-    m_points.push_back(TAssistantPoint(
-      TAssistantPoint::CircleCross ));
-  }
+    TAssistant(object),
+    m_pointCenter( addPoint("center", TAssistantPoint::CircleCross) )
+  { }
 
   static QString getLocalName()
     { return tr("Vanishing Point"); }
@@ -35,13 +36,13 @@ public:
       new TGuidelineInfiniteLine(
         getEnabled(),
         getMagnetism(),
-        toTool*m_points.front().position,
+        toTool * m_pointCenter.position,
         position )));
   }
 
   void draw(TToolViewer *viewer, bool enabled) const override {
     double pixelSize = sqrt(tglGetPixelSize2());
-    const TPointD &p = m_points.front().position;
+    const TPointD &p = m_pointCenter.position;
     TPointD dx(20.0*pixelSize, 0.0);
     TPointD dy(0.0, 10.0*pixelSize);
     drawSegment(p-dx-dy, p+dx+dy, pixelSize, enabled);
diff --git a/toonz/sources/tnztools/editassistantstool.cpp b/toonz/sources/tnztools/editassistantstool.cpp
index d89ac37..f694613 100644
--- a/toonz/sources/tnztools/editassistantstool.cpp
+++ b/toonz/sources/tnztools/editassistantstool.cpp
@@ -33,6 +33,7 @@ class EditAssistantsUndo final : public ToolUtils::TToolUndo {
 private:
   bool m_isCreated;
   bool m_isRemoved;
+  int m_index;
   TMetaObjectP m_metaObject;
   TVariant m_oldData;
   TVariant m_newData;
@@ -46,12 +47,14 @@ public:
     bool levelCreated,
     bool objectCreated,
     bool objectRemoved,
+    int index,
     TMetaObjectP metaObject,
     TVariant oldData
   ):
     ToolUtils::TToolUndo(level, frameId, frameCreated, levelCreated),
     m_isCreated(objectCreated),
     m_isRemoved(objectRemoved),
+    m_index(index),
     m_metaObject(metaObject),
     m_oldData(oldData),
     m_newData(m_metaObject->data()),
@@ -64,24 +67,23 @@ public:
     { return QString("Edit Assistants Tool"); }
 
   void process(bool remove, const TVariant &data) const {
-    if (TMetaImage *metaImage = dynamic_cast<TMetaImage*>(m_level->getFrame(m_frameId, true).getPointer()))
-    {
-      { // wrap writer
-        TMetaImage::Writer writer(*metaImage);
-        bool found = false;
-        for(TMetaObjectList::iterator i = writer->begin(); i != writer->end(); ++i)
-          if ((*i) == m_metaObject) {
-            if (remove) writer->erase(i);
-            found = true;
-            break;
-          }
-        if (!remove) {
-          if (!found)
-            writer->push_back(m_metaObject);
-          m_metaObject->data() = data;
-          if (m_metaObject->handler())
-            m_metaObject->handler()->fixData();
+    if (TMetaImage *metaImage = dynamic_cast<TMetaImage*>(m_level->getFrame(m_frameId, true).getPointer())) {
+      TMetaImage::Writer writer(*metaImage);
+      bool found = false;
+      for(TMetaObjectList::iterator i = writer->begin(); i != writer->end(); ++i)
+        if ((*i) == m_metaObject) {
+          if (remove) writer->erase(i);
+          found = true;
+          break;
         }
+      if (!remove) {
+        if (!found)
+          writer->insert(
+            writer->begin() + std::max(0, std::min((int)writer->size(), m_index)),
+            m_metaObject );
+        m_metaObject->data() = data;
+        if (m_metaObject->handler())
+          m_metaObject->handler()->fixData();
       }
     }
   }
@@ -126,7 +128,7 @@ protected:
   bool           m_currentAssistantChanged;
   int            m_currentAssistantIndex;
   TVariant       m_currentAssistantBackup;
-  int            m_currentPointIndex;
+  TStringId      m_currentPointName;
   TPointD        m_currentPointOffset;
   TPointD        m_currentPosition;
   TGuidelineList m_currentGuidelines;
@@ -149,7 +151,6 @@ public:
     m_currentAssistantCreated(),
     m_currentAssistantChanged(),
     m_currentAssistantIndex(-1),
-    m_currentPointIndex(-1),
     m_reader(),
     m_readImage(),
     m_readAssistant(),
@@ -246,7 +247,7 @@ protected:
 
     if ( (mode >= ModeAssistant && !m_currentAssistant)
       || (mode >= ModeAssistant && m_currentAssistantIndex < 0)
-      || (mode >= ModePoint && m_currentPointIndex < 0) ) return false;
+      || (mode >= ModePoint && !m_currentPointName) ) return false;
 
     m_readImage = dynamic_cast<TMetaImage*>(getImage(true));
     if (m_readImage) {
@@ -260,7 +261,7 @@ protected:
         m_readAssistant = m_readObject->getHandler<TAssistant>();
         if (mode == ModeAssistant) return true;
 
-        if (m_currentPointIndex < m_readAssistant->pointsCount()) {
+        if (m_readAssistant->findPoint(m_currentPointName)) {
           if (mode == ModePoint) return true;
         }
       }
@@ -282,7 +283,7 @@ protected:
 
     if ( (mode >= ModeAssistant && !m_currentAssistant)
       || (mode >= ModeAssistant && m_currentAssistantIndex < 0)
-      || (mode >= ModePoint && m_currentPointIndex < 0) ) return false;
+      || (mode >= ModePoint && !m_currentPointName) ) return false;
 
     m_writeImage = dynamic_cast<TMetaImage*>(getImage(true));
     if (m_writeImage) {
@@ -295,7 +296,7 @@ protected:
         m_writeObject = (**m_writer)[m_currentAssistantIndex];
         m_writeAssistant = m_writeObject->getHandler<TAssistant>();
         if ( (mode == ModeAssistant)
-          || (mode == ModePoint && m_currentPointIndex < m_writeAssistant->pointsCount()) )
+          || (mode == ModePoint && m_writeAssistant->findPoint(m_currentPointName)) )
         {
           if (touch) this->touch();
           return true;
@@ -340,7 +341,7 @@ protected:
     m_currentAssistantCreated = false;
     m_currentAssistantChanged = false;
     m_currentAssistantIndex = -1;
-    m_currentPointIndex = -1;
+    m_currentPointName.reset();
     m_currentPointOffset = TPointD();
     m_currentAssistantBackup.reset();
     if (updateOptionsBox) this->updateOptionsBox();
@@ -356,13 +357,14 @@ protected:
         if (!assistant) continue;
 
         assistant->deselectAll();
-        for(int j = 0; j < assistant->pointsCount() && m_currentAssistantIndex < 0; ++j) {
-          const TAssistantPoint &p = assistant->points()[j];
+        const TAssistantPointMap &points = assistant->points();
+        for(TAssistantPointMap::const_iterator j = points.begin(); j != points.end() && m_currentAssistantIndex < 0; ++j) {
+          const TAssistantPoint &p = j->second;
           TPointD offset = p.position - position;
-          if (norm2(offset) <= p.radius*p.radius*pixelSize*pixelSize) {
+          if (p.visible && norm2(offset) <= p.radius*p.radius*pixelSize*pixelSize) {
             m_currentAssistant.set(*i);
             m_currentAssistantIndex = i - (*m_reader)->begin();
-            m_currentPointIndex = j;
+            m_currentPointName = j->first;
             m_currentPointOffset = offset;
             assistant->selectAll();
           }
@@ -386,6 +388,7 @@ protected:
           m_isLevelCreated,
           m_currentAssistantCreated,
           false,
+          m_currentAssistantIndex,
           m_writeObject,
           m_currentAssistantBackup ));
         m_currentAssistantCreated = false;
@@ -420,17 +423,15 @@ public:
       if (Closer closer = write(ModeImage)) {
         TMetaObjectP object(new TMetaObject(m_newAssisnantType));
         if (TAssistant *assistant = object->getHandler<TAssistant>()) {
-          if (assistant->pointsCount()) {
-            assistant->setDefaults();
-            assistant->movePoint(0, position);
-            m_currentAssistantCreated = true;
-            m_currentAssistantChanged = true;
-            m_currentAssistantIndex = (int)(*m_writer)->size();
-            m_currentAssistant = object;
-            m_currentPointIndex = 0;
-            m_currentPointOffset = TPointD();
-            m_currentAssistantBackup = assistant->data();
-          }
+          assistant->setDefaults();
+          assistant->movePoint(assistant->getBasePoint().name, position);
+          m_currentAssistantCreated = true;
+          m_currentAssistantChanged = true;
+          m_currentAssistantIndex = (int)(*m_writer)->size();
+          m_currentAssistant = object;
+          m_currentPointName = assistant->getBasePoint().name;
+          m_currentPointOffset = TPointD();
+          m_currentAssistantBackup = assistant->data();
           (*m_writer)->push_back(object);
         }
       }
@@ -446,7 +447,7 @@ public:
   void leftButtonDrag(const TPointD &position, const TMouseEvent&) override {
     if (Closer closer = write(ModePoint, true))
       m_writeAssistant->movePoint(
-        m_currentPointIndex,
+        m_currentPointName,
         position + m_currentPointOffset);
     m_currentPosition = position;
     getViewer()->GLInvalidateAll();
@@ -455,7 +456,7 @@ public:
   void leftButtonUp(const TPointD &position, const TMouseEvent&) override {
     if (Closer closer = write(ModePoint, true))
       m_writeAssistant->movePoint(
-        m_currentPointIndex,
+        m_currentPointName,
         position + m_currentPointOffset);
 
     apply();
@@ -481,6 +482,7 @@ public:
             false, // levelCreated
             false, // objectCreated
             true,  // objectRemoved
+            m_currentAssistantIndex,
             m_writeObject,
             m_writeObject->data() ));
           success = true;