Salome HOME
Issue #1652 Add a real widget displaying the length of the line in the panel: correct...
[modules/shaper.git] / src / PartSet / PartSet_Tools.cpp
index f9dfb6c0b4bb4b847906bd3207bafa9586045eb6..6495c3ce9da85724a5727a442234f72e4c889b46 100755 (executable)
 #include <ModelAPI_Document.h>
 #include <ModelAPI_Session.h>
 #include <ModelAPI_ResultConstruction.h>
+#include <ModelAPI_Events.h>
+#include <ModelAPI_Validator.h>
+
+#include <Events_Loop.h>
 
 #include <SketcherPrs_Tools.h>
 
@@ -50,6 +54,7 @@
 
 #include <ModuleBase_IWorkshop.h>
 #include <ModuleBase_ViewerPrs.h>
+#include <ModuleBase_Tools.h>
 
 #include <V3d_View.hxx>
 #include <gp_Pln.hxx>
 #endif
 
 const double PRECISION_TOLERANCE = 0.000001;
+const int AIS_DEFAULT_WIDTH = 2;
+
+int PartSet_Tools::getAISDefaultWidth()
+{
+  return AIS_DEFAULT_WIDTH;
+}
 
 gp_Pnt PartSet_Tools::convertClickToPoint(QPoint thePoint, Handle(V3d_View) theView)
 {
@@ -185,26 +196,6 @@ 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)
 {
@@ -275,8 +266,8 @@ 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();
+  // 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<GeomDataAPI_Point2D> PartSet_Tools::
@@ -308,14 +299,77 @@ void PartSet_Tools::createConstraint(CompositeFeaturePtr theSketch,
 }*/
 
 
+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> aPoint = featurePoint(theMode);
-  std::shared_ptr<GeomDataAPI_Point2D> aFeaturePoint = std::dynamic_pointer_cast<
-      GeomDataAPI_Point2D>(theFeature->data()->attribute(theAttribute));
+  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;
 
@@ -328,25 +382,12 @@ void PartSet_Tools::setConstraints(CompositeFeaturePtr theSketch, FeaturePtr the
   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;
-      }
-    }
+    std::shared_ptr<GeomDataAPI_Point2D> aFPoint = PartSet_Tools::findFirstEqualPoint(aFeature,
+                                                                                aClickedPoint);
     if (aFPoint)
       PartSet_Tools::createConstraint(theSketch, aFPoint, aFeaturePoint);
   }
@@ -356,28 +397,15 @@ std::shared_ptr<GeomAPI_Pln> PartSet_Tools::sketchPlane(CompositeFeaturePtr theS
 {
   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;
 }
 
@@ -485,6 +513,15 @@ ResultPtr PartSet_Tools::createFixedObjectByExternal(const TopoDS_Shape& theShap
         (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();
       }
@@ -515,6 +552,15 @@ ResultPtr PartSet_Tools::createFixedObjectByExternal(const TopoDS_Shape& theShap
         (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 = 
@@ -557,11 +603,11 @@ ResultPtr PartSet_Tools::createFixedObjectByExternal(const TopoDS_Shape& theShap
   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;
@@ -623,15 +669,16 @@ ResultPtr PartSet_Tools::findExternalVertex(CompositeFeaturePtr theSketch, std::
 }
 
 
-bool PartSet_Tools::hasVertexShape(const ModuleBase_ViewerPrs& thePrs, FeaturePtr theSketch,
+bool PartSet_Tools::hasVertexShape(const ModuleBase_ViewerPrsPtr& thePrs, FeaturePtr theSketch,
                                    Handle_V3d_View theView, double& theX, double& theY)
 {
   bool aHasVertex = false;
 
-  const TopoDS_Shape& aShape = thePrs.shape();
-  if (!aShape.IsNull() && aShape.ShapeType() == TopAbs_VERTEX)
+  const GeomShapePtr& aShape = thePrs->shape();
+  if (aShape.get() && !aShape->isNull() && aShape->shapeType() == GeomAPI_Shape::VERTEX)
   {
-    const TopoDS_Vertex& aVertex = TopoDS::Vertex(aShape);
+    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);
@@ -644,52 +691,42 @@ bool PartSet_Tools::hasVertexShape(const ModuleBase_ViewerPrs& thePrs, FeaturePt
 }
 
 GeomShapePtr PartSet_Tools::findShapeBy2DPoint(const AttributePtr& theAttribute,
-                                               ModuleBase_IWorkshop* theWorkshop)
+                                                       ModuleBase_IWorkshop* theWorkshop)
 {
-  // 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;
-                    }
-                  }
-                }
+  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;
               }
             }
           }
@@ -728,10 +765,40 @@ std::shared_ptr<GeomAPI_Pnt2d> PartSet_Tools::getPoint(std::shared_ptr<ModelAPI_
   return std::shared_ptr<GeomAPI_Pnt2d>();
 }
 
+FeaturePtr findFirstCoincidenceByData(const DataPtr& theData, std::shared_ptr<GeomAPI_Pnt2d> thePoint)
+{
+  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 aCoincident;
+}
+
 FeaturePtr PartSet_Tools::findFirstCoincidence(const FeaturePtr& theFeature,
                                                std::shared_ptr<GeomAPI_Pnt2d> thePoint)
 {
   FeaturePtr aCoincident;
+  if (theFeature.get() == NULL)
+    return aCoincident;
 
   const std::set<AttributePtr>& aRefsList = theFeature->data()->refsToMe();
   std::set<AttributePtr>::const_iterator aIt;
@@ -754,30 +821,79 @@ 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;
+      aCoincident = findFirstCoincidenceByData(aResult->data(), thePoint);
+      if (aCoincident.get())
+        break;
+    }
+  }
   return aCoincident;
 }
 
 void PartSet_Tools::findCoincidences(FeaturePtr theStartCoin, QList<FeaturePtr>& theList,
+                                     QList<FeaturePtr>& theCoincidencies,
                                      std::string theAttr)
 {
+  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 = getCoincedencePoint(theStartCoin);
-    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 = getCoincedencePoint(aConstrFeature);
-        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);
+      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());
+              findCoincidences(aConstrFeature, theList, theCoincidencies, 
+                SketchPlugin_ConstraintCoincidence::ENTITY_B());
+            }
+          }
+        }
+      }
+    }
+  } 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);
+
+      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());
+              findCoincidences(aConstrFeature, theList, theCoincidencies, 
+                SketchPlugin_ConstraintCoincidence::ENTITY_B());
+            }
+          }
         }
       }
     }
@@ -828,3 +944,33 @@ 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();
+  for (int i = 0; i < theComposite->numberOfSubs(); 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;
+}