Salome HOME
updated copyright message
[modules/shaper.git] / src / PartSet / PartSet_Tools.cpp
old mode 100755 (executable)
new mode 100644 (file)
index de6b4bd..315abbd
@@ -1,8 +1,21 @@
-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
-
-// File:        PartSet_Tools.cpp
-// Created:     28 Apr 2014
-// Author:      Natalia ERMOLAEVA
+// Copyright (C) 2014-2023  CEA, EDF
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// 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
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
 
 #include <PartSet_Tools.h>
 #include <PartSet_Module.h>
 #include <ModelAPI_ResultConstruction.h>
 #include <ModelAPI_Events.h>
 #include <ModelAPI_Validator.h>
+#include <ModelAPI_Tools.h>
+
+#include <ModuleBase_IViewWindow.h>
 
 #include <ModelGeomAlgo_Point2D.h>
 
 #include <Events_Loop.h>
+#include <Events_InfoMessage.h>
 
 #include <SketcherPrs_Tools.h>
 
 #include <GeomDataAPI_Point.h>
 #include <GeomDataAPI_Dir.h>
 #include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
 #include <GeomAPI_Pln.h>
 #include <GeomAPI_Pnt2d.h>
 #include <GeomAPI_Pnt.h>
 #include <GeomAPI_Edge.h>
 #include <GeomAPI_Vertex.h>
+#include <GeomAPI_ShapeExplorer.h>
 
 #include <GeomAPI_Dir.h>
 #include <GeomAPI_XYZ.h>
@@ -53,6 +72,8 @@
 #include <SketchPlugin_Arc.h>
 #include <SketchPlugin_Line.h>
 #include <SketchPlugin_Point.h>
+#include <SketchPlugin_Projection.h>
+#include <SketchPlugin_IntersectionPoint.h>
 
 #include <ModuleBase_IWorkshop.h>
 #include <ModuleBase_ViewerPrs.h>
 #include <StdSelect_BRepOwner.hxx>
 #include <SelectMgr_IndexedMapOfOwner.hxx>
 
+#include <QMouseEvent>
+
 #ifdef _DEBUG
 #include <QDebug>
 #endif
 
 const double PRECISION_TOLERANCE = 0.000001;
 const int AIS_DEFAULT_WIDTH = 2;
+const bool SKETCH_PROJECTION_INCLUDE_INTO_RESULT = false; // by default, it is not presented
 
 int PartSet_Tools::getAISDefaultWidth()
 {
@@ -90,15 +114,14 @@ gp_Pnt PartSet_Tools::convertClickToPoint(QPoint thePoint, Handle(V3d_View) theV
   if (theView.IsNull())
     return gp_Pnt();
 
-  V3d_Coordinate XEye, YEye, ZEye, XAt, YAt, ZAt;
-  theView->Eye(XEye, YEye, ZEye);
-
+  Standard_Real XAt, YAt, ZAt;
   theView->At(XAt, YAt, ZAt);
-  gp_Pnt EyePoint(XEye, YEye, ZEye);
   gp_Pnt AtPoint(XAt, YAt, ZAt);
 
-  gp_Vec EyeVector(EyePoint, AtPoint);
-  gp_Dir EyeDir(EyeVector);
+  double aX, aY, aZ;
+  theView->Proj(aX, aY, aZ);
+  gp_Dir EyeDir(aX, aY, aZ);
+  EyeDir.Reverse();
 
   gp_Pln PlaneOfTheView = gp_Pln(AtPoint, EyeDir);
   Standard_Real X, Y, Z;
@@ -106,9 +129,8 @@ gp_Pnt PartSet_Tools::convertClickToPoint(QPoint thePoint, Handle(V3d_View) theV
   gp_Pnt ConvertedPoint(X, Y, Z);
 
   gp_Pnt2d ConvertedPointOnPlane = ProjLib::Project(PlaneOfTheView, ConvertedPoint);
-  gp_Pnt ResultPoint = ElSLib::Value(ConvertedPointOnPlane.X(), ConvertedPointOnPlane.Y(),
+  return ElSLib::Value(ConvertedPointOnPlane.X(), ConvertedPointOnPlane.Y(),
                                      PlaneOfTheView);
-  return ResultPoint;
 }
 
 void PartSet_Tools::convertTo2D(const gp_Pnt& thePoint, FeaturePtr theSketch,
@@ -134,25 +156,27 @@ Handle(V3d_View) theView,
   gp_Vec aVec(anOriginPnt, thePoint);
 
   if (!theView.IsNull()) {
-    V3d_Coordinate XEye, YEye, ZEye, XAt, YAt, ZAt;
+    Standard_Real XEye, YEye, ZEye, XAt, YAt, ZAt;
     theView->Eye(XEye, YEye, ZEye);
 
     theView->At(XAt, YAt, ZAt);
     gp_Pnt EyePoint(XEye, YEye, ZEye);
     gp_Pnt AtPoint(XAt, YAt, ZAt);
 
-    gp_Vec anEyeVec(EyePoint, AtPoint);
-    anEyeVec.Normalize();
+    if (EyePoint.Distance(AtPoint) > gp::Resolution()) {
+      gp_Vec anEyeVec(EyePoint, AtPoint);
+      anEyeVec.Normalize();
 
-    std::shared_ptr<GeomDataAPI_Dir> aNormal = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
-        aData->attribute(SketchPlugin_Sketch::NORM_ID()));
-    gp_Vec aNormalVec(aNormal->x(), aNormal->y(), aNormal->z());
+      std::shared_ptr<GeomDataAPI_Dir> aNormal = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
+         aData->attribute(SketchPlugin_Sketch::NORM_ID()));
+      gp_Vec aNormalVec(aNormal->x(), aNormal->y(), aNormal->z());
 
-    double aDen = anEyeVec * aNormalVec;
-    double aLVec = aDen != 0 ? aVec * aNormalVec / aDen : DBL_MAX;
+      double aDen = anEyeVec * aNormalVec;
+      double aLVec = aDen != 0 ? aVec * aNormalVec / aDen : DBL_MAX;
 
-    gp_Vec aDeltaVec = anEyeVec * aLVec;
-    aVec = aVec - aDeltaVec;
+      gp_Vec aDeltaVec = anEyeVec * aLVec;
+      aVec = aVec - aDeltaVec;
+    }
   }
   theX = aVec.X() * aX->x() + aVec.Y() * aX->y() + aVec.Z() * aX->z();
   theY = aVec.X() * anY->x() + aVec.Y() * anY->y() + aVec.Z() * anY->z();
@@ -273,130 +297,6 @@ void PartSet_Tools::createConstraint(CompositeFeaturePtr theSketch,
   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_CREATED));
 }
 
-/*std::shared_ptr<GeomDataAPI_Point2D> PartSet_Tools::
-  findAttributePoint(CompositeFeaturePtr theSketch, double theX, double theY,
-  double theTolerance, const QList<FeaturePtr>& theIgnore)
-{
-  std::shared_ptr<GeomAPI_Pnt2d> aClickedPoint = std::shared_ptr<GeomAPI_Pnt2d>(
-      new GeomAPI_Pnt2d(theX, theY));
-
-  std::list<std::shared_ptr<ModelAPI_Attribute> > anAttiributes;
-  for (int i = 0; i < theSketch->numberOfSubs(); i++) {
-    FeaturePtr aFeature = theSketch->subFeature(i);
-    if (!theIgnore.contains(aFeature)) {
-      anAttiributes = aFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
-
-      std::list<std::shared_ptr<ModelAPI_Attribute> >::const_iterator anIt;
-      for (anIt = anAttiributes.cbegin(); anIt != anAttiributes.cend(); ++anIt) {
-        std::shared_ptr<GeomDataAPI_Point2D> aCurPoint = 
-          std::dynamic_pointer_cast<GeomDataAPI_Point2D>(*anIt);
-        double x = aCurPoint->x();
-        double y = aCurPoint->y();
-        if (aCurPoint && (aCurPoint->pnt()->distance(aClickedPoint) < theTolerance)) {
-          return aCurPoint;
-        }
-      }
-    }
-  }
-  return std::shared_ptr<GeomDataAPI_Point2D>();
-}*/
-
-
-std::shared_ptr<GeomDataAPI_Point2D> PartSet_Tools::findFirstEqualPointInArgumentFeatures(
-                  const FeaturePtr& theFeature, const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
-{
-  std::shared_ptr<GeomDataAPI_Point2D> aFeaturePoint;
-
-  // may be feature is not updated yet, execute is not performed and references features
-  // are not created. Case: rectangle macro feature
-  ModuleBase_Tools::flushUpdated(theFeature);
-
-  std::list<AttributePtr> anAttributes = theFeature->data()->attributes(
-                                          ModelAPI_AttributeRefList::typeId());
-  std::list<AttributePtr>::const_iterator anIt = anAttributes.begin(), aLast = anAttributes.end();
-  for (; anIt != aLast && !aFeaturePoint.get(); anIt++) {
-    std::shared_ptr<ModelAPI_AttributeRefList> aCurSelList =
-                                      std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anIt);
-    for (int i = 0, aNb = aCurSelList->size(); i < aNb && !aFeaturePoint.get(); i++) {
-      ObjectPtr anObject = aCurSelList->object(i);
-      FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anObject);
-      if (aFeature.get())
-        aFeaturePoint = PartSet_Tools::findFirstEqualPoint(aFeature, thePoint);
-    }
-  }
-  return aFeaturePoint;
-}
-
-std::shared_ptr<GeomDataAPI_Point2D> PartSet_Tools::findFirstEqualPoint(
-                                              const FeaturePtr& theFeature,
-                                              const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
-{
-  std::shared_ptr<GeomDataAPI_Point2D> aFPoint;
-
-  // find the given point in the feature attributes
-  std::list<std::shared_ptr<ModelAPI_Attribute> > anAttiributes =
-                                    theFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
-  std::list<std::shared_ptr<ModelAPI_Attribute> >::const_iterator anIt = anAttiributes.begin(),
-      aLast = anAttiributes.end();
-  ModelAPI_ValidatorsFactory* aValidators = ModelAPI_Session::get()->validators();
-
-  for (; anIt != aLast && !aFPoint; anIt++) {
-    std::shared_ptr<GeomDataAPI_Point2D> aCurPoint =
-                                             std::dynamic_pointer_cast<GeomDataAPI_Point2D>(*anIt);
-    if (aCurPoint && aCurPoint->isInitialized() &&
-        aValidators->isCase(theFeature, aCurPoint->id()) &&
-        (aCurPoint->pnt()->distance(thePoint) < Precision::Confusion())) {
-      aFPoint = aCurPoint;
-      break;
-    }
-  }
-  return aFPoint;
-}
-
-void PartSet_Tools::setConstraints(CompositeFeaturePtr theSketch, FeaturePtr theFeature,
-                                   const std::string& theAttribute, double theClickedX,
-                                   double theClickedY)
-{
-  if (!theFeature.get())
-    return;
-
-  std::shared_ptr<GeomAPI_Pnt2d> aClickedPoint = std::shared_ptr<GeomAPI_Pnt2d>(
-      new GeomAPI_Pnt2d(theClickedX, theClickedY));
-
-  // find a feature point by the selection mode
-  std::shared_ptr<GeomDataAPI_Point2D> aFeaturePoint;
-  if (theFeature->isMacro()) {
-    // the macro feature will be removed after the operation is stopped, so we need to build
-    // coicidence to possible sub-features
-    aFeaturePoint = PartSet_Tools::findFirstEqualPointInArgumentFeatures(theFeature, aClickedPoint);
-  }
-  else {
-    aFeaturePoint = std::dynamic_pointer_cast<
-        GeomDataAPI_Point2D>(theFeature->data()->attribute(theAttribute));
-  }
-  if (!aFeaturePoint)
-    return;
-
-  // get all sketch features. If the point with the given coordinates belong to any sketch feature,
-  // the constraint is created between the feature point and the found sketch point
-  std::shared_ptr<ModelAPI_Data> aData = theSketch->data();
-  std::shared_ptr<ModelAPI_AttributeRefList> aRefList = std::dynamic_pointer_cast<
-      ModelAPI_AttributeRefList>(aData->attribute(SketchPlugin_Sketch::FEATURES_ID()));
-
-  std::list<ObjectPtr> aFeatures = aRefList->list();
-  std::list<ObjectPtr>::const_iterator anIt = aFeatures.begin(), aLast = aFeatures.end();
-  std::list<std::shared_ptr<ModelAPI_Attribute> > anAttiributes;
-  for (; anIt != aLast; anIt++) {
-    FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*anIt);
-    if (!aFeature.get() || (theFeature == aFeature) || (aFeaturePoint->owner() == aFeature))
-      continue;
-    std::shared_ptr<GeomDataAPI_Point2D> aFPoint = PartSet_Tools::findFirstEqualPoint(aFeature,
-                                                                                aClickedPoint);
-    if (aFPoint)
-      PartSet_Tools::createConstraint(theSketch, aFPoint, aFeaturePoint);
-  }
-}
-
 std::shared_ptr<GeomAPI_Pln> PartSet_Tools::sketchPlane(CompositeFeaturePtr theSketch)
 {
   std::shared_ptr<GeomAPI_Pln> aPlane;
@@ -413,6 +313,17 @@ std::shared_ptr<GeomAPI_Pln> PartSet_Tools::sketchPlane(CompositeFeaturePtr theS
   return aPlane;
 }
 
+void PartSet_Tools::nullifySketchPlane(CompositeFeaturePtr theSketch)
+{
+  std::shared_ptr<GeomDataAPI_Point> anOrigin = std::dynamic_pointer_cast<GeomDataAPI_Point>(
+    theSketch->data()->attribute(SketchPlugin_Sketch::ORIGIN_ID()));
+  std::shared_ptr<GeomDataAPI_Dir> aNormal = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
+    theSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
+
+  aNormal->reset();
+  anOrigin->reset();
+}
+
 std::shared_ptr<GeomAPI_Pnt> PartSet_Tools::point3D(std::shared_ptr<GeomAPI_Pnt2d> thePoint2D,
                                                       CompositeFeaturePtr theSketch)
 {
@@ -436,276 +347,72 @@ ResultPtr PartSet_Tools::findFixedObjectByExternal(const TopoDS_Shape& theShape,
                                                    const ObjectPtr& theObject,
                                                    CompositeFeaturePtr theSketch)
 {
-  ResultPtr aResult;
-  if (theShape.ShapeType() == TopAbs_EDGE) {
-    // Check that we already have such external edge
-    std::shared_ptr<GeomAPI_Edge> aInEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge());
-    aInEdge->setImpl(new TopoDS_Shape(theShape));
-    aResult = findExternalEdge(theSketch, aInEdge);
-  }
-  if (theShape.ShapeType() == TopAbs_VERTEX) {
-    std::shared_ptr<GeomAPI_Vertex> aInVert = std::shared_ptr<GeomAPI_Vertex>(new GeomAPI_Vertex());
-    aInVert->setImpl(new TopoDS_Shape(theShape));
-    aResult = findExternalVertex(theSketch, aInVert);
-  }
-  return aResult;
-}
-
-ResultPtr PartSet_Tools::createFixedObjectByExternal(const TopoDS_Shape& theShape,
-                                                     const ObjectPtr& theObject,
-                                                     CompositeFeaturePtr theSketch,
-                                                     const bool theTemporary)
-{
-  if (theShape.ShapeType() == TopAbs_EDGE) {
-    Standard_Real aStart, aEnd;
-    Handle(V3d_View) aNullView;
-    FeaturePtr aMyFeature;
-
-    Handle(Geom_Curve) aCurve = BRep_Tool::Curve(TopoDS::Edge(theShape), aStart, aEnd);
-    GeomAdaptor_Curve aAdaptor(aCurve);
-    std::shared_ptr<GeomAPI_Edge> anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge);
-    anEdge->setImpl(new TopoDS_Shape(theShape));
-    if (aAdaptor.GetType() == GeomAbs_Line) {
-      // Create line
-      aMyFeature = theSketch->addFeature(SketchPlugin_Line::ID());
-      if (!theObject.get()) {
-        // There is no selected result
-        std::shared_ptr<GeomAPI_Pnt> aPnt1 = anEdge->firstPoint();
-        std::shared_ptr<GeomAPI_Pnt> aPnt2 = anEdge->lastPoint();
-        std::shared_ptr<GeomAPI_Pnt2d> aPnt2d1 = convertTo2D(theSketch, aPnt1);
-        std::shared_ptr<GeomAPI_Pnt2d> aPnt2d2 = convertTo2D(theSketch, aPnt2);
-
-        std::shared_ptr<ModelAPI_Data> aData = aMyFeature->data();
-        std::shared_ptr<GeomDataAPI_Point2D> aPoint1 =
-          std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-          aData->attribute(SketchPlugin_Line::START_ID()));
-        std::shared_ptr<GeomDataAPI_Point2D> aPoint2 =
-          std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-          aData->attribute(SketchPlugin_Line::END_ID()));
-
-        aPoint1->setValue(aPnt2d1);
-        aPoint2->setValue(aPnt2d2);
-
-        // If this is an axis then its name has to be changed correspondently
-        std::string aSuffix = "";
-        bool aXdir = fabs(aPnt1->x() - aPnt2->x()) > Precision::Confusion();
-        bool aYdir = fabs(aPnt1->y() - aPnt2->y()) > Precision::Confusion();
-        bool aZdir = fabs(aPnt1->z() - aPnt2->z()) > Precision::Confusion();
-        if (aXdir && (!aYdir) && (!aZdir))
-          aSuffix = "X";
-        else if ((!aXdir) && aYdir && (!aZdir))
-          aSuffix = "Y";
-        else if ((!aXdir) && (!aYdir) && aZdir)
-          aSuffix = "Z";
-        if (aSuffix.length() > 0)
-          aData->setName("Axis_" + aSuffix);
-        aMyFeature->execute();
+  ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
+  if (!aResult.get())
+    return ResultPtr();
 
-      }
-    } else if (aAdaptor.GetType() == GeomAbs_Circle) {
-      if (anEdge->isArc()) {
-        // Create arc
-        aMyFeature = theSketch->addFeature(SketchPlugin_Arc::ID());
-        if (theShape.Orientation() == TopAbs_REVERSED)
-          aMyFeature->boolean(SketchPlugin_Arc::INVERSED_ID())->setValue(true);
-      }
-      else {
-        // Create circle
-        aMyFeature = theSketch->addFeature(SketchPlugin_Circle::ID());
-      }
-    }
-    if (aMyFeature) {
-      DataPtr aData = aMyFeature->data();
-      AttributeSelectionPtr anAttr =
-        std::dynamic_pointer_cast<ModelAPI_AttributeSelection>
-        (aData->attribute(SketchPlugin_SketchEntity::EXTERNAL_ID()));
-
-      ResultPtr aRes = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
-      // selection shape has no result owner => the trihedron axis
-      // TODO: make reference to the real axes when
-      // they are implemented in the initialization plugin
-      if (!aRes.get()) {
-        ObjectPtr aPointObj = ModelAPI_Session::get()->moduleDocument()->objectByName(
-          ModelAPI_ResultConstruction::group(), "Origin");
-        if (aPointObj.get()) { // if initialization plugin performed well
-          aRes = std::dynamic_pointer_cast<ModelAPI_Result>(aPointObj);
-        }
-      }
-      if (!aRes.get()) {
-        aRes = aMyFeature->firstResult();
-      }
-      if (anAttr.get() && aRes.get()) {
-        std::shared_ptr<GeomAPI_Shape> anEdge(new GeomAPI_Shape);
-        anEdge->setImpl(new TopoDS_Shape(theShape));
-
-        anAttr->setValue(aRes, anEdge);
-        //if (!theTemporary) {
-          aMyFeature->execute();
-
-          // fix this edge
-          FeaturePtr aFix = theSketch->addFeature(SketchPlugin_ConstraintRigid::ID());
-          aFix->data()->refattr(SketchPlugin_Constraint::ENTITY_A())->
-            setObject(aMyFeature->lastResult());
-          // we need to flush created signal in order to fixed constraint is processed by solver
-          Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_CREATED));
-        //}
-        return aMyFeature->lastResult();
-      }
-    }
-  }
-  if (theShape.ShapeType() == TopAbs_VERTEX) {
-    FeaturePtr aMyFeature = theSketch->addFeature(SketchPlugin_Point::ID());
-
-    if (aMyFeature) {
-      DataPtr aData = aMyFeature->data();
-      AttributeSelectionPtr anAttr =
-        std::dynamic_pointer_cast<ModelAPI_AttributeSelection>
-        (aData->attribute(SketchPlugin_SketchEntity::EXTERNAL_ID()));
-
-      ResultPtr aRes = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
-      // if there is no object,
-      // it means that this is the origin point: search it in the module document
-      if (!aRes.get()) {
-        ObjectPtr aPointObj = ModelAPI_Session::get()->moduleDocument()->objectByName(
-          ModelAPI_ResultConstruction::group(), "Origin");
-        if (aPointObj.get()) { // if initialization plugin performed well
-          aRes = std::dynamic_pointer_cast<ModelAPI_Result>(aPointObj);
-        }
-      }
-      // reference to itself with name "Origin" (but this may cause the infinitive cycling)
-      if (!aRes.get()) {
-        // If the point is selected not from Result object
-        std::shared_ptr<GeomAPI_Shape> aShape =
-          std::shared_ptr<GeomAPI_Shape>(new GeomAPI_Shape());
-        aShape->setImpl(new TopoDS_Shape(theShape));
-
-        std::shared_ptr<GeomAPI_Vertex> aVertex =
-          std::shared_ptr<GeomAPI_Vertex>(new GeomAPI_Vertex(aShape));
-        std::shared_ptr<GeomAPI_Pnt> aPnt = aVertex->point();
-
-        std::shared_ptr<GeomAPI_Pnt2d> aPnt2d = convertTo2D(theSketch, aPnt);
-        std::shared_ptr<GeomDataAPI_Point2D> aPoint =
-          std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-          aData->attribute(SketchPlugin_Point::COORD_ID()));
-        aPoint->setValue(aPnt2d);
-        if ((aPnt->x() < Precision::Confusion()) &&
-            (aPnt->y() < Precision::Confusion()) &&
-            (aPnt->z() < Precision::Confusion()))
-          aData->setName("Origin");
-
-        aMyFeature->execute();
-        aRes = aMyFeature->firstResult();
-      }
-      if (anAttr.get() && aRes.get()) {
-        std::shared_ptr<GeomAPI_Shape> aVert(new GeomAPI_Shape);
-        aVert->setImpl(new TopoDS_Shape(theShape));
-
-        anAttr->setValue(aRes, aVert);
-        //if (theTemporary) {
-          aMyFeature->execute();
-
-          // fix this edge
-          FeaturePtr aFix = theSketch->addFeature(SketchPlugin_ConstraintRigid::ID());
-          aFix->data()->refattr(SketchPlugin_Constraint::ENTITY_A())->
-            setObject(aMyFeature->lastResult());
-          // we need to flush created signal in order to fixed constraint is processed by solver
-          Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_CREATED));
-        //}
-        return aMyFeature->lastResult();
-      }
-    }
+  for (int i = 0, aNbSubs = theSketch->numberOfSubs(); i < aNbSubs; i++) {
+    FeaturePtr aFeature = theSketch->subFeature(i);
+    if (aFeature->getKind() != SketchPlugin_Projection::PROJECTED_FEATURE_ID())
+      continue;
+    if (aFeature->lastResult() == aResult)
+      return aResult;
   }
   return ResultPtr();
 }
 
-bool PartSet_Tools::isContainPresentation(const QList<ModuleBase_ViewerPrsPtr>& theSelected,
-                                          const ModuleBase_ViewerPrsPtr& thePrs)
+ResultPtr PartSet_Tools::createFixedObjectByExternal(
+                                   const std::shared_ptr<GeomAPI_Shape>& theShape,
+                                   const ObjectPtr& theObject,
+                                   CompositeFeaturePtr theSketch,
+                                   const bool theTemporary,
+                                   FeaturePtr& theCreatedFeature)
 {
-  foreach (ModuleBase_ViewerPrsPtr aPrs, theSelected) {
-    if (aPrs->object() == thePrs->object())
-      return true;
-  }
-  return false;
-}
+  ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
+  if (!aResult.get())
+    return ResultPtr();
 
-ResultPtr PartSet_Tools::findExternalEdge(CompositeFeaturePtr theSketch,
-                                          std::shared_ptr<GeomAPI_Edge> theEdge)
-{
-  for (int i = 0; i < theSketch->numberOfSubs(); i++) {
-    FeaturePtr aFeature = theSketch->subFeature(i);
-    std::shared_ptr<SketchPlugin_Feature> aSketchFea =
-      std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
-    // not displayed result of feature projection should not be returned as external edge
-    if (aSketchFea && aSketchFea->canBeDisplayed()) {
-      if (aSketchFea->isExternal()) {
-        std::list<ResultPtr> aResults = aSketchFea->results();
-        std::list<ResultPtr>::const_iterator aIt;
-        for (aIt = aResults.cbegin(); aIt != aResults.cend(); ++aIt) {
-          ResultConstructionPtr aRes =
-            std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aIt);
-          if (aRes) {
-            std::shared_ptr<GeomAPI_Shape> aShape = aRes->shape();
-            if (aShape) {
-              if (theEdge->isEqual(aShape))
-                return aRes;
-            }
-          }
-        }
-      }
-    }
-  }
-  return ResultPtr();
-}
+  FeaturePtr aProjectionFeature = theSketch->addFeature(SketchPlugin_Projection::ID());
+  theCreatedFeature = aProjectionFeature;
+  AttributeSelectionPtr anExternalAttr = std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(
+                 aProjectionFeature->attribute(SketchPlugin_Projection::EXTERNAL_FEATURE_ID()));
+  anExternalAttr->setValue(aResult, theShape);
 
+  AttributeBooleanPtr anIntoResult = std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>
+    (aProjectionFeature->data()->attribute(SketchPlugin_Projection::INCLUDE_INTO_RESULT()));
+  anIntoResult->setValue(SKETCH_PROJECTION_INCLUDE_INTO_RESULT);
+  aProjectionFeature->execute();
 
-ResultPtr PartSet_Tools::findExternalVertex(CompositeFeaturePtr theSketch,
-                                            std::shared_ptr<GeomAPI_Vertex> theVert)
-{
-  for (int i = 0; i < theSketch->numberOfSubs(); i++) {
-    FeaturePtr aFeature = theSketch->subFeature(i);
-    std::shared_ptr<SketchPlugin_Feature> aSketchFea =
-      std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
-    if (aSketchFea) {
-      if (aSketchFea->isExternal()) {
-        std::list<ResultPtr> aResults = aSketchFea->results();
-        std::list<ResultPtr>::const_iterator aIt;
-        for (aIt = aResults.cbegin(); aIt != aResults.cend(); ++aIt) {
-          ResultConstructionPtr aRes =
-            std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aIt);
-          if (aRes) {
-            std::shared_ptr<GeomAPI_Shape> aShape = aRes->shape();
-            if (aShape) {
-              if (theVert->isEqual(aShape))
-                return aRes;
-            }
-          }
-        }
-      }
-    }
+  ModelAPI_ValidatorsFactory* aValidators = ModelAPI_Session::get()->validators();
+  bool isValid = aValidators->validate(aProjectionFeature);
+
+  // if projection feature has not been created, exit
+  AttributeRefAttrPtr aRefAttr = aProjectionFeature->data()->refattr(
+    SketchPlugin_Projection::PROJECTED_FEATURE_ID());
+  if (!isValid || !aRefAttr || !aRefAttr->isInitialized())
+  {
+    // remove external feature if the attribute is not filled
+    std::set<FeaturePtr> aFeatures;
+    aFeatures.insert(aProjectionFeature);
+    ModelAPI_Tools::removeFeaturesAndReferences(aFeatures);
+    return ResultPtr();
   }
+
+  FeaturePtr aProjection = ModelAPI_Feature::feature(aRefAttr->object());
+  if (aProjection.get() && aProjection->lastResult().get())
+    return aProjection->lastResult();
+
   return ResultPtr();
 }
 
-
-bool PartSet_Tools::hasVertexShape(const ModuleBase_ViewerPrsPtr& thePrs, FeaturePtr theSketch,
-                                   Handle(V3d_View) theView, double& theX, double& theY)
+bool PartSet_Tools::isContainPresentation(const QList<ModuleBase_ViewerPrsPtr>& theSelected,
+                                          const ModuleBase_ViewerPrsPtr& thePrs)
 {
-  bool aHasVertex = false;
-
-  const GeomShapePtr& aShape = thePrs->shape();
-  if (aShape.get() && !aShape->isNull() && aShape->shapeType() == GeomAPI_Shape::VERTEX)
-  {
-    const TopoDS_Shape& aTDShape = aShape->impl<TopoDS_Shape>();
-    const TopoDS_Vertex& aVertex = TopoDS::Vertex(aTDShape);
-    if (!aVertex.IsNull())
-    {
-      gp_Pnt aPoint = BRep_Tool::Pnt(aVertex);
-      PartSet_Tools::convertTo2D(aPoint, theSketch, theView, theX, theY);
-      aHasVertex = true;
-    }
+  foreach (ModuleBase_ViewerPrsPtr aPrs, theSelected) {
+    if (aPrs->object() == thePrs->object())
+      return true;
   }
-
-  return aHasVertex;
+  return false;
 }
 
 GeomShapePtr PartSet_Tools::findShapeBy2DPoint(const AttributePtr& theAttribute,
@@ -739,9 +446,9 @@ GeomShapePtr PartSet_Tools::findShapeBy2DPoint(const AttributePtr& theAttribute,
               // attribute, returns the shape
               PartSet_Module* aModule = dynamic_cast<PartSet_Module*>(theWorkshop->module());
               PartSet_SketcherMgr* aSketchMgr = aModule->sketchMgr();
-              AttributePtr aPntAttr = PartSet_Tools::findAttributeBy2dPoint(anAttributeFeature,
-                                                        aBRepShape, aSketchMgr->activeSketch());
-              if (aPntAttr.get() != NULL && aPntAttr == theAttribute) {
+              std::pair<AttributePtr, int> aPntAttrIndex = PartSet_Tools::findAttributeBy2dPoint(
+                  anAttributeFeature, aBRepShape, aSketchMgr->activeSketch());
+              if (aPntAttrIndex.first.get() != NULL && aPntAttrIndex.first == theAttribute) {
                 aShape = std::shared_ptr<GeomAPI_Shape>(new GeomAPI_Shape);
                 aShape->setImpl(new TopoDS_Shape(aBRepShape));
                 break;
@@ -767,6 +474,36 @@ std::shared_ptr<GeomAPI_Pnt2d> PartSet_Tools::getPoint(
   return std::shared_ptr<GeomAPI_Pnt2d>();
 }
 
+std::shared_ptr<GeomAPI_Pnt2d> PartSet_Tools::getPnt2d(QMouseEvent* theEvent,
+                                                ModuleBase_IViewWindow* theWindow,
+                                                const FeaturePtr& theSketch)
+{
+  gp_Pnt aPnt = PartSet_Tools::convertClickToPoint(theEvent->pos(), theWindow->v3dView());
+  double aX, anY;
+  Handle(V3d_View) aView = theWindow->v3dView();
+  PartSet_Tools::convertTo2D(aPnt, theSketch, aView, aX, anY);
+
+  return std::shared_ptr<GeomAPI_Pnt2d>(new GeomAPI_Pnt2d(aX, anY));
+}
+
+std::shared_ptr<GeomAPI_Pnt2d> PartSet_Tools::getPnt2d(const Handle(V3d_View)& theView,
+                                                       const TopoDS_Shape& theShape,
+                                                       const FeaturePtr& theSketch)
+{
+  GeomPnt2dPtr aPoint2D;
+  if (!theShape.IsNull() && theShape.ShapeType() == TopAbs_VERTEX) {
+    const TopoDS_Vertex& aVertex = TopoDS::Vertex(theShape);
+    if (!aVertex.IsNull()) {
+      // the case when the point is taken from the existing vertex
+      gp_Pnt aPoint = BRep_Tool::Pnt(aVertex);
+      double aX, aY;
+      PartSet_Tools::convertTo2D(aPoint, theSketch, theView, aX, aY);
+      aPoint2D.reset(new GeomAPI_Pnt2d(aX, aY));
+    }
+  }
+  return aPoint2D;
+}
+
 FeaturePtr findFirstCoincidenceByData(const DataPtr& theData,
                                       std::shared_ptr<GeomAPI_Pnt2d> thePoint)
 {
@@ -808,7 +545,7 @@ FeaturePtr PartSet_Tools::findFirstCoincidence(const FeaturePtr& theFeature,
   for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
     std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
     FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
-    if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
+    if (aConstrFeature && aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
       std::shared_ptr<GeomAPI_Pnt2d> a2dPnt =
         PartSet_Tools::getPoint(aConstrFeature, SketchPlugin_ConstraintCoincidence::ENTITY_A());
       if (a2dPnt.get() && thePoint->isEqual(a2dPnt)) {
@@ -827,9 +564,9 @@ FeaturePtr PartSet_Tools::findFirstCoincidence(const FeaturePtr& theFeature,
   /// Find by result
   if (!aCoincident.get()) {
     std::list<ResultPtr> aResults = theFeature->results();
-    std::list<ResultPtr>::const_iterator aIt;
-    for (aIt = aResults.cbegin(); aIt != aResults.cend(); ++aIt) {
-      ResultPtr aResult = *aIt;
+    std::list<ResultPtr>::const_iterator aResIt;
+    for (aResIt = aResults.cbegin(); aResIt != aResults.cend(); ++aResIt) {
+      ResultPtr aResult = *aResIt;
       aCoincident = findFirstCoincidenceByData(aResult->data(), thePoint);
       if (aCoincident.get())
         break;
@@ -840,7 +577,7 @@ FeaturePtr PartSet_Tools::findFirstCoincidence(const FeaturePtr& theFeature,
 
 void PartSet_Tools::findCoincidences(FeaturePtr theStartCoin, QList<FeaturePtr>& theList,
                                      QList<FeaturePtr>& theCoincidencies,
-                                     std::string theAttr)
+                                     std::string theAttr, QList<bool>& theIsAttributes)
 {
   std::shared_ptr<GeomAPI_Pnt2d> aOrig = getCoincedencePoint(theStartCoin);
   if (aOrig.get() == NULL)
@@ -855,6 +592,7 @@ void PartSet_Tools::findCoincidences(FeaturePtr theStartCoin, QList<FeaturePtr>&
     if (!theList.contains(aFeature)) {
       theList.append(aFeature);
       theCoincidencies.append(theStartCoin);
+      theIsAttributes.append(true); // point attribute on a feature
       const std::set<AttributePtr>& aRefsList = aFeature->data()->refsToMe();
       std::set<AttributePtr>::const_iterator aIt;
       for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
@@ -862,12 +600,12 @@ void PartSet_Tools::findCoincidences(FeaturePtr theStartCoin, QList<FeaturePtr>&
         FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
         if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
           if (!theCoincidencies.contains(aConstrFeature)) {
-            std::shared_ptr<GeomAPI_Pnt2d> aPnt = getCoincedencePoint(aConstrFeature);
-            if (aPnt.get() && aOrig->isEqual(aPnt)) {
+            std::shared_ptr<GeomAPI_Pnt2d> aCoincPnt = getCoincedencePoint(aConstrFeature);
+            if (aCoincPnt.get() && aOrig->isEqual(aCoincPnt)) {
               findCoincidences(aConstrFeature, theList, theCoincidencies,
-                SketchPlugin_ConstraintCoincidence::ENTITY_A());
+                SketchPlugin_ConstraintCoincidence::ENTITY_A(), theIsAttributes);
               findCoincidences(aConstrFeature, theList, theCoincidencies,
-                SketchPlugin_ConstraintCoincidence::ENTITY_B());
+                SketchPlugin_ConstraintCoincidence::ENTITY_B(), theIsAttributes);
             }
           }
         }
@@ -877,10 +615,11 @@ void PartSet_Tools::findCoincidences(FeaturePtr theStartCoin, QList<FeaturePtr>&
     // Find by Results
     ResultConstructionPtr aResult = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aObj);
     if (aResult.get()) {
-      FeaturePtr aFeature = ModelAPI_Feature::feature(aPnt->object());
-      if (!theList.contains(aFeature))
-        theList.append(aFeature);
+      FeaturePtr aFeat = ModelAPI_Feature::feature(aPnt->object());
+      if (!theList.contains(aFeat))
+        theList.append(aFeat);
       theCoincidencies.append(theStartCoin);
+      theIsAttributes.append(false); // point attribute on a feature
 
       const std::set<AttributePtr>& aRefsList = aResult->data()->refsToMe();
       std::set<AttributePtr>::const_iterator aIt;
@@ -889,12 +628,12 @@ void PartSet_Tools::findCoincidences(FeaturePtr theStartCoin, QList<FeaturePtr>&
         FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
         if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
           if (!theCoincidencies.contains(aConstrFeature)) {
-            std::shared_ptr<GeomAPI_Pnt2d> aPnt = getCoincedencePoint(aConstrFeature);
-            if (aPnt.get() && aOrig->isEqual(aPnt)) {
+            std::shared_ptr<GeomAPI_Pnt2d> aCoincPnt = getCoincedencePoint(aConstrFeature);
+            if (aCoincPnt.get() && aOrig->isEqual(aCoincPnt)) {
               findCoincidences(aConstrFeature, theList, theCoincidencies,
-                SketchPlugin_ConstraintCoincidence::ENTITY_A());
+                SketchPlugin_ConstraintCoincidence::ENTITY_A(), theIsAttributes);
               findCoincidences(aConstrFeature, theList, theCoincidencies,
-                SketchPlugin_ConstraintCoincidence::ENTITY_B());
+                SketchPlugin_ConstraintCoincidence::ENTITY_B(), theIsAttributes);
             }
           }
         }
@@ -912,12 +651,44 @@ std::shared_ptr<GeomAPI_Pnt2d> PartSet_Tools::getCoincedencePoint(FeaturePtr the
   return aPnt;
 }
 
-AttributePtr PartSet_Tools::findAttributeBy2dPoint(ObjectPtr theObj,
-                                                   const TopoDS_Shape theShape,
-                                                   FeaturePtr theSketch)
+class PointWrapper
+{
+public:
+  PointWrapper(AttributePtr theAttribute)
+    : myPoint(std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute)),
+      myArray(std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(theAttribute))
+  {}
+
+  int size() const { return myPoint.get() ? 1 : (myArray.get() ? myArray->size() : 0); }
+
+  GeomPointPtr point(int theIndex, FeaturePtr theSketch)
+  {
+    GeomPnt2dPtr aP2d;
+    if (myPoint.get())
+      aP2d = myPoint->pnt();
+    else if (myArray.get())
+      aP2d = myArray->pnt(theIndex);
+
+    GeomPointPtr aP3d;
+    if (aP2d.get())
+      aP3d = PartSet_Tools::convertTo3D(aP2d->x(), aP2d->y(), theSketch);
+    return aP3d;
+  }
+
+  bool isArray() const { return myArray.get(); }
+
+private:
+  AttributePoint2DPtr myPoint;
+  AttributePoint2DArrayPtr myArray;
+};
+
+std::pair<AttributePtr, int> PartSet_Tools::findAttributeBy2dPoint(ObjectPtr theObj,
+                                                                   const TopoDS_Shape theShape,
+                                                                   FeaturePtr theSketch)
 {
 
   AttributePtr anAttribute;
+  int aPointIndex = -1;
   FeaturePtr aFeature = ModelAPI_Feature::feature(theObj);
   if (aFeature) {
     if (theShape.ShapeType() == TopAbs_VERTEX) {
@@ -930,25 +701,32 @@ AttributePtr PartSet_Tools::findAttributeBy2dPoint(ObjectPtr theObj,
         // find the given point in the feature attributes
         std::list<AttributePtr> anAttiributes =
           aFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
+        std::list<AttributePtr> anArrays =
+          aFeature->data()->attributes(GeomDataAPI_Point2DArray::typeId());
+        anAttiributes.insert(anAttiributes.end(), anArrays.begin(), anArrays.end());
+
         std::list<AttributePtr>::const_iterator anIt = anAttiributes.begin(),
                                                 aLast = anAttiributes.end();
+        double aMinDistance = 1.e-6; // searching for point with minimal distance and < 1.e-6
         for (; anIt != aLast && !anAttribute; anIt++) {
-          std::shared_ptr<GeomDataAPI_Point2D> aCurPoint =
-            std::dynamic_pointer_cast<GeomDataAPI_Point2D>(*anIt);
-          if (!aCurPoint->isInitialized())
-            continue;
-
-          std::shared_ptr<GeomAPI_Pnt> aPnt =
-            convertTo3D(aCurPoint->x(), aCurPoint->y(), theSketch);
-          if (aPnt && (aPnt->distance(aValue) < Precision::Confusion())) {
-            anAttribute = aCurPoint;
-            break;
+          PointWrapper aWrapper(*anIt);
+          for (int anIndex = 0, aSize = aWrapper.size(); anIndex < aSize; ++anIndex) {
+            std::shared_ptr<GeomAPI_Pnt> aPnt = aWrapper.point(anIndex, theSketch);
+            if (aPnt) {
+              double aDistance = aPnt->distance(aValue);
+              if (aDistance < aMinDistance) {
+                anAttribute = *anIt;
+                if (aWrapper.isArray())
+                  aPointIndex = anIndex;
+                aMinDistance = aPnt->distance(aValue);
+              }
+            }
           }
         }
       }
     }
   }
-  return anAttribute;
+  return std::pair<AttributePtr, int>(anAttribute, aPointIndex);
 }
 
 void PartSet_Tools::sendSubFeaturesEvent(const CompositeFeaturePtr& theComposite,
@@ -957,8 +735,8 @@ void PartSet_Tools::sendSubFeaturesEvent(const CompositeFeaturePtr& theComposite
   if (!theComposite.get())
     return;
 
-  static Events_Loop* aLoop = Events_Loop::loop();
-  for (int i = 0; i < theComposite->numberOfSubs(); i++) {
+  int aNumberOfSubs = theComposite->numberOfSubs();
+  for (int i = 0; i < aNumberOfSubs; i++) {
     FeaturePtr aSubFeature = theComposite->subFeature(i);
     static const ModelAPI_EventCreator* aECreator = ModelAPI_EventCreator::get();
     aECreator->sendUpdated(aSubFeature, theEventId);
@@ -980,3 +758,163 @@ bool PartSet_Tools::isAuxiliarySketchEntity(const ObjectPtr& theObject)
 
   return isAuxiliaryFeature;
 }
+
+bool PartSet_Tools::isIncludeIntoSketchResult(const ObjectPtr& theObject)
+{
+  // check the feature is neither Projection nor IntersectionPoint feature
+  FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
+  if (aFeature->getKind() == SketchPlugin_Projection::ID() ||
+      aFeature->getKind() == SketchPlugin_IntersectionPoint::ID())
+    return false;
+
+  // go through the references to the feature to check
+  // if it was created by Projection or Intersection
+  const std::set<AttributePtr>& aRefs = theObject->data()->refsToMe();
+  for (std::set<AttributePtr>::const_iterator aRefIt = aRefs.begin();
+       aRefIt != aRefs.end(); ++aRefIt) {
+    AttributePtr anAttr = *aRefIt;
+    std::string anIncludeToResultAttrName;
+    if (anAttr->id() == SketchPlugin_Projection::PROJECTED_FEATURE_ID())
+      anIncludeToResultAttrName = SketchPlugin_Projection::INCLUDE_INTO_RESULT();
+    else if (anAttr->id() == SketchPlugin_IntersectionPoint::INTERSECTION_POINTS_ID())
+      anIncludeToResultAttrName = SketchPlugin_IntersectionPoint::INCLUDE_INTO_RESULT();
+
+    if (!anIncludeToResultAttrName.empty()) {
+      // check "include into result" flag
+      FeaturePtr aParent = ModelAPI_Feature::feature(anAttr->owner());
+      return aParent->boolean(anIncludeToResultAttrName)->value();
+    }
+  }
+  return true;
+}
+
+
+ResultPtr PartSet_Tools::createFixedByExternalCenter(
+    const ObjectPtr& theObject,
+    const std::shared_ptr<GeomAPI_Edge>& theEdge,
+    ModelAPI_AttributeSelection::CenterType theType,
+    const CompositeFeaturePtr& theSketch,
+    bool theTemporary,
+    FeaturePtr& theCreatedFeature)
+{
+  ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
+  if (!aResult.get())
+    return ResultPtr();
+
+  FeaturePtr aProjectionFeature = theSketch->addFeature(SketchPlugin_Projection::ID());
+  theCreatedFeature = aProjectionFeature;
+  AttributeSelectionPtr anExternalAttr = std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(
+                 aProjectionFeature->attribute(SketchPlugin_Projection::EXTERNAL_FEATURE_ID()));
+  anExternalAttr->setValueCenter(aResult, theEdge, theType, theTemporary);
+
+  AttributeBooleanPtr anIntoResult = std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>
+    (aProjectionFeature->data()->attribute(SketchPlugin_Projection::INCLUDE_INTO_RESULT()));
+  anIntoResult->setValue(SKETCH_PROJECTION_INCLUDE_INTO_RESULT);
+  aProjectionFeature->execute();
+
+  // if projection feature has not been created, exit
+  AttributeRefAttrPtr aRefAttr = aProjectionFeature->data()->refattr(
+    SketchPlugin_Projection::PROJECTED_FEATURE_ID());
+  if (!aRefAttr || !aRefAttr->isInitialized())
+    return ResultPtr();
+
+  FeaturePtr aProjection = ModelAPI_Feature::feature(aRefAttr->object());
+  if (aProjection.get() && aProjection->lastResult().get())
+    return aProjection->lastResult();
+
+  return ResultPtr();
+}
+
+void PartSet_Tools::getFirstAndLastIndexInFolder(const ObjectPtr& theFolder,
+  int& theFirst, int& theLast)
+{
+  theFirst = -1;
+  theLast = -1;
+
+  DocumentPtr aDoc = theFolder->document();
+  FolderPtr aFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(theFolder);
+  if (!aFolder.get())
+    return;
+
+  AttributeReferencePtr aFirstFeatAttr =
+    aFolder->data()->reference(ModelAPI_Folder::FIRST_FEATURE_ID());
+  if (!aFirstFeatAttr.get())
+    return;
+  FeaturePtr aFirstFeatureInFolder = ModelAPI_Feature::feature(aFirstFeatAttr->value());
+  if (!aFirstFeatureInFolder.get())
+    return;
+
+  FeaturePtr aLastFeatureInFolder = aFolder->lastVisibleFeature();
+  if (!aLastFeatureInFolder.get())
+    return;
+
+  theFirst = aDoc->index(aFirstFeatureInFolder);
+  theLast = aDoc->index(aLastFeatureInFolder);
+}
+
+
+void PartSet_Tools::getDefaultColor(ObjectPtr theObject, const bool isEmptyColorValid,
+  std::vector<int>& theColor)
+{
+  theColor.clear();
+  // get default color from the preferences manager for the given result
+  std::string aSection, aName, aDefault;
+  theObject->colorConfigInfo(aSection, aName, aDefault);
+  if (!aSection.empty() && !aName.empty()) {
+    theColor = Config_PropManager::color(aSection, aName);
+  }
+  if (!isEmptyColorValid && theColor.empty()) {
+    // all AIS objects, where the color is not set, are in black.
+    // The color should be defined in XML or set in the attribute
+    theColor = Config_PropManager::color("Visualization", "object_default_color");
+    Events_InfoMessage("PartSet_Tools",
+      "A default color is not defined in the preferences for this result type").send();
+  }
+}
+
+double PartSet_Tools::getDefaultDeflection(const ObjectPtr& theObject)
+{
+  double aDeflection = -1;
+  ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
+  if (aResult.get()) {
+    bool isConstruction = false;
+
+    std::string aResultGroup = aResult->groupName();
+    if (aResultGroup == ModelAPI_ResultConstruction::group())
+      isConstruction = true;
+    else if (aResultGroup == ModelAPI_ResultBody::group()) {
+      GeomShapePtr aGeomShape = aResult->shape();
+      if (aGeomShape.get()) {
+        // if the shape could not be exploded on faces, it contains only wires, edges, and vertices
+        // correction of deviation for them should not influence to the application performance
+        GeomAPI_ShapeExplorer anExp(aGeomShape, GeomAPI_Shape::FACE);
+        isConstruction = !anExp.more();
+      }
+    }
+    if (isConstruction)
+      aDeflection = Config_PropManager::real("Visualization", "construction_deflection");
+    else
+      aDeflection = Config_PropManager::real("Visualization", "body_deflection");
+  }
+  return aDeflection;
+}
+
+
+double PartSet_Tools::getDefaultTransparency()
+{
+  return Config_PropManager::integer("Visualization", "shaper_default_transparency") / 100.;
+}
+
+QCursor PartSet_Tools::getOperationCursor()
+{
+  int aId = Config_PropManager::integer(SKETCH_TAB_NAME, "operation_cursor");
+  switch (aId) {
+  case 0:
+    return QCursor(Qt::ArrowCursor);
+  case 1:
+    return QCursor(Qt::CrossCursor);
+  case 2:
+    return QCursor(Qt::PointingHandCursor);
+  }
+  return QCursor();
+}