Salome HOME
Implementation of Fitter
[modules/shaper.git] / src / PartSet / PartSet_SketcherMgr.cpp
old mode 100755 (executable)
new mode 100644 (file)
index 88334e9..1576ff0
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2017  CEA/DEN, EDF R&D
+// Copyright (C) 2014-2019  CEA/DEN, EDF R&D
 //
 // This library is free software; you can redistribute it and/or
 // modify it under the terms of the GNU Lesser General Public
 //
 // You should have received a copy of the GNU Lesser General Public
 // License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 //
-// See http://www.salome-platform.org/ or
-// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
 
 #include "PartSet_SketcherMgr.h"
+
+#include "PartSet_Filters.h"
 #include "PartSet_SketcherReentrantMgr.h"
 #include "PartSet_Module.h"
 #include "PartSet_MouseProcessor.h"
@@ -34,6 +35,7 @@
 #include <XGUI_Workshop.h>
 #include <XGUI_ContextMenuMgr.h>
 #include <XGUI_Selection.h>
+#include <XGUI_SelectionActivate.h>
 #include <XGUI_SelectionMgr.h>
 #include <XGUI_ModuleConnector.h>
 #include <XGUI_PropertyPanel.h>
 #include <ModuleBase_ViewerPrs.h>
 #include <ModuleBase_Tools.h>
 #include <ModuleBase_ResultPrs.h>
+#include <ModuleBase_ViewerFilters.h>
 
 #include <GeomDataAPI_Point2D.h>
 
+#include <GeomAPI_Shape.h>
+
 #include <Events_Loop.h>
 
 #include <SketchPlugin_Line.h>
@@ -85,6 +90,9 @@
 #include <SketchPlugin_MultiTranslation.h>
 #include <SketchPlugin_IntersectionPoint.h>
 #include <SketchPlugin_Projection.h>
+#include <SketchPlugin_ConstraintDistanceAlongDir.h>
+#include <SketchPlugin_ConstraintDistanceHorizontal.h>
+#include <SketchPlugin_ConstraintDistanceVertical.h>
 
 #include <SketcherPrs_Tools.h>
 
 //#define DEBUG_DO_NOT_BY_ENTER
 //#define DEBUG_SKETCHER_ENTITIES
 //#define DEBUG_SKETCH_ENTITIES_ON_MOVE
-
+//#define DRAGGING_DEBUG
 //#define DEBUG_CURSOR
 
+
+#ifdef DRAGGING_DEBUG
+#include <QTime>
+#endif
+
 /// Fills attribute and result lists by the selected owner. In case if the attribute is found,
 /// by the owner shape, it is put to the list. Otherwise if type of owner shape is edge,
 /// put the function result as is to the list of results.
@@ -155,7 +168,7 @@ PartSet_SketcherMgr::PartSet_SketcherMgr(PartSet_Module* theModule)
   : QObject(theModule), myModule(theModule), myIsEditLaunching(false), myIsDragging(false),
     myDragDone(false), myIsMouseOverWindow(false),
     myIsMouseOverViewProcessed(true), myPreviousUpdateViewerEnabled(true),
-    myIsPopupMenuActive(false), myExternalPointsMgr(0)
+    myIsPopupMenuActive(false), myExternalPointsMgr(0), myNoDragMoving(false)
 {
   ModuleBase_IWorkshop* anIWorkshop = myModule->workshop();
   ModuleBase_IViewer* aViewer = anIWorkshop->viewer();
@@ -183,12 +196,14 @@ PartSet_SketcherMgr::PartSet_SketcherMgr(PartSet_Module* theModule)
   myIsConstraintsShown[PartSet_Tools::Expressions] = false;
 
   mySketchPlane = new PartSet_PreviewSketchPlane();
+
+  registerSelectionFilter(SF_SketchCirclePointFilter, new PartSet_CirclePointFilter(anIWorkshop));
+  registerSelectionFilter(SF_SketchPlaneFilter, new ModuleBase_ShapeInPlaneFilter());
 }
 
 PartSet_SketcherMgr::~PartSet_SketcherMgr()
 {
-  if (!myPlaneFilter.IsNull())
-    myPlaneFilter.Nullify();
+  delete mySketchPlane;
 }
 
 void PartSet_SketcherMgr::onEnterViewPort()
@@ -338,15 +353,23 @@ void PartSet_SketcherMgr::onMousePressed(ModuleBase_IViewWindow* theWnd, QMouseE
 
   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
   ModuleBase_IViewer* aViewer = aWorkshop->viewer();
-  if (!aViewer->canDragByMouse())
-    return;
+  //if (!aViewer->canDragByMouse())
+  //  return;
 
   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
                                                                (getCurrentOperation());
   if (!aFOperation)
     return;
 
-  if (aFOperation->isEditOperation()) {
+  bool isEditing = aFOperation->isEditOperation();
+  bool aCanDrag = aViewer->canDragByMouse();
+
+  //if (!aViewer->canDragByMouse() && isEditing) {
+  //  // Do not edit by dragging
+  //  return;
+  //}
+
+  if (isEditing) {
     // If the current widget is a selector, do nothing, it processes the mouse press
     ModuleBase_ModelWidget* anActiveWidget = getActiveWidget();
     if(anActiveWidget && anActiveWidget->isViewerSelector()) {
@@ -366,16 +389,10 @@ void PartSet_SketcherMgr::onMousePressed(ModuleBase_IViewWindow* theWnd, QMouseE
     if ((!isSketchOpe) && (!isSketcher))
       return;
 
-    bool isEditing = aFOperation->isEditOperation();
-
     // Ignore creation sketch operation
     if ((!isSketcher) && (!isEditing))
       return;
 
-    Handle(AIS_InteractiveContext) aContext = aViewer->AISContext();
-    // Remember highlighted objects for editing
-    ModuleBase_ISelection* aSelect = aWorkshop->selection();
-
     bool aHasShift = (theEvent->modifiers() & Qt::ShiftModifier);
     storeSelection(aHasShift ? ST_SelectAndHighlightType : ST_HighlightType, myCurrentSelection);
 
@@ -391,9 +408,10 @@ void PartSet_SketcherMgr::onMousePressed(ModuleBase_IViewWindow* theWnd, QMouseE
 
     get2dPoint(theWnd, theEvent, myCurrentPoint);
     if (isSketcher) {
-      myIsDragging = true;
-      myDragDone = false;
-
+      if (aCanDrag) {
+        myIsDragging = true;
+        myDragDone = false;
+      }
       myPreviousDrawModeEnabled = aViewer->enableDrawMode(false);
       launchEditing();
       if (aFeature.get() != NULL) {
@@ -419,9 +437,10 @@ void PartSet_SketcherMgr::onMousePressed(ModuleBase_IViewWindow* theWnd, QMouseE
       myIsEditLaunching = !myModule->sketchReentranceMgr()->isInternalEditActive();
       aFOperation->commit();
 
-      myIsDragging = true;
-      myDragDone = false;
-
+      if (aCanDrag) {
+        myIsDragging = true;
+        myDragDone = false;
+      }
       myPreviousDrawModeEnabled = aViewer->enableDrawMode(false);
       launchEditing();
       myIsEditLaunching = aPrevLaunchingState;
@@ -444,37 +463,56 @@ void PartSet_SketcherMgr::onMousePressed(ModuleBase_IViewWindow* theWnd, QMouseE
 
 void PartSet_SketcherMgr::onMouseReleased(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)
 {
+  ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
+  if (myIsDragging)
+    aWorkshop->viewer()->enableDrawMode(myPreviousDrawModeEnabled);
+
   bool aWasDragging = myIsDragging;
   myIsDragging = false;
 
-  if (myModule->sketchReentranceMgr()->processMouseReleased(theWnd, theEvent))
+  if (myModule->sketchReentranceMgr()->processMouseReleased(theWnd, theEvent)) {
     return;
-
+  }
   // if mouse is pressed when it was over view and at release the mouse is out of view, do nothing
-  if (!myIsMouseOverViewProcessed)
+  if (!myIsMouseOverViewProcessed) {
     return;
-
-  ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
+  }
   ModuleBase_IViewer* aViewer = aWorkshop->viewer();
-  if (!aViewer->canDragByMouse())
-    return;
-  ModuleBase_Operation* aOp = getCurrentOperation();
+  //if (!aViewer->canDragByMouse())
+  //  return;
+  ModuleBase_OperationFeature* aOp =
+      dynamic_cast<ModuleBase_OperationFeature*>(getCurrentOperation());
   if (aOp) {
-    if (isNestedSketchOperation(aOp)) {
-      // Only for sketcher operations
-      if (aWasDragging) {
-        if (myDragDone) {
-          /// the previous selection is lost by mouse release in the viewer(Select method), but
-          /// it is still stored in myCurrentSelection. So, it is possible to restore selection
-          /// It is important for drag(edit with mouse) of sketch entities.
-          restoreSelection(myCurrentSelection);
-          myCurrentSelection.clear();
+    bool aStartNoDragOperation = !aViewer->canDragByMouse() && aOp->isEditOperation();
+    if (aStartNoDragOperation || myNoDragMoving) {
+      // Process edit operation without dragging
+      if (myCurrentSelection.size() > 0)
+        myNoDragMoving = !myNoDragMoving;
+      else
+        myNoDragMoving = false;
+      if (myNoDragMoving)
+        return;
+      else {
+        restoreSelection(myCurrentSelection);
+        myCurrentSelection.clear();
+      }
+    }
+    else {
+      if (isNestedSketchOperation(aOp)) {
+        // Only for sketcher operations
+        if (aWasDragging) {
+          if (myDragDone) {
+            /// the previous selection is lost by mouse release in the viewer(Select method), but
+            /// it is still stored in myCurrentSelection. So, it is possible to restore selection
+            /// It is important for drag(edit with mouse) of sketch entities.
+            restoreSelection(myCurrentSelection);
+            myCurrentSelection.clear();
+          }
         }
       }
     }
   }
 
-  aWorkshop->viewer()->enableDrawMode(myPreviousDrawModeEnabled);
 
   ModuleBase_ModelWidget* anActiveWidget = getActiveWidget();
   PartSet_MouseProcessor* aProcessor = dynamic_cast<PartSet_MouseProcessor*>(anActiveWidget);
@@ -497,11 +535,14 @@ void PartSet_SketcherMgr::onMouseMoved(ModuleBase_IViewWindow* theWnd, QMouseEve
     qDebug(QString("%1").arg(anInfo.size()).arg(anInfoStr).toStdString().c_str());
   }
 #endif
-
   if (myModule->sketchReentranceMgr()->processMouseMoved(theWnd, theEvent))
     return;
 
   if (isNestedCreateOperation(getCurrentOperation(), activeSketch())) {
+#ifdef DRAGGING_DEBUG
+    QTime t;
+    t.start();
+#endif
     // 1. perform the widget mouse move functionality and display the presentation
     // the mouse move should be processed in the widget, if it can in order to visualize correct
     // presentation. These widgets correct the feature attribute according to the mouse position
@@ -515,37 +556,44 @@ void PartSet_SketcherMgr::onMouseMoved(ModuleBase_IViewWindow* theWnd, QMouseEve
       // the feature is to be erased here, but it is correct to call canDisplayObject because
       // there can be additional check (e.g. editor widget in distance constraint)
       ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
-                                                 (getCurrentOperation());
+        (getCurrentOperation());
       if (aFOperation) {
         FeaturePtr aFeature = aFOperation->feature();
         visualizeFeature(aFeature, aFOperation->isEditOperation(), canDisplayObject(aFeature));
       }
     }
+#ifdef DRAGGING_DEBUG
+    cout << "Mouse move processing " << t.elapsed() << endl;
+#endif
   }
   //myClickedPoint.clear();
 
-  if (myIsDragging) {
+  if (myIsDragging || myNoDragMoving) {
     // 1. the current selection is saved in the mouse press method in order to restore it after
     //    moving
     // 2. the enable selection in the viewer should be temporary switched off in order to ignore
     // mouse press signal in the viewer(it call Select for AIS context and the dragged objects are
     // deselected). This flag should be restored in the slot, processed the mouse release signal.
-
     ModuleBase_Operation* aCurrentOperation = getCurrentOperation();
     if (!aCurrentOperation)
       return;
     if (isSketchOperation(aCurrentOperation))
       return; // No edit operation activated
 
+#ifdef DRAGGING_DEBUG
+    QTime t;
+    t.start();
+#endif
+
     Handle(V3d_View) aView = theWnd->v3dView();
     gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), aView);
     Point aMousePnt;
     get2dPoint(theWnd, theEvent, aMousePnt);
 
     std::shared_ptr<GeomAPI_Pnt2d> anOriginalPosition = std::shared_ptr<GeomAPI_Pnt2d>(
-                            new GeomAPI_Pnt2d(myCurrentPoint.myCurX, myCurrentPoint.myCurY));
+      new GeomAPI_Pnt2d(myCurrentPoint.myCurX, myCurrentPoint.myCurY));
     std::shared_ptr<GeomAPI_Pnt2d> aCurrentPosition = std::shared_ptr<GeomAPI_Pnt2d>(
-                            new GeomAPI_Pnt2d(aMousePnt.myCurX, aMousePnt.myCurY));
+      new GeomAPI_Pnt2d(aMousePnt.myCurX, aMousePnt.myCurY));
 
     ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
     XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);
@@ -558,7 +606,7 @@ void PartSet_SketcherMgr::onMouseMoved(ModuleBase_IViewWindow* theWnd, QMouseEve
     static Events_ID aMoveEvent = Events_Loop::eventByName(EVENT_OBJECT_MOVED);
     //static Events_ID aUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
     FeatureToSelectionMap::const_iterator anIt = myCurrentSelection.begin(),
-                                          aLast = myCurrentSelection.end();
+      aLast = myCurrentSelection.end();
     // 4. the features and attributes modification(move)
     bool isModified = false;
     for (; anIt != aLast; anIt++) {
@@ -568,7 +616,7 @@ void PartSet_SketcherMgr::onMouseMoved(ModuleBase_IViewWindow* theWnd, QMouseEve
       // Process selection by attribute: the priority to the attribute
       if (!anAttributes.empty()) {
         std::set<AttributePtr>::const_iterator anAttIt = anAttributes.begin(),
-                                               anAttLast = anAttributes.end();
+          anAttLast = anAttributes.end();
         for (; anAttIt != anAttLast; anAttIt++) {
           AttributePtr anAttr = *anAttIt;
           if (anAttr.get() == NULL)
@@ -582,7 +630,7 @@ void PartSet_SketcherMgr::onMouseMoved(ModuleBase_IViewWindow* theWnd, QMouseEve
               bool isImmutable = aPoint->setImmutable(true);
 
               std::shared_ptr<ModelAPI_ObjectMovedMessage> aMessage = std::shared_ptr
-                       <ModelAPI_ObjectMovedMessage>(new ModelAPI_ObjectMovedMessage(this));
+                <ModelAPI_ObjectMovedMessage>(new ModelAPI_ObjectMovedMessage(this));
               aMessage->setMovedAttribute(aPoint);
               aMessage->setOriginalPosition(anOriginalPosition);
               aMessage->setCurrentPosition(aCurrentPosition);
@@ -593,13 +641,14 @@ void PartSet_SketcherMgr::onMouseMoved(ModuleBase_IViewWindow* theWnd, QMouseEve
             }
           }
         }
-      } else {
+      }
+      else {
         // Process selection by feature
         std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
           std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
         if (aSketchFeature) {
           std::shared_ptr<ModelAPI_ObjectMovedMessage> aMessage = std::shared_ptr
-                    <ModelAPI_ObjectMovedMessage>(new ModelAPI_ObjectMovedMessage(this));
+            <ModelAPI_ObjectMovedMessage>(new ModelAPI_ObjectMovedMessage(this));
           aMessage->setMovedObject(aFeature);
           aMessage->setOriginalPosition(anOriginalPosition);
           aMessage->setCurrentPosition(aCurrentPosition);
@@ -622,6 +671,10 @@ void PartSet_SketcherMgr::onMouseMoved(ModuleBase_IViewWindow* theWnd, QMouseEve
     aDisplayer->enableUpdateViewer(isEnableUpdateViewer);
     aDisplayer->updateViewer();
 
+#ifdef DRAGGING_DEBUG
+    cout << "Mouse move processing " << t.elapsed() << endl;
+#endif
+
     myDragDone = true;
     myCurrentPoint = aMousePnt;
   }
@@ -640,8 +693,10 @@ void PartSet_SketcherMgr::onMouseDoubleClick(ModuleBase_IViewWindow* theWnd, QMo
       QList<ModuleBase_ModelWidget*> aWidgets = aPanel->modelWidgets();
       // Find corresponded widget to activate value editing
       foreach (ModuleBase_ModelWidget* aWgt, aWidgets) {
-        if (aWgt->attributeID() == SketchPlugin_Constraint::VALUE() ||
-            aWgt->attributeID() == SketchPlugin_ConstraintAngle::ANGLE_VALUE_ID()) {
+        std::string anId = aWgt->attributeID();
+        if (anId == SketchPlugin_Constraint::VALUE() ||
+          anId == SketchPlugin_ConstraintAngle::ANGLE_VALUE_ID() ||
+          anId == SketchPlugin_ConstraintDistanceAlongDir::DISTANCE_VALUE_ID()) {
           PartSet_WidgetEditor* anEditor = dynamic_cast<PartSet_WidgetEditor*>(aWgt);
           if (anEditor)
             anEditor->showPopupEditor();
@@ -666,8 +721,8 @@ void PartSet_SketcherMgr::onApplicationStarted()
 
     connect(aPropertyPanel, SIGNAL(noMoreWidgets(const std::string&)),
             aReentranceMgr, SLOT(onNoMoreWidgets(const std::string&)));
-    connect(aPropertyPanel, SIGNAL(widgetActivated(ModuleBase_ModelWidget*)),
-            aReentranceMgr, SLOT(onWidgetActivated()));
+    //connect(aPropertyPanel, SIGNAL(widgetActivated(ModuleBase_ModelWidget*)),
+    //        aReentranceMgr, SLOT(onWidgetActivated()));
   }
 
   XGUI_ViewerProxy* aViewerProxy = aWorkshop->viewer();
@@ -727,10 +782,15 @@ void PartSet_SketcherMgr::launchEditing()
       if (!aSPFeature->isExternal())
         myModule->editFeature(aSPFeature);
       else {
-        FeaturePtr aProjectionFeature = PartSet_Tools::findRefsToMeFeature(aFeature,
+        // need to edit a feature (Projection/IntersectionPoint),
+        // which produces current External feature
+        FeaturePtr aProducerFeature = PartSet_Tools::findRefsToMeFeature(aFeature,
                                                         SketchPlugin_Projection::ID());
-        if (aProjectionFeature.get())
-          myModule->editFeature(aProjectionFeature);
+        if (!aProducerFeature.get())
+          aProducerFeature = PartSet_Tools::findRefsToMeFeature(aFeature,
+                                                        SketchPlugin_IntersectionPoint::ID());
+        if (aProducerFeature.get())
+          myModule->editFeature(aProducerFeature);
       }
     }
   }
@@ -799,13 +859,18 @@ const QStringList& PartSet_SketcherMgr::constraintsIdList()
     aConstraintIds << SketchPlugin_ConstraintMirror::ID().c_str();
     aConstraintIds << SketchPlugin_MultiTranslation::ID().c_str();
     aConstraintIds << SketchPlugin_MultiRotation::ID().c_str();
+    aConstraintIds << SketchPlugin_ConstraintDistanceAlongDir::ID().c_str();
+    aConstraintIds << SketchPlugin_ConstraintDistanceHorizontal::ID().c_str();
+    aConstraintIds << SketchPlugin_ConstraintDistanceVertical::ID().c_str();
   }
   return aConstraintIds;
 }
 
-void PartSet_SketcherMgr::sketchSelectionModes(QIntList& theModes)
+void PartSet_SketcherMgr::sketchSelectionModes(const CompositeFeaturePtr& theSketch,
+                                               QIntList& theModes)
 {
-  theModes.clear();
+  if (!theSketch.get() || !PartSet_Tools::sketchPlane(theSketch).get())
+    return;
 
   theModes.append(SketcherPrs_Tools::Sel_Dimension_Text);
   theModes.append(SketcherPrs_Tools::Sel_Dimension_Line);
@@ -912,7 +977,10 @@ bool PartSet_SketcherMgr::isDistanceKind(std::string& theKind)
   return (theKind == SketchPlugin_ConstraintLength::ID()) ||
          (theKind == SketchPlugin_ConstraintDistance::ID()) ||
          (theKind == SketchPlugin_ConstraintRadius::ID()) ||
-         (theKind == SketchPlugin_ConstraintAngle::ID());
+         (theKind == SketchPlugin_ConstraintAngle::ID()) ||
+         (theKind == SketchPlugin_ConstraintDistanceHorizontal::ID()) ||
+         (theKind == SketchPlugin_ConstraintDistanceVertical::ID()) ||
+         (theKind == SketchPlugin_ConstraintDistanceAlongDir::ID());
 }
 
 void PartSet_SketcherMgr::startSketch(ModuleBase_Operation* theOperation)
@@ -922,10 +990,19 @@ void PartSet_SketcherMgr::startSketch(ModuleBase_Operation* theOperation)
   if (!aFOperation)
     return;
 
+  SketcherPrs_Tools::setPixelRatio(ModuleBase_Tools::currentPixelRatio());
+
   myModule->onViewTransformed();
 
   // Display all sketcher sub-Objects
   myCurrentSketch = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aFOperation->feature());
+  double aSizeOfView = 0;
+  std::shared_ptr<GeomAPI_Pnt> aCentralPoint;
+  if (aFOperation->isEditOperation() &&
+      mySketchPlane->getDefaultSizeOfView(myCurrentSketch, aSizeOfView, aCentralPoint)) {
+    mySketchPlane->setSizeOfView(aSizeOfView, true, aCentralPoint);
+  }
+
   mySketchPlane->createSketchPlane(myCurrentSketch, myModule->workshop());
   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
 
@@ -940,7 +1017,8 @@ void PartSet_SketcherMgr::startSketch(ModuleBase_Operation* theOperation)
   // Remove invalid sketch entities
   std::set<FeaturePtr> anInvalidFeatures;
   ModelAPI_ValidatorsFactory* aFactory = ModelAPI_Session::get()->validators();
-  for (int i = 0; i < myCurrentSketch->numberOfSubs(); i++) {
+  int aNumberOfSubs = myCurrentSketch->numberOfSubs();
+  for (int i = 0; i < aNumberOfSubs; i++) {
     FeaturePtr aFeature = myCurrentSketch->subFeature(i);
     if (aFeature.get()) {
       if (!aFactory->validate(aFeature))
@@ -981,7 +1059,8 @@ void PartSet_SketcherMgr::startSketch(ModuleBase_Operation* theOperation)
   QStringList anInfo;
   Events_ID EVENT_DISP = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
   const ModelAPI_EventCreator* aECreator = ModelAPI_EventCreator::get();
-  for (int i = 0; i < myCurrentSketch->numberOfSubs(); i++) {
+  aNumberOfSubs = myCurrentSketch->numberOfSubs();
+  for (int i = 0; i < aNumberOfSubs; i++) {
     FeaturePtr aFeature = myCurrentSketch->subFeature(i);
 #ifdef DEBUG_SKETCHER_ENTITIES
     anInfo.append(ModuleBase_Tools::objectInfo(aFeature));
@@ -1005,32 +1084,35 @@ void PartSet_SketcherMgr::startSketch(ModuleBase_Operation* theOperation)
   qDebug(QString("startSketch: %1, %2").arg(anInfo.size()).arg(anInfoStr).toStdString().c_str());
 #endif
 
-  if(myCirclePointFilter.IsNull()) {
-    myCirclePointFilter = new PartSet_CirclePointFilter(myModule->workshop());
-  }
-
-  myModule->workshop()->viewer()->addSelectionFilter(myCirclePointFilter);
-
-  if (myPlaneFilter.IsNull())
-    myPlaneFilter = new ModuleBase_ShapeInPlaneFilter();
-
-  myModule->workshop()->viewer()->addSelectionFilter(myPlaneFilter);
   bool aHasPlane = false;
   std::shared_ptr<GeomAPI_Pln> aPln;
   aPln = PartSet_Tools::sketchPlane(myCurrentSketch);
-  myPlaneFilter->setPlane(aPln);
+  Handle(SelectMgr_Filter) aFilter = myModule->selectionFilter(SF_SketchPlaneFilter);
+  if (!aFilter.IsNull())
+    Handle(ModuleBase_ShapeInPlaneFilter)::DownCast(aFilter)->setPlane(aPln);
+
+  workshop()->selectionActivate()->updateSelectionFilters();
+  workshop()->selectionActivate()->updateSelectionModes();
 
   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
-  // all displayed objects should be activated in current selection modes according to switched
-  // plane filter
-  if (aPln.get())
-    aConnector->activateModuleSelectionModes();
 
   myExternalPointsMgr = new PartSet_ExternalPointsMgr(myModule->workshop(), myCurrentSketch);
+
+  workshop()->viewer()->set2dMode(true);
+
+  PartSet_Fitter* aFitter = new PartSet_Fitter(myCurrentSketch);
+  XGUI_Workshop* aWorkshop = aConnector->workshop();
+  aWorkshop->viewer()->setFitter(aFitter);
 }
 
 void PartSet_SketcherMgr::stopSketch(ModuleBase_Operation* theOperation)
 {
+  XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
+  XGUI_Workshop* aWorkshop = aConnector->workshop();
+  PartSet_Fitter* aFitter = (PartSet_Fitter*)aWorkshop->viewer()->currentFitter();
+  aWorkshop->viewer()->unsetFitter();
+  delete aFitter;
+
   myIsMouseOverWindow = false;
   myIsConstraintsShown[PartSet_Tools::Geometrical] = true;
   myIsConstraintsShown[PartSet_Tools::Dimensional] = true;
@@ -1040,8 +1122,7 @@ void PartSet_SketcherMgr::stopSketch(ModuleBase_Operation* theOperation)
     delete myExternalPointsMgr;
     myExternalPointsMgr = 0;
   }
-
-  XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
+  onShowPoints(false);
 
   DataPtr aData = myCurrentSketch->data();
   if (!aData->isValid()) {
@@ -1049,9 +1130,6 @@ void PartSet_SketcherMgr::stopSketch(ModuleBase_Operation* theOperation)
     // The sketch was aborted
     myCurrentSketch = CompositeFeaturePtr();
     mySketchPlane->eraseSketchPlane(myModule->workshop());
-    // TODO: move this outside of if-else
-    myModule->workshop()->viewer()->removeSelectionFilter(myCirclePointFilter);
-    myModule->workshop()->viewer()->removeSelectionFilter(myPlaneFilter);
 
     // Erase all sketcher objects
     QObjectPtrList aObjects = aDisplayer->displayedObjects();
@@ -1063,7 +1141,8 @@ void PartSet_SketcherMgr::stopSketch(ModuleBase_Operation* theOperation)
   }
   else {
     // Hide all sketcher sub-Objects
-    for (int i = 0; i < myCurrentSketch->numberOfSubs(); i++) {
+    int aNumberOfSubs = myCurrentSketch->numberOfSubs();
+    for (int i = 0; i < aNumberOfSubs; i++) {
       FeaturePtr aFeature = myCurrentSketch->subFeature(i);
       std::list<ResultPtr> aResults = aFeature->results();
       std::list<ResultPtr>::const_iterator aIt;
@@ -1094,13 +1173,11 @@ void PartSet_SketcherMgr::stopSketch(ModuleBase_Operation* theOperation)
     myCurrentSketch = CompositeFeaturePtr();
     mySketchPlane->eraseSketchPlane(myModule->workshop());
 
-    myModule->workshop()->viewer()->removeSelectionFilter(myCirclePointFilter);
-    myModule->workshop()->viewer()->removeSelectionFilter(myPlaneFilter);
-
     Events_Loop::loop()->flush(aDispEvent);
   }
-  // restore the module selection modes, which were changed on startSketch
-  aConnector->activateModuleSelectionModes();
+  workshop()->selectionActivate()->updateSelectionFilters();
+  workshop()->selectionActivate()->updateSelectionModes();
+  workshop()->viewer()->set2dMode(false);
 }
 
 void PartSet_SketcherMgr::startNestedSketch(ModuleBase_Operation* theOperation)
@@ -1118,7 +1195,6 @@ void PartSet_SketcherMgr::startNestedSketch(ModuleBase_Operation* theOperation)
 
 void PartSet_SketcherMgr::stopNestedSketch(ModuleBase_Operation* theOperation)
 {
-  previewSketchPlane()->updatePlaneSize(activeSketch(), myModule->workshop());
   myIsMouseOverViewProcessed = true;
   operationMgr()->onValidateOperation();
   // when sketch nested operation is stopped the cursor should be restored unconditionally
@@ -1143,6 +1219,8 @@ void PartSet_SketcherMgr::stopNestedSketch(ModuleBase_Operation* theOperation)
   }
   if (isClearSelectionPossible)
     workshop()->selector()->clearSelection();
+  if (myPointsHighlight.size())
+    onShowPoints(true);
 }
 
 void PartSet_SketcherMgr::commitNestedSketch(ModuleBase_Operation* theOperation)
@@ -1161,12 +1239,16 @@ void PartSet_SketcherMgr::commitNestedSketch(ModuleBase_Operation* theOperation)
   }
 }
 
-void PartSet_SketcherMgr::activatePlaneFilter(const bool& toActivate)
+bool PartSet_SketcherMgr::sketchSelectionFilter(const ModuleBase_SelectionFilterType theFilterType)
 {
-  if (toActivate)
-    myModule->workshop()->viewer()->addSelectionFilter(myPlaneFilter);
-  else
-    myModule->workshop()->viewer()->removeSelectionFilter(myPlaneFilter);
+  return mySelectionFilterTypes.find(theFilterType) != mySelectionFilterTypes.end();
+}
+
+void PartSet_SketcherMgr::registerSelectionFilter(
+  const ModuleBase_SelectionFilterType theFilterType, const Handle(SelectMgr_Filter)& theFilter)
+{
+  mySelectionFilterTypes.insert(theFilterType);
+  myModule->registerSelectionFilter(theFilterType, theFilter);
 }
 
 bool PartSet_SketcherMgr::operationActivatedByPreselection()
@@ -1461,7 +1543,7 @@ bool PartSet_SketcherMgr::isObjectOfSketch(const ObjectPtr& theObject) const
   FeaturePtr anObjectFeature = ModelAPI_Feature::feature(theObject);
   if (anObjectFeature.get()) {
     int aSize = myCurrentSketch->numberOfSubs();
-    for (int i = 0; i < myCurrentSketch->numberOfSubs() && !isFoundObject; i++) {
+    for (int i = 0; i < aSize && !isFoundObject; i++) {
       FeaturePtr aCurrentFeature = myCurrentSketch->subFeature(i);
       isFoundObject = myCurrentSketch->subFeature(i) == anObjectFeature;
     }
@@ -1469,12 +1551,13 @@ bool PartSet_SketcherMgr::isObjectOfSketch(const ObjectPtr& theObject) const
   return isFoundObject;
 }
 
-void PartSet_SketcherMgr::onPlaneSelected(const std::shared_ptr<GeomAPI_Pln>& thePln)
+void PartSet_SketcherMgr::onPlaneSelected(const std::shared_ptr<GeomAPI_Pln>& thePlane)
 {
-  if (myPlaneFilter.IsNull())
-   myPlaneFilter = new ModuleBase_ShapeInPlaneFilter();
+  Handle(SelectMgr_Filter) aFilter = myModule->selectionFilter(SF_SketchPlaneFilter);
+  if (!aFilter.IsNull())
+    Handle(ModuleBase_ShapeInPlaneFilter)::DownCast(aFilter)->setPlane(thePlane);
 
-  myPlaneFilter->setPlane(thePln);
+  workshop()->selectionActivate()->updateSelectionModes();
 }
 
 bool PartSet_SketcherMgr::setDistanceValueByPreselection(ModuleBase_Operation* theOperation,
@@ -1881,7 +1964,8 @@ void PartSet_SketcherMgr::updateBySketchParameters(
       if (aPrevState != theState) {
         ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
         XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);
-        for (int i = 0; i < myCurrentSketch->numberOfSubs(); i++) {
+        int aNumberOfSubs = myCurrentSketch->numberOfSubs();
+        for (int i = 0; i < aNumberOfSubs; i++) {
           FeaturePtr aSubFeature = myCurrentSketch->subFeature(i);
           bool aProcessed = false;
           bool aConstraintDisplayed = canDisplayConstraint(aSubFeature, theType, aProcessed);
@@ -1964,3 +2048,88 @@ XGUI_OperationMgr* PartSet_SketcherMgr::operationMgr() const
   return workshop()->operationMgr();
 }
 
+void PartSet_SketcherMgr::onShowPoints(bool toShow)
+{
+  if (!myCurrentSketch.get())
+    return;
+  ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
+  ModuleBase_IViewer* aViewer = aWorkshop->viewer();
+  Handle(AIS_InteractiveContext) aContext = aViewer->AISContext();
+
+  bool aToUpdate = false;
+  if (toShow) {
+    std::list<ResultPtr> aFreePoints = SketcherPrs_Tools::getFreePoints(myCurrentSketch);
+
+    // Delete obsolete presentations
+    std::list<ResultPtr> aDelList;
+    foreach(ResultPtr aObj, myPointsHighlight.keys()) {
+      bool aFound = (std::find(aFreePoints.begin(), aFreePoints.end(), aObj) != aFreePoints.end());
+      if (!aFound)
+        aDelList.push_back(aObj);
+    }
+    foreach(ResultPtr aObj, aDelList) {
+      aContext->Remove(myPointsHighlight[aObj], false);
+      aToUpdate = true;
+      myPointsHighlight.remove(aObj);
+    }
+
+    // Display new objects
+    QList<ResultPtr> aKeysList = myPointsHighlight.keys();
+    std::list<ResultPtr>::const_iterator aIt;
+    for (aIt = aFreePoints.cbegin(); aIt != aFreePoints.cend(); aIt++) {
+      if (!aKeysList.contains(*aIt)) {
+        GeomShapePtr aShapePtr = (*aIt)->shape();
+        TopoDS_Shape aShape = aShapePtr->impl<TopoDS_Shape>();
+        Handle(AIS_Shape) aShapePrs = new AIS_Shape(aShape);
+        aShapePrs->SetColor(Quantity_NOC_BLUE1);
+        aShapePrs->SetZLayer(Graphic3d_ZLayerId_Top);
+        Handle(Prs3d_Drawer) aDrawer = aShapePrs->Attributes();
+        if (aDrawer->HasOwnPointAspect()) {
+          aDrawer->PointAspect()->SetTypeOfMarker(Aspect_TOM_O_STAR);
+          aDrawer->PointAspect()->SetColor(Quantity_NOC_BLUE1);
+          aDrawer->PointAspect()->SetScale(2);
+        }
+        else
+          aDrawer->SetPointAspect(new Prs3d_PointAspect(Aspect_TOM_O_STAR, Quantity_NOC_BLUE1, 2));
+        aContext->Display(aShapePrs, false);
+        aContext->Deactivate(aShapePrs);
+        myPointsHighlight[*aIt] = aShapePrs;
+        aToUpdate = true;
+      }
+    }
+  }
+  else {
+    foreach(Handle(AIS_Shape) aPrs, myPointsHighlight.values()) {
+      aContext->Remove(aPrs, false);
+      aToUpdate = true;
+    }
+    myPointsHighlight.clear();
+  }
+  if (aToUpdate)
+    aViewer->update();
+}
+
+
+void PartSet_Fitter::fitScene(Handle(V3d_View) theView)
+{
+  Bnd_Box aBndBox;
+  int aNumberOfSubs = mySketch->numberOfSubs();
+  for (int i = 0; i < aNumberOfSubs; i++) {
+    FeaturePtr aFeature = mySketch->subFeature(i);
+    std::list<ResultPtr> aResults = aFeature->results();
+    std::list<ResultPtr>::const_iterator aIt;
+    ResultPtr aRes;
+    double aXmin, aYmin, aZmin, aXmax, aYmax, aZmax;
+    for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
+      aRes = (*aIt);
+      if (aRes->isDisplayed()) {
+        GeomShapePtr aShape = aRes->shape();
+        aShape->computeSize(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
+        Bnd_Box aBox;
+        aBox.Update(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
+        aBndBox.Add(aBox);
+      }
+    }
+  }
+  theView->FitAll(aBndBox, 0.01);
+}