Salome HOME
Fix for the issue #2909 : Folder becomes empty after "export to GEOM"
[modules/shaper.git] / src / PartSet / PartSet_Tools.cpp
old mode 100755 (executable)
new mode 100644 (file)
index ebd22fd..5779d33
@@ -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-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
+// 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_Document.h>
 #include <ModelAPI_Session.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 <SketcherPrs_Tools.h>
 
 #include <XGUI_ModuleConnector.h>
 #include <XGUI_Displayer.h>
 #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 <ModuleBase_Tools.h>
 
 #include <V3d_View.hxx>
 #include <gp_Pln.hxx>
 #include <AIS_InteractiveObject.hxx>
 #include <StdSelect_BRepOwner.hxx>
 #include <SelectMgr_IndexedMapOfOwner.hxx>
+#include <V3d_Coordinate.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()
+{
+  return AIS_DEFAULT_WIDTH;
+}
 
 gp_Pnt PartSet_Tools::convertClickToPoint(QPoint thePoint, Handle(V3d_View) theView)
 {
@@ -143,7 +180,7 @@ Handle(V3d_View) theView,
   theY = aVec.X() * anY->x() + aVec.Y() * anY->y() + aVec.Z() * anY->z();
 }
 
-std::shared_ptr<GeomAPI_Pnt2d> PartSet_Tools::convertTo2D(FeaturePtr theSketch, 
+std::shared_ptr<GeomAPI_Pnt2d> PartSet_Tools::convertTo2D(FeaturePtr theSketch,
                                                     const std::shared_ptr<GeomAPI_Pnt>& thePnt)
 {
   std::shared_ptr<GeomAPI_Pnt2d> aRes;
@@ -160,7 +197,8 @@ std::shared_ptr<GeomAPI_Pnt2d> PartSet_Tools::convertTo2D(FeaturePtr theSketch,
 }
 
 
-std::shared_ptr<GeomAPI_Pnt> PartSet_Tools::convertTo3D(const double theX, const double theY, FeaturePtr theSketch)
+std::shared_ptr<GeomAPI_Pnt> PartSet_Tools::convertTo3D(const double theX, const double theY,
+                                                        FeaturePtr theSketch)
 {
   std::shared_ptr<ModelAPI_Data> aData = theSketch->data();
 
@@ -172,99 +210,17 @@ std::shared_ptr<GeomAPI_Pnt> PartSet_Tools::convertTo3D(const double theX, const
       aData->attribute(SketchPlugin_Sketch::NORM_ID()));
   std::shared_ptr<GeomAPI_Dir> aY(new GeomAPI_Dir(aNorm->dir()->cross(aX->dir())));
 
-  std::shared_ptr<GeomAPI_Pnt2d> aPnt2d = 
+  std::shared_ptr<GeomAPI_Pnt2d> aPnt2d =
     std::shared_ptr<GeomAPI_Pnt2d>(new GeomAPI_Pnt2d(theX, theY));
 
   return aPnt2d->to3D(aC->pnt(), aX->dir(), aY);
 }
 
-ObjectPtr PartSet_Tools::nearestFeature(QPoint thePoint, Handle_V3d_View theView,
-                                        FeaturePtr theSketch,
-                                        const QList<ModuleBase_ViewerPrs>& theSelected,
-                                        const QList<ModuleBase_ViewerPrs>& theHighlighted)
-{
-  // firstly it finds the feature in the list of highlight
-  ObjectPtr aDeltaObject  = nearestFeature(thePoint, theView, theSketch, theHighlighted);
-  if (!aDeltaObject)
-    // secondly it finds the feature in the list of selected objects
-    aDeltaObject  = nearestFeature(thePoint, theView, theSketch, theSelected);
-
-  return aDeltaObject;
-}
-
-ObjectPtr PartSet_Tools::nearestFeature(QPoint thePoint, Handle_V3d_View theView,
-                                        FeaturePtr theSketch,
-                                        const QList<ModuleBase_ViewerPrs>& thePresentations)
-{
-  ObjectPtr aDeltaObject;
-
-  CompositeFeaturePtr aSketch = 
-      std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theSketch);
-  // 1. find it in the selected list by the selected point
-  if (!aDeltaObject) {
-    double aX, anY;
-    gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(thePoint, theView);
-    PartSet_Tools::convertTo2D(aPoint, theSketch, theView, aX, anY);
-
-    FeaturePtr aFeature;
-    double aMinDelta = -1;
-    ModuleBase_ViewerPrs aPrs;
-    foreach (ModuleBase_ViewerPrs aPrs, thePresentations) {
-      if (!aPrs.object())
-        continue;
-      FeaturePtr aFeature = ModelAPI_Feature::feature(aPrs.object());
-      std::shared_ptr<SketchPlugin_Feature> aSketchFeature = std::dynamic_pointer_cast<
-          SketchPlugin_Feature>(aFeature);
-      if (!aSketchFeature || !aSketch->isSub(aSketchFeature))
-        continue;
-
-      double aDelta = aSketchFeature->distanceToPoint(
-          std::shared_ptr<GeomAPI_Pnt2d>(new GeomAPI_Pnt2d(aX, anY)));
-      if (aMinDelta < 0 || aMinDelta > aDelta) {
-        aMinDelta = aDelta;
-        // TODO aDeltaObject = aPrs.result();
-      }
-    }
-  }
-  // 2. if the object is not found, returns the first selected sketch feature
-  if (!aDeltaObject && thePresentations.size() > 0) {
-    // there can be some highlighted objects, e.g. a result of boolean operation and a sketch point
-    foreach (ModuleBase_ViewerPrs aPrs, thePresentations) {
-      if (!aPrs.object())
-        continue;
-      FeaturePtr aFeature = ModelAPI_Feature::feature(aPrs.object());
-      if (aFeature && aSketch->isSub(aFeature))
-        aDeltaObject = aPrs.object();
-    }
-  }
-  return aDeltaObject;
-}
-
 std::shared_ptr<ModelAPI_Document> PartSet_Tools::document()
 {
   return ModelAPI_Session::get()->moduleDocument();
 }
 
-/*std::shared_ptr<GeomDataAPI_Point2D> PartSet_Tools::getFeaturePoint(FeaturePtr theFeature,
-                                                                      double theX, double theY)
-{
-  std::shared_ptr<GeomAPI_Pnt2d> aClickedPoint = std::shared_ptr<GeomAPI_Pnt2d>(
-                                                                 new GeomAPI_Pnt2d(theX, theY));
-  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();
-  std::shared_ptr<GeomDataAPI_Point2D> aFPoint;
-  for (; anIt != aLast && !aFPoint; anIt++) {
-    std::shared_ptr<GeomDataAPI_Point2D> aCurPoint = std::dynamic_pointer_cast<
-        GeomDataAPI_Point2D>(*anIt);
-    if (aCurPoint && aCurPoint->pnt()->distance(aClickedPoint) < Precision::Confusion())
-      aFPoint = aCurPoint;
-  }
-
-  return aFPoint;
-}*/
-
 void PartSet_Tools::setFeatureValue(FeaturePtr theFeature, double theValue,
                                     const std::string& theAttribute)
 {
@@ -335,109 +291,23 @@ void PartSet_Tools::createConstraint(CompositeFeaturePtr theSketch,
       ModelAPI_AttributeRefAttr>(aData->attribute(SketchPlugin_Constraint::ENTITY_B()));
   aRef2->setAttr(thePoint2);
 
-  if (aFeature)  // TODO: generate an error if feature was not created
-    aFeature->execute();
-}
-
-/*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>();
-}*/
-
-
-void PartSet_Tools::setConstraints(CompositeFeaturePtr theSketch, FeaturePtr theFeature,
-                                   const std::string& theAttribute, double theClickedX,
-                                   double theClickedY)
-{
-  // find a feature point by the selection mode
-  //std::shared_ptr<GeomDataAPI_Point2D> aPoint = featurePoint(theMode);
-  std::shared_ptr<GeomDataAPI_Point2D> 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;
-  std::shared_ptr<GeomAPI_Pnt2d> aClickedPoint = std::shared_ptr<GeomAPI_Pnt2d>(
-      new GeomAPI_Pnt2d(theClickedX, theClickedY));
-  for (; anIt != aLast; anIt++) {
-    FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*anIt);
-    if (!aFeature.get() || theFeature == aFeature)
-      continue;
-    // find the given point in the feature attributes
-    anAttiributes = aFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
-    std::list<std::shared_ptr<ModelAPI_Attribute> >::const_iterator anIt = anAttiributes.begin(),
-        aLast = anAttiributes.end();
-    std::shared_ptr<GeomDataAPI_Point2D> aFPoint;
-    for (; anIt != aLast && !aFPoint; anIt++) {
-      std::shared_ptr<GeomDataAPI_Point2D> aCurPoint = 
-        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(*anIt);
-      if (aCurPoint && (aCurPoint->pnt()->distance(aClickedPoint) < Precision::Confusion())) {
-        aFPoint = aCurPoint;
-        break;
-      }
-    }
-    if (aFPoint)
-      PartSet_Tools::createConstraint(theSketch, aFPoint, aFeaturePoint);
-  }
+  // we need to flush created signal in order to coincidence is processed by solver
+  Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_CREATED));
 }
 
 std::shared_ptr<GeomAPI_Pln> PartSet_Tools::sketchPlane(CompositeFeaturePtr theSketch)
 {
   std::shared_ptr<GeomAPI_Pln> aPlane;
 
-  std::shared_ptr<ModelAPI_Data> aData = theSketch->data();
-  if (aData) {
-    std::shared_ptr<GeomDataAPI_Point> anOrigin = std::dynamic_pointer_cast<GeomDataAPI_Point>(
-        aData->attribute(SketchPlugin_Sketch::ORIGIN_ID()));
-    std::shared_ptr<GeomDataAPI_Dir> aNormal = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
-        aData->attribute(SketchPlugin_Sketch::NORM_ID()));
-    if (aNormal && anOrigin) {
-      double adX = aNormal->x();
-      double adY = aNormal->y();
-      double adZ = aNormal->z();
-
-      if ( (adX != 0) || (adY != 0) || (adZ != 0) ) { // Plane is valid
-        double aX = anOrigin->x();
-        double aY = anOrigin->y();
-        double aZ = anOrigin->z();
-        gp_Pln aPln(gp_Pnt(aX, aY, aZ), gp_Dir(adX, adY, adZ));
-        double aA, aB, aC, aD;
-        aPln.Coefficients(aA, aB, aC, aD);
-        aPlane = std::shared_ptr<GeomAPI_Pln>(new GeomAPI_Pln(aA, aB, aC, aD));
-      }
-    }
-  }
+  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()));
+
+  if (aNormal.get() && aNormal->isInitialized() &&
+      anOrigin.get() && anOrigin->isInitialized())
+    aPlane = std::shared_ptr<GeomAPI_Pln>(new GeomAPI_Pln(anOrigin->pnt(), aNormal->dir()));
+
   return aPlane;
 }
 
@@ -464,302 +334,291 @@ 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);
+  ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
+  if (!aResult.get())
+    return ResultPtr();
+
+  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 aResult;
+  return ResultPtr();
 }
 
-ResultPtr PartSet_Tools::createFixedObjectByExternal(const TopoDS_Shape& theShape, 
-                                                     const ObjectPtr& theObject, 
-                                                     CompositeFeaturePtr theSketch,
-                                                     const bool theTemporary)
+ResultPtr PartSet_Tools::createFixedObjectByExternal(
+                                   const std::shared_ptr<GeomAPI_Shape>& theShape,
+                                   const ObjectPtr& theObject,
+                                   CompositeFeaturePtr theSketch,
+                                   const bool theTemporary,
+                                   FeaturePtr& theCreatedFeature)
 {
-  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);
-    if (aAdaptor.GetType() == GeomAbs_Line) {
-      // Create line
-      aMyFeature = theSketch->addFeature(SketchPlugin_Line::ID());
-    } else if (aAdaptor.GetType() == GeomAbs_Circle) {
-      std::shared_ptr<GeomAPI_Edge> anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge);
-      anEdge->setImpl(new TopoDS_Shape(theShape));
-      if (anEdge->isArc()) {
-        // Create arc
-        aMyFeature = theSketch->addFeature(SketchPlugin_Arc::ID());
-      }
-      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);
-      if (anAttr && aRes) {
-        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());
-        //}
-        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 (anAttr && aRes) {
-        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());
-        //}
-        return aMyFeature->lastResult();
-      }
-    }
+  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->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();
+
+  // if projection feature has not been created, exit
+  AttributeRefAttrPtr aRefAttr = aProjectionFeature->data()->refattr(
+    SketchPlugin_Projection::PROJECTED_FEATURE_ID());
+  if (!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::isContainPresentation(const QList<ModuleBase_ViewerPrs>& theSelected,
-                                          const ModuleBase_ViewerPrs& thePrs)
+bool PartSet_Tools::isContainPresentation(const QList<ModuleBase_ViewerPrsPtr>& theSelected,
+                                          const ModuleBase_ViewerPrsPtr& thePrs)
 {
-  foreach (ModuleBase_ViewerPrs aPrs, theSelected) {
-    if (aPrs.object() == thePrs.object())
+  foreach (ModuleBase_ViewerPrsPtr aPrs, theSelected) {
+    if (aPrs->object() == thePrs->object())
       return true;
   }
   return false;
 }
 
-ResultPtr PartSet_Tools::findExternalEdge(CompositeFeaturePtr theSketch, std::shared_ptr<GeomAPI_Edge> theEdge)
+GeomShapePtr PartSet_Tools::findShapeBy2DPoint(const AttributePtr& theAttribute,
+                                                       ModuleBase_IWorkshop* theWorkshop)
 {
-  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 (theEdge->isEqual(aShape))
-                return aRes;
+  GeomShapePtr aShape;
+  XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(theWorkshop);
+  XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
+
+  // 2. find visualized vertices of the attribute and if the attribute of the vertex is
+  // the same, return it
+  FeaturePtr anAttributeFeature = ModelAPI_Feature::feature(theAttribute->owner());
+  // 2.1 get visualized results of the feature
+  const std::list<ResultPtr>& aResList = anAttributeFeature->results();
+  std::list<ResultPtr>::const_iterator anIt = aResList.begin(), aLast = aResList.end();
+  for (; anIt != aLast; anIt++) {
+    AISObjectPtr aAISObj = aDisplayer->getAISObject(*anIt);
+    if (aAISObj.get() != NULL) {
+      Handle(AIS_InteractiveObject) anAISIO = aAISObj->impl<Handle(AIS_InteractiveObject)>();
+      // 2.2 find selected owners of a visualizedd object
+      SelectMgr_IndexedMapOfOwner aSelectedOwners;
+      aConnector->workshop()->selector()->selection()->entityOwners(anAISIO, aSelectedOwners);
+      for (Standard_Integer i = 1, n = aSelectedOwners.Extent(); i <= n; i++) {
+        Handle(SelectMgr_EntityOwner) anOwner = aSelectedOwners(i);
+        if (!anOwner.IsNull()) {
+          Handle(StdSelect_BRepOwner) aBRepOwner = Handle(StdSelect_BRepOwner)::DownCast(anOwner);
+          if (!aBRepOwner.IsNull() && aBRepOwner->HasShape()) {
+            const TopoDS_Shape& aBRepShape = aBRepOwner->Shape();
+            if (aBRepShape.ShapeType() == TopAbs_VERTEX) {
+              // 2.3 if the owner is vertex and an attribute of the vertex is equal to the initial
+              // 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) {
+                aShape = std::shared_ptr<GeomAPI_Shape>(new GeomAPI_Shape);
+                aShape->setImpl(new TopoDS_Shape(aBRepShape));
+                break;
+              }
             }
           }
         }
       }
     }
   }
-  return ResultPtr();
+  return aShape;
 }
 
-
-ResultPtr PartSet_Tools::findExternalVertex(CompositeFeaturePtr theSketch, std::shared_ptr<GeomAPI_Vertex> theVert)
+std::shared_ptr<GeomAPI_Pnt2d> PartSet_Tools::getPoint(
+                                                  std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                                  const std::string& theAttribute)
 {
-  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;
-            }
-          }
-        }
-      }
-    }
-  }
-  return ResultPtr();
+  std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = ModelGeomAlgo_Point2D::getPointOfRefAttr(
+                                          theFeature.get(), theAttribute, SketchPlugin_Point::ID(),
+                                          SketchPlugin_Point::COORD_ID());
+  if (aPointAttr.get() != NULL)
+    return aPointAttr->pnt();
+  return std::shared_ptr<GeomAPI_Pnt2d>();
 }
 
-
-bool PartSet_Tools::hasVertexShape(const ModuleBase_ViewerPrs& thePrs, FeaturePtr theSketch,
-                                   Handle_V3d_View theView, double& theX, double& theY)
+std::shared_ptr<GeomAPI_Pnt2d> PartSet_Tools::getPnt2d(QMouseEvent* theEvent,
+                                                ModuleBase_IViewWindow* theWindow,
+                                                const FeaturePtr& theSketch)
 {
-  bool aHasVertex = false;
+  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);
 
-  const TopoDS_Shape& aShape = thePrs.shape();
-  if (!aShape.IsNull() && aShape.ShapeType() == TopAbs_VERTEX)
-  {
-    const TopoDS_Vertex& aVertex = TopoDS::Vertex(aShape);
-    if (!aVertex.IsNull())
-    {
-      gp_Pnt aPoint = BRep_Tool::Pnt(aVertex);
-      PartSet_Tools::convertTo2D(aPoint, theSketch, theView, theX, theY);
-      aHasVertex = true;
-    }
-  }
-
-  return aHasVertex;
+  return std::shared_ptr<GeomAPI_Pnt2d>(new GeomAPI_Pnt2d(aX, anY));
 }
 
-GeomShapePtr PartSet_Tools::findShapeBy2DPoint(const AttributePtr& theAttribute,
-                                               ModuleBase_IWorkshop* theWorkshop)
+FeaturePtr findFirstCoincidenceByData(const DataPtr& theData,
+                                      std::shared_ptr<GeomAPI_Pnt2d> thePoint)
 {
-  // 1. find an attribute value in attribute reference attribute value
-  GeomShapePtr aShape;
-  AttributeRefAttrPtr aRefAttr =
-    std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
-  if (aRefAttr) {
-    if (!aRefAttr->isObject()) {
-      AttributePtr theAttribute = aRefAttr->attr();
-      if (theAttribute.get()) {
-        XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(theWorkshop);
-        XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
-
-        // 2. find visualized vertices of the attribute and if the attribute of the vertex is
-        // the same, return it
-        FeaturePtr anAttributeFeature = ModelAPI_Feature::feature(theAttribute->owner());
-        // 2.1 get visualized results of the feature
-        const std::list<ResultPtr>& aResList = anAttributeFeature->results();
-        std::list<ResultPtr>::const_iterator anIt = aResList.begin(), aLast = aResList.end();
-        for (; anIt != aLast; anIt++) {
-          AISObjectPtr aAISObj = aDisplayer->getAISObject(*anIt);
-          if (aAISObj.get() != NULL) {
-            Handle(AIS_InteractiveObject) anAISIO = aAISObj->impl<Handle(AIS_InteractiveObject)>();
-            // 2.2 find selected owners of a visualizedd object
-            SelectMgr_IndexedMapOfOwner aSelectedOwners;
-            aConnector->workshop()->selector()->selection()->entityOwners(anAISIO, aSelectedOwners);
-            for (Standard_Integer i = 1, n = aSelectedOwners.Extent(); i <= n; i++) {
-              Handle(SelectMgr_EntityOwner) anOwner = aSelectedOwners(i);
-              if (!anOwner.IsNull()) {
-                Handle(StdSelect_BRepOwner) aBRepOwner = Handle(StdSelect_BRepOwner)::DownCast(anOwner);
-                if (!aBRepOwner.IsNull() && aBRepOwner->HasShape()) {
-                  const TopoDS_Shape& aBRepShape = aBRepOwner->Shape();
-                  if (aBRepShape.ShapeType() == TopAbs_VERTEX) {
-                    // 2.3 if the owner is vertex and an attribute of the vertex is equal to the initial
-                    // 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) {
-                      aShape = std::shared_ptr<GeomAPI_Shape>(new GeomAPI_Shape);
-                      aShape->setImpl(new TopoDS_Shape(aBRepShape));
-                      break;
-                    }
-                  }
-                }
-              }
-            }
-          }
+  FeaturePtr aCoincident;
+
+  const std::set<AttributePtr>& aRefsList = theData->refsToMe();
+  std::set<AttributePtr>::const_iterator aIt;
+  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()) {
+      std::shared_ptr<GeomAPI_Pnt2d> a2dPnt =
+        PartSet_Tools::getPoint(aConstrFeature, SketchPlugin_ConstraintCoincidence::ENTITY_A());
+      if (a2dPnt.get() && thePoint->isEqual(a2dPnt)) {
+        aCoincident = aConstrFeature;
+        break;
+      } else {
+        a2dPnt = PartSet_Tools::getPoint(aConstrFeature,
+                                          SketchPlugin_ConstraintCoincidence::ENTITY_B());
+        if (a2dPnt.get() && thePoint->isEqual(a2dPnt)) {
+          aCoincident = aConstrFeature;
+          break;
         }
       }
     }
   }
-  return aShape;
+  return aCoincident;
 }
 
-std::shared_ptr<GeomAPI_Pnt2d> PartSet_Tools::getPoint(std::shared_ptr<ModelAPI_Feature>& theFeature,
-                                                       const std::string& theAttribute)
+FeaturePtr PartSet_Tools::findFirstCoincidence(const FeaturePtr& theFeature,
+                                               std::shared_ptr<GeomAPI_Pnt2d> thePoint)
 {
-  std::shared_ptr<GeomDataAPI_Point2D> aPointAttr;
-
-  if (!theFeature->data())
-    return std::shared_ptr<GeomAPI_Pnt2d>();
-
-  FeaturePtr aFeature;
-  std::shared_ptr<ModelAPI_AttributeRefAttr> anAttr = std::dynamic_pointer_cast<
-      ModelAPI_AttributeRefAttr>(theFeature->data()->attribute(theAttribute));
-  if (!anAttr)
-    return std::shared_ptr<GeomAPI_Pnt2d>();
-
-  aFeature = ModelAPI_Feature::feature(anAttr->object());
-
-  if (aFeature && aFeature->getKind() == SketchPlugin_Point::ID())
-    aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-        aFeature->data()->attribute(SketchPlugin_Point::COORD_ID()));
-
-  else if (anAttr->attr()) {
-    aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr->attr());
+  FeaturePtr aCoincident;
+  if (theFeature.get() == NULL)
+    return aCoincident;
+
+  const std::set<AttributePtr>& aRefsList = theFeature->data()->refsToMe();
+  std::set<AttributePtr>::const_iterator aIt;
+  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 && 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)) {
+        aCoincident = aConstrFeature;
+        break;
+      } else {
+        a2dPnt = PartSet_Tools::getPoint(aConstrFeature,
+                                          SketchPlugin_ConstraintCoincidence::ENTITY_B());
+        if (a2dPnt.get() && thePoint->isEqual(a2dPnt)) {
+          aCoincident = aConstrFeature;
+          break;
+        }
+      }
+    }
   }
-  if (aPointAttr.get() != NULL)
-    return aPointAttr->pnt();
-  return std::shared_ptr<GeomAPI_Pnt2d>();
+  /// 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;
+      aCoincident = findFirstCoincidenceByData(aResult->data(), thePoint);
+      if (aCoincident.get())
+        break;
+    }
+  }
+  return aCoincident;
 }
 
 void PartSet_Tools::findCoincidences(FeaturePtr theStartCoin, QList<FeaturePtr>& theList,
-                                     std::string theAttr)
+                                     QList<FeaturePtr>& theCoincidencies,
+                                     std::string theAttr, QList<bool>& theIsAttributes)
 {
+  std::shared_ptr<GeomAPI_Pnt2d> aOrig = getCoincedencePoint(theStartCoin);
+  if (aOrig.get() == NULL)
+    return;
+
   AttributeRefAttrPtr aPnt = theStartCoin->refattr(theAttr);
-  if (!aPnt) return;
-  FeaturePtr aObj = ModelAPI_Feature::feature(aPnt->object());
-  if (!theList.contains(aObj)) {
-    std::shared_ptr<GeomAPI_Pnt2d> aOrig = getPoint(theStartCoin, theAttr);
-    if (aOrig.get() == NULL)
-      return;
-    theList.append(aObj);
-    const std::set<AttributePtr>& aRefsList = aObj->data()->refsToMe();
-    std::set<AttributePtr>::const_iterator aIt;
-    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()) { 
-        std::shared_ptr<GeomAPI_Pnt2d> aPnt = getPoint(aConstrFeature, theAttr);
-        if (aPnt.get() && aOrig->isEqual(aPnt)) {
-          findCoincidences(aConstrFeature, theList, SketchPlugin_ConstraintCoincidence::ENTITY_A());
-          findCoincidences(aConstrFeature, theList, SketchPlugin_ConstraintCoincidence::ENTITY_B());
+  if (!aPnt)
+    return;
+  ObjectPtr aObj = aPnt->object();
+  FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aObj);
+  if (aFeature.get()) {
+    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) {
+        std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
+        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)) {
+              findCoincidences(aConstrFeature, theList, theCoincidencies,
+                SketchPlugin_ConstraintCoincidence::ENTITY_A(), theIsAttributes);
+              findCoincidences(aConstrFeature, theList, theCoincidencies,
+                SketchPlugin_ConstraintCoincidence::ENTITY_B(), theIsAttributes);
+            }
+          }
+        }
+      }
+    }
+  } else {
+    // 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);
+      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;
+      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 (!theCoincidencies.contains(aConstrFeature)) {
+            std::shared_ptr<GeomAPI_Pnt2d> aPnt = getCoincedencePoint(aConstrFeature);
+            if (aPnt.get() && aOrig->isEqual(aPnt)) {
+              findCoincidences(aConstrFeature, theList, theCoincidencies,
+                SketchPlugin_ConstraintCoincidence::ENTITY_A(), theIsAttributes);
+              findCoincidences(aConstrFeature, theList, theCoincidencies,
+                SketchPlugin_ConstraintCoincidence::ENTITY_B(), theIsAttributes);
+            }
+          }
         }
       }
     }
   }
 }
 
-AttributePtr PartSet_Tools::findAttributeBy2dPoint(ObjectPtr theObj, 
-                                                   const TopoDS_Shape theShape, 
+std::shared_ptr<GeomAPI_Pnt2d> PartSet_Tools::getCoincedencePoint(FeaturePtr theStartCoin)
+{
+  std::shared_ptr<GeomAPI_Pnt2d> aPnt = SketcherPrs_Tools::getPoint(theStartCoin.get(),
+                                                        SketchPlugin_Constraint::ENTITY_A());
+  if (aPnt.get() == NULL)
+    aPnt = SketcherPrs_Tools::getPoint(theStartCoin.get(), SketchPlugin_Constraint::ENTITY_B());
+  return aPnt;
+}
+
+AttributePtr PartSet_Tools::findAttributeBy2dPoint(ObjectPtr theObj,
+                                                   const TopoDS_Shape theShape,
                                                    FeaturePtr theSketch)
 {
 
@@ -774,15 +633,18 @@ AttributePtr PartSet_Tools::findAttributeBy2dPoint(ObjectPtr theObj,
             new GeomAPI_Pnt(aPoint.X(), aPoint.Y(), aPoint.Z()));
 
         // find the given point in the feature attributes
-        std::list<AttributePtr> anAttiributes = 
+        std::list<AttributePtr> anAttiributes =
           aFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
-        std::list<AttributePtr>::const_iterator anIt = anAttiributes.begin(), 
+        std::list<AttributePtr>::const_iterator anIt = anAttiributes.begin(),
                                                 aLast = anAttiributes.end();
         for (; anIt != aLast && !anAttribute; anIt++) {
-          std::shared_ptr<GeomDataAPI_Point2D> aCurPoint = 
+          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);
+          std::shared_ptr<GeomAPI_Pnt> aPnt =
+            convertTo3D(aCurPoint->x(), aCurPoint->y(), theSketch);
           if (aPnt && (aPnt->distance(aValue) < Precision::Confusion())) {
             anAttribute = aCurPoint;
             break;
@@ -793,3 +655,127 @@ AttributePtr PartSet_Tools::findAttributeBy2dPoint(ObjectPtr theObj,
   }
   return anAttribute;
 }
+
+void PartSet_Tools::sendSubFeaturesEvent(const CompositeFeaturePtr& theComposite,
+                                         const Events_ID theEventId)
+{
+  if (!theComposite.get())
+    return;
+
+  static Events_Loop* aLoop = Events_Loop::loop();
+  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);
+  }
+  Events_Loop::loop()->flush(theEventId);
+}
+
+bool PartSet_Tools::isAuxiliarySketchEntity(const ObjectPtr& theObject)
+{
+  bool isAuxiliaryFeature = false;
+
+  FeaturePtr anObjectFeature = ModelAPI_Feature::feature(theObject);
+  std::string anAuxiliaryAttribute = SketchPlugin_SketchEntity::AUXILIARY_ID();
+  AttributeBooleanPtr anAuxiliaryAttr = std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(
+                                    anObjectFeature->data()->attribute(anAuxiliaryAttribute));
+  if (anAuxiliaryAttr.get())
+    isAuxiliaryFeature = anAuxiliaryAttr->value();
+
+
+  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);
+}