Salome HOME
#1095 line does not stop on arc end
[modules/shaper.git] / src / SketchSolver / SketchSolver_Group.cpp
index 0a250d8c2d8dfea3340b93b3b473b37432526327..5a9652fe6955ae404f23f248f5d8da9605bf81c3 100644 (file)
@@ -9,6 +9,7 @@
 #include <SketchSolver_Builder.h>
 #include <SketchSolver_Constraint.h>
 #include <SketchSolver_ConstraintCoincidence.h>
+#include <SketchSolver_ConstraintMulti.h>
 #include <SketchSolver_Error.h>
 
 #include <Events_Error.h>
 #include <GeomDataAPI_Point.h>
 #include <GeomDataAPI_Point2D.h>
 #include <ModelAPI_AttributeDouble.h>
-#include <ModelAPI_AttributeRefList.h>
+#include <ModelAPI_AttributeString.h>
 #include <ModelAPI_Document.h>
 #include <ModelAPI_Events.h>
 #include <ModelAPI_ResultConstruction.h>
+#include <ModelAPI_Session.h>
+#include <ModelAPI_Validator.h>
 
 #include <SketchPlugin_Constraint.h>
-#include <SketchPlugin_ConstraintFillet.h>
-#include <SketchPlugin_ConstraintLength.h>
+#include <SketchPlugin_ConstraintAngle.h>
 #include <SketchPlugin_ConstraintCoincidence.h>
+#include <SketchPlugin_ConstraintDistance.h>
+#include <SketchPlugin_ConstraintEqual.h>
+#include <SketchPlugin_ConstraintHorizontal.h>
+#include <SketchPlugin_ConstraintLength.h>
+#include <SketchPlugin_ConstraintFillet.h>
 #include <SketchPlugin_ConstraintMirror.h>
+#include <SketchPlugin_ConstraintParallel.h>
+#include <SketchPlugin_ConstraintPerpendicular.h>
+#include <SketchPlugin_ConstraintRadius.h>
 #include <SketchPlugin_ConstraintRigid.h>
+#include <SketchPlugin_ConstraintTangent.h>
+#include <SketchPlugin_ConstraintVertical.h>
+#include <SketchPlugin_Feature.h>
+#include <SketchPlugin_MultiRotation.h>
+#include <SketchPlugin_MultiTranslation.h>
+#include <SketchPlugin_Sketch.h>
 
 #include <SketchPlugin_Arc.h>
 #include <SketchPlugin_Circle.h>
@@ -60,16 +76,17 @@ private:
   static Slvs_hGroup myGroupIndex; ///< index of the group
 };
 
-Slvs_hGroup GroupIndexer::myGroupIndex = 0;
+Slvs_hGroup GroupIndexer::myGroupIndex = SLVS_G_OUTOFGROUP;
+
+
+static void sendMessage(const char* theMessageName)
+{
+  std::shared_ptr<Events_Message> aMessage = std::shared_ptr<Events_Message>(
+      new Events_Message(Events_Loop::eventByName(theMessageName)));
+  Events_Loop::loop()->send(aMessage);
+}
 
 
-/** \brief Search the entity/parameter with specified ID in the list of elements
- *  \param[in] theEntityID unique ID of the element
- *  \param[in] theEntities list of elements
- *  \return position of the found element or -1 if the element is not found
- */
-template<typename T>
-static int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities);
 
 // ========================================================
 // =========  SketchSolver_Group  ===============
@@ -77,7 +94,8 @@ static int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities
 
 SketchSolver_Group::SketchSolver_Group(
     std::shared_ptr<ModelAPI_CompositeFeature> theWorkplane)
-    : myID(GroupIndexer::NEW_GROUP())
+    : myID(GroupIndexer::NEW_GROUP()),
+      myPrevSolved(true)
 {
   // Initialize workplane
   myWorkplaneID = SLVS_E_UNKNOWN;
@@ -117,7 +135,16 @@ bool SketchSolver_Group::isInteract(
   ConstraintPtr aConstraint = std::dynamic_pointer_cast<SketchPlugin_Constraint>(theFeature);
   if (aConstraint)
     return myFeatureStorage->isInteract(aConstraint);
-  return myFeatureStorage->isInteract(theFeature);
+  return myFeatureStorage->isInteract(std::dynamic_pointer_cast<ModelAPI_Feature>(theFeature));
+}
+
+// check the entity is really exists
+static void checkEntity(StoragePtr theStorage, Slvs_hEntity& theEntity)
+{
+  if (theEntity == SLVS_E_UNKNOWN)
+    return;
+  Slvs_Entity anEnt = theStorage->getEntity(theEntity);
+  theEntity = anEnt.h;
 }
 
 // ============================================================================
@@ -127,15 +154,24 @@ bool SketchSolver_Group::isInteract(
 // ============================================================================
 Slvs_hEntity SketchSolver_Group::getFeatureId(FeaturePtr theFeature) const
 {
+  Slvs_hEntity aResult = SLVS_E_UNKNOWN;
   if (!myFeatureStorage)
-    return SLVS_E_UNKNOWN;
-  std::set<ConstraintPtr> aConstraints = myFeatureStorage->getConstraints(theFeature);
-  if (aConstraints.empty())
-    return SLVS_E_UNKNOWN;
-  ConstraintConstraintMap::const_iterator aCIter = myConstraints.find(*aConstraints.begin());
-  if (aCIter == myConstraints.end())
-    return SLVS_E_UNKNOWN;
-  return aCIter->second->getId(theFeature);
+    return aResult;
+  // Obtain regular constraints interacting with the feature and find its ID
+  ConstraintConstraintMap::const_iterator aCIter = myConstraints.begin();
+  for (; aCIter != myConstraints.end(); ++aCIter) {
+    aResult = aCIter->second->getId(theFeature);
+    checkEntity(myStorage, aResult);
+    if (aResult != SLVS_E_UNKNOWN)
+      return aResult;
+  }
+  // The feature is not found, check it in the temporary constraints
+  std::set<SolverConstraintPtr>::iterator aTmpCIter = myTempConstraints.begin();
+  for (; aTmpCIter != myTempConstraints.end() && aResult == SLVS_E_UNKNOWN; ++aTmpCIter) {
+    aResult = (*aTmpCIter)->getId(theFeature);
+    checkEntity(myStorage, aResult);
+  }
+  return aResult;
 }
 
 // ============================================================================
@@ -145,15 +181,31 @@ Slvs_hEntity SketchSolver_Group::getFeatureId(FeaturePtr theFeature) const
 // ============================================================================
 Slvs_hEntity SketchSolver_Group::getAttributeId(AttributePtr theAttribute) const
 {
+  Slvs_hEntity aResult = SLVS_E_UNKNOWN;
   if (!myFeatureStorage)
-    return SLVS_E_UNKNOWN;
-  std::set<ConstraintPtr> aConstraints = myFeatureStorage->getConstraints(theAttribute);
-  if (aConstraints.empty())
-    return SLVS_E_UNKNOWN;
-  ConstraintConstraintMap::const_iterator aCIter = myConstraints.find(*aConstraints.begin());
-  if (aCIter == myConstraints.end())
-    return SLVS_E_UNKNOWN;
-  return aCIter->second->getId(theAttribute);
+    return aResult;
+  // Obtain regular constraints interacting with the attribute and find its ID
+  ConstraintConstraintMap::const_iterator aCIter = myConstraints.begin();
+  for (; aCIter != myConstraints.end(); ++aCIter) {
+    aResult = aCIter->second->getId(theAttribute);
+    checkEntity(myStorage, aResult);
+    if (aResult != SLVS_E_UNKNOWN)
+      return aResult;
+  }
+  // The attribute is not found, check it in the temporary constraints
+  std::set<SolverConstraintPtr>::const_iterator aTmpCIter = myTempConstraints.begin();
+  for (; aTmpCIter != myTempConstraints.end() && aResult == SLVS_E_UNKNOWN; ++aTmpCIter) {
+    aResult = (*aTmpCIter)->getId(theAttribute);
+    checkEntity(myStorage, aResult);
+  }
+  // Last chance to find attribute in parametric constraints
+  std::map<AttributePtr, SolverConstraintPtr>::const_iterator aParIter =
+      myParametricConstraints.find(theAttribute);
+  if (aParIter != myParametricConstraints.end()) {
+    aResult = aParIter->second->getId(theAttribute);
+    checkEntity(myStorage, aResult);
+  }
+  return aResult;
 }
 
 // ============================================================================
@@ -168,10 +220,14 @@ bool SketchSolver_Group::changeConstraint(
   if (myWorkplaneID == SLVS_E_UNKNOWN)
     return false;
 
-  if (!theConstraint)
+  if (!theConstraint || !theConstraint->data())
+    return false;
+
+  if (!checkFeatureValidity(theConstraint))
     return false;
 
-  if (myConstraints.find(theConstraint) == myConstraints.end()) {
+  bool isNewConstraint = myConstraints.find(theConstraint) == myConstraints.end();
+  if (isNewConstraint) {
     // Add constraint to the current group
     SolverConstraintPtr aConstraint =
         SketchSolver_Builder::getInstance()->createConstraint(theConstraint);
@@ -187,8 +243,9 @@ bool SketchSolver_Group::changeConstraint(
 
     // Additional verification of coincidence of several points
     if (theConstraint->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
+      bool hasMultiCoincidence = false;
       ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
-      for (; aCIter != myConstraints.end(); aCIter++) {
+      for (; aCIter != myConstraints.end(); ++aCIter) {
         std::shared_ptr<SketchSolver_ConstraintCoincidence> aCoincidence =
           std::dynamic_pointer_cast<SketchSolver_ConstraintCoincidence>(aCIter->second);
         if (!aCoincidence)
@@ -196,1092 +253,231 @@ bool SketchSolver_Group::changeConstraint(
         std::shared_ptr<SketchSolver_ConstraintCoincidence> aCoinc2 =
           std::dynamic_pointer_cast<SketchSolver_ConstraintCoincidence>(aConstraint);
         if (aCoincidence != aCoinc2 && aCoincidence->isCoincide(aCoinc2)) {
-          aCoincidence->attach(aCoinc2);
-          aConstraint = aCoincidence;
+          aCoinc2->attach(aCoincidence);
+          // update other coincidences
+          ConstraintConstraintMap::iterator anIt = aCIter;
+          for (++anIt; anIt != myConstraints.end(); ++anIt)
+            if (anIt->second == aCIter->second)
+              anIt->second = aCoinc2;
+          aCIter->second = aCoinc2;
+          hasMultiCoincidence = true;
         }
       }
+
+      if (hasMultiCoincidence)
+        notifyMultiConstraints();
     }
     myConstraints[theConstraint] = aConstraint;
   }
   else
     myConstraints[theConstraint]->update();
 
+  // Fix base features for fillet
+  if (isNewConstraint && theConstraint->getKind() == SketchPlugin_ConstraintFillet::ID()) {
+    std::list<AttributePtr> anAttrList =
+        theConstraint->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
+    std::list<AttributePtr>::iterator anAttrIter = anAttrList.begin();
+    for (; anAttrIter != anAttrList.end(); anAttrIter++) {
+      AttributeRefAttrPtr aRefAttr =
+          std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttrIter);
+      if (!aRefAttr || !aRefAttr->isObject())
+        continue;
+      FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
+      SolverConstraintPtr aConstraint =
+          SketchSolver_Builder::getInstance()->createRigidConstraint(aFeature);
+      if (!aConstraint)
+        continue;
+      aConstraint->setGroup(this);
+      aConstraint->setStorage(myStorage);
+      setTemporary(aConstraint);
+    }
+  }
+  // Fix mirror line
+  if (theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID()) {
+    AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+        theConstraint->attribute(SketchPlugin_ConstraintMirror::ENTITY_A()));
+    if (aRefAttr && aRefAttr->isObject()) {
+      FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
+      if (aFeature) {
+        SolverConstraintPtr aConstraint =
+            SketchSolver_Builder::getInstance()->createRigidConstraint(aFeature);
+        if (aConstraint) {
+          aConstraint->setGroup(this);
+          aConstraint->setStorage(myStorage);
+          setTemporary(aConstraint);
+        }
+      }
+    }
+  }
+
   if (!myFeatureStorage)
     myFeatureStorage = FeatureStoragePtr(new SketchSolver_FeatureStorage);
   myFeatureStorage->changeConstraint(theConstraint);
 
-////  if (theConstraint) {
-////    if (theConstraint->getKind() == SketchPlugin_ConstraintRigid::ID())
-////      return changeRigidConstraint(theConstraint);
-////    if (theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID())
-////      return changeMirrorConstraint(theConstraint);
-////    if (theConstraint->getKind() == SketchPlugin_ConstraintFillet::ID())
-////      return changeFilletConstraint(theConstraint);
-////  }
-////
-////  // Search this constraint in the current group to update it
-////  ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint);
-////  std::vector<Slvs_Constraint>::iterator aConstrIter;
-////  if (aConstrMapIter != myConstraintMap.end()) {
-////    int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints);
-////    aConstrIter = myConstraints.begin() + aConstrPos;
-////  }
-////
-////  // Get constraint type and verify the constraint parameters are correct
-////  SketchSolver_Constraint aConstraint(theConstraint);
-////  int aConstrType = aConstraint.getType();
-////  if (aConstrType == SLVS_C_UNKNOWN
-////      || (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType))
-////    return false;
-////  const std::vector<std::string>& aConstraintAttributes = aConstraint.getAttributes();
-////
-////  // Create constraint parameters
-////  double aDistance = 0.0;  // scalar value of the constraint
-////  AttributeDoublePtr aDistAttr = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
-////      theConstraint->data()->attribute(SketchPlugin_Constraint::VALUE()));
-////  if (aDistAttr) {
-////    aDistance = aDistAttr->value();
-////    // Issue #196: checking the positivity of the distance constraint
-////    if (aDistance < tolerance &&
-////       (aConstrType == SLVS_C_PT_PT_DISTANCE || aConstrType == SLVS_C_PT_LINE_DISTANCE))
-////      return false;
-////    // SketchPlugin circle defined by its radius, but SolveSpace uses constraint for diameter
-////    if (aConstrType == SLVS_C_DIAMETER)
-////      aDistance *= 2.0;
-////    if (aConstrMapIter != myConstraintMap.end()
-////        && fabs(aConstrIter->valA - aDistance) > tolerance) {
-////      myNeedToSolve = true;
-////      aConstrIter->valA = aDistance;
-////    }
-////  }
-////
-////  size_t aNbTmpConstraints = myTempConstraints.size();
-////  Slvs_hEntity aConstrEnt[CONSTRAINT_ATTR_SIZE];  // parameters of the constraint
-////  for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
-////    aConstrEnt[indAttr] = SLVS_E_UNKNOWN;
-////    std::shared_ptr<ModelAPI_AttributeRefAttr> aConstrAttr = std::dynamic_pointer_cast<
-////        ModelAPI_AttributeRefAttr>(
-////        theConstraint->data()->attribute(aConstraintAttributes[indAttr]));
-////    if (!aConstrAttr)
-////      continue;
-////
-////    // Convert the object of the attribute to the feature
-////    FeaturePtr aFeature;
-////    if (aConstrAttr->isObject() && aConstrAttr->object()) {
-////      ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
-////          aConstrAttr->object());
-////      if (!aRC)
-////        continue;
-////      std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
-////      aFeature = aDoc->feature(aRC);
-////    }
-////
-////    // For the length constraint the start and end points of the line should be added to the entities list instead of line
-////    if (aConstrType == SLVS_C_PT_PT_DISTANCE
-////        && theConstraint->getKind().compare(SketchPlugin_ConstraintLength::ID()) == 0) {
-////      Slvs_hEntity aLineEnt = changeEntityFeature(aFeature);
-////      int aEntPos = Search(aLineEnt, myEntities);
-////      aConstrEnt[indAttr++] = myEntities[aEntPos].point[0];
-////      aConstrEnt[indAttr++] = myEntities[aEntPos].point[1];
-////      while (indAttr < CONSTRAINT_ATTR_SIZE)
-////        aConstrEnt[indAttr++] = 0;
-////      break;  // there should be no other entities
-////    } else if (aConstrAttr->isObject())
-////      aConstrEnt[indAttr] = changeEntityFeature(aFeature);
-////    else
-////      aConstrEnt[indAttr] = changeEntity(aConstrAttr->attr());
-////  }
-////
-////  if (aConstrMapIter == myConstraintMap.end()) { // Add new constraint
-////    // Several points may be coincident, it is not necessary to store all constraints between them.
-////    // Try to find sequence of coincident points which connects the points of new constraint
-////    if (aConstrType == SLVS_C_POINTS_COINCIDENT) {
-////      if (aConstrEnt[0] == aConstrEnt[1])  // no need to add self coincidence
-////        return false;
-////      if (!addCoincidentPoints(aConstrEnt[0], aConstrEnt[1])) {
-////        myExtraCoincidence.insert(theConstraint);  // the constraint is stored for further purposes
-////        return false;
-////      }
-////      if (aNbTmpConstraints < myTempConstraints.size()) {
-////        // There was added temporary constraint. Check that there is no coincident points which already rigid.
-////
-////        // Get list of already fixed points
-////        std::set<Slvs_hEntity> anAlreadyFixed;
-////        std::vector<Slvs_Constraint>::const_iterator aCIter = myConstraints.begin();
-////        for (; aCIter != myConstraints.end(); aCIter++)
-////          if (aCIter->type == SLVS_C_WHERE_DRAGGED) {
-////            std::list<Slvs_hConstraint>::const_iterator aTmpIt = myTempConstraints.begin();
-////            for (; aTmpIt != myTempConstraints.end(); aTmpIt++)
-////              if (*aTmpIt == aCIter->h)
-////                break;
-////            if (aTmpIt == myTempConstraints.end())
-////              anAlreadyFixed.insert(aCIter->ptA);
-////          }
-////
-////        std::set<Slvs_hConstraint> aTmpConstrToDelete;
-////        std::list<Slvs_hConstraint>::reverse_iterator aTmpIter = myTempConstraints.rbegin();
-////        size_t aCurSize = myTempConstraints.size();
-////        for (; aCurSize > aNbTmpConstraints && aTmpIter != myTempConstraints.rend();
-////            aTmpIter++, aCurSize--) {
-////          int aConstrPos = Search(*aTmpIter, myConstraints);
-////          std::vector<std::set<Slvs_hEntity> >::const_iterator
-////            aCoincIter = myCoincidentPoints.begin();
-////          for (; aCoincIter != myCoincidentPoints.end(); aCoincIter++)
-////            if (aCoincIter->find(myConstraints[aConstrPos].ptA) != aCoincIter->end()) {
-////              std::set<Slvs_hEntity>::const_iterator anIt;
-////              for (anIt = aCoincIter->begin(); anIt != aCoincIter->end(); anIt++)
-////                if (anAlreadyFixed.find(*anIt) != anAlreadyFixed.end()) {
-////                  aTmpConstrToDelete.insert(*aTmpIter);
-////                  break;
-////                }
-////              break;
-////            }
-////        }
-////        if (!aTmpConstrToDelete.empty())
-////          removeTemporaryConstraints(aTmpConstrToDelete);
-////      }
-////    }
-////    // For the tangency constraints it is necessary to identify which points of entities are coincident
-////    int aSlvsOtherFlag = 0;
-////    int aSlvsOther2Flag = 0;
-////    if (aConstrType == SLVS_C_ARC_LINE_TANGENT || aConstrType == SLVS_C_CURVE_CURVE_TANGENT) {
-////      // Search entities used by constraint
-////      int anEnt1Pos = Search(aConstrEnt[2], myEntities);
-////      int anEnt2Pos = Search(aConstrEnt[3], myEntities);
-////      // Obtain start and end points of entities
-////      Slvs_hEntity aPointsToFind[4];
-////      aPointsToFind[0] = myEntities[anEnt1Pos].point[1];
-////      aPointsToFind[1]= myEntities[anEnt1Pos].point[2];
-////      bool hasLine = (myEntities[anEnt2Pos].type == SLVS_E_LINE_SEGMENT);
-////      aPointsToFind[2]= myEntities[anEnt2Pos].point[hasLine ? 0 : 1];
-////      aPointsToFind[3]= myEntities[anEnt2Pos].point[hasLine ? 1 : 2];
-////      // Search coincident points
-////      bool isPointFound[4];
-////      std::vector<std::set<Slvs_hEntity> >::const_iterator aCPIter = myCoincidentPoints.begin();
-////      for ( ; aCPIter != myCoincidentPoints.end(); aCPIter++) {
-////        for (int i = 0; i < 4; i++)
-////          isPointFound[i] = (aCPIter->find(aPointsToFind[i]) != aCPIter->end());
-////        if ((isPointFound[0] || isPointFound[1]) && (isPointFound[2] || isPointFound[3])) {
-////          // the arc is tangent by end point
-////          if (isPointFound[1]) aSlvsOtherFlag = 1;
-////          // the second item is an arc and it is tangent by end point too
-////          if (!hasLine && isPointFound[3]) aSlvsOther2Flag = 1;
-////          break;
-////        }
-////      }
-////      if (aCPIter == myCoincidentPoints.end()) {
-////        // There is no coincident points between tangential objects. Generate error message
-////        Events_Error::send(SketchSolver_Error::NO_COINCIDENT_POINTS(), this);
-////        return false;
-////      }
-////    }
-////
-////    // Create SolveSpace constraint structure
-////    Slvs_Constraint aSlvsConstr = Slvs_MakeConstraint(++myConstrMaxID, myID, aConstrType,
-////                                                      myWorkplane.h, aDistance, aConstrEnt[0],
-////                                                      aConstrEnt[1], aConstrEnt[2], aConstrEnt[3]);
-////    if (aSlvsOtherFlag != 0) aSlvsConstr.other = aSlvsOtherFlag;
-////    if (aSlvsOther2Flag != 0) aSlvsConstr.other2 = aSlvsOther2Flag;
-////    myConstraints.push_back(aSlvsConstr);
-////    myConstraintMap[theConstraint] = std::vector<Slvs_hEntity>(1, aSlvsConstr.h);
-////    int aConstrPos = Search(aSlvsConstr.h, myConstraints);
-////    aConstrIter = myConstraints.begin() + aConstrPos;
-////    myNeedToSolve = true;
-////  } else { // Attributes of constraint may be changed => update constraint
-////    Slvs_hEntity* aCurrentAttr[] = {&aConstrIter->ptA, &aConstrIter->ptB,
-////                                   &aConstrIter->entityA, &aConstrIter->entityB,
-////                                   &aConstrIter->entityC, &aConstrIter->entityD};
-////    for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
-////      if (*(aCurrentAttr[indAttr]) != aConstrEnt[indAttr])
-////      {
-////        *(aCurrentAttr[indAttr]) = aConstrEnt[indAttr];
-////        myNeedToSolve = true;
-////      }
-////    }
-////  }
-////
-////  // Update flags of entities to be used by constraints
-////  for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++)
-////    if (aConstrEnt[indAttr] != 0) {
-////      int aPos = Search(aConstrEnt[indAttr], myEntities);
-////      myEntOfConstr[aPos] = true;
-////      // Sub-entities should be used implcitly
-////      Slvs_hEntity* aEntPtr = myEntities[aPos].point;
-////      while (*aEntPtr != 0) {
-////        aPos = Search(*aEntPtr, myEntities);
-////        myEntOfConstr[aPos] = true;
-////        aEntPtr++;
-////      }
-////    }
-////
-////  checkConstraintConsistence(*aConstrIter);
+  // Check the attributes of constraint are given by parametric expression
+  std::list<AttributePtr> anAttributes =
+      theConstraint->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
+  std::list<AttributePtr>::iterator anAttrIt = anAttributes.begin();
+  for (; anAttrIt != anAttributes.end(); ++anAttrIt) {
+    AttributeRefAttrPtr aRefAttr =
+        std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttrIt);
+    if (!aRefAttr)
+      continue;
+
+    std::shared_ptr<GeomDataAPI_Point2D> aPoint;
+    if (aRefAttr->isObject()) {
+      FeaturePtr aFeat = ModelAPI_Feature::feature(aRefAttr->object());
+      if (aFeat->getKind() != SketchPlugin_Point::ID())
+        continue;
+      aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+          aFeat->attribute(SketchPlugin_Point::COORD_ID()));
+    } else
+      aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
+
+    if (!aPoint || (aPoint->textX().empty() && aPoint->textY().empty()))
+      continue;
+
+    std::map<AttributePtr, SolverConstraintPtr>::iterator aFound =
+        myParametricConstraints.find(aPoint);
+    if (aFound == myParametricConstraints.end()) {
+      SolverConstraintPtr aConstraint =
+          SketchSolver_Builder::getInstance()->createParametricConstraint(aPoint);
+      if (!aConstraint)
+        continue;
+      aConstraint->setGroup(this);
+      aConstraint->setStorage(myStorage);
+      myParametricConstraints[aPoint] = aConstraint;
+    } else
+      aFound->second->update();
+  }
+
   return true;
 }
 
 
+void SketchSolver_Group::updateConstraints()
+{
+  std::set<SolverConstraintPtr> aPostponed; // postponed constraints Multi-Rotation and Multi-Translation
+
+  ConstraintConstraintMap::iterator anIt = myConstraints.begin();
+  for (; anIt != myConstraints.end(); ++anIt) {
+    if (myChangedConstraints.find(anIt->first) == myChangedConstraints.end())
+      continue;
+    if (anIt->first->getKind() == SketchPlugin_MultiRotation::ID() ||
+        anIt->first->getKind() == SketchPlugin_MultiTranslation::ID())
+      aPostponed.insert(anIt->second);
+    else
+      anIt->second->update();
+  }
+
+  // Update postponed constraints
+  std::set<SolverConstraintPtr>::iterator aSCIter = aPostponed.begin();
+  for (; aSCIter != aPostponed.end(); ++aSCIter)
+    (*aSCIter)->update();
+
+  myChangedConstraints.clear();
+}
+
 bool SketchSolver_Group::updateFeature(std::shared_ptr<SketchPlugin_Feature> theFeature)
 {
-  std::set<ConstraintPtr> aConstraints = myFeatureStorage->getConstraints(theFeature);
+  if (!checkFeatureValidity(theFeature))
+    return false;
+
+  std::set<ConstraintPtr> aConstraints =
+      myFeatureStorage->getConstraints(std::dynamic_pointer_cast<ModelAPI_Feature>(theFeature));
   if (aConstraints.empty())
     return false;
   std::set<ConstraintPtr>::iterator aCIter = aConstraints.begin();
   for (; aCIter != aConstraints.end(); aCIter++) {
     ConstraintConstraintMap::iterator aSolConIter = myConstraints.find(*aCIter);
-    aSolConIter->second->update();
+    if (aSolConIter == myConstraints.end() || !aSolConIter->first->data() ||
+        !aSolConIter->first->data()->isValid())
+      continue;
+    myFeatureStorage->changeFeature(theFeature, aSolConIter->first);
+
+    aSolConIter->second->addFeature(theFeature);
+    myChangedConstraints.insert(aSolConIter->first);
+  }
+
+  // Search attributes of the feature in the set of parametric constraints and update them
+  std::list<AttributePtr> anAttrList =
+      theFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
+  std::list<AttributePtr>::iterator anAttrIt = anAttrList.begin();
+  for (; anAttrIt != anAttrList.end(); ++anAttrIt) {
+    std::map<AttributePtr, SolverConstraintPtr>::iterator aFound =
+        myParametricConstraints.find(*anAttrIt);
+    if (aFound != myParametricConstraints.end())
+      aFound->second->update();
+    else {
+      std::shared_ptr<GeomDataAPI_Point2D> aPoint =
+          std::dynamic_pointer_cast<GeomDataAPI_Point2D>(*anAttrIt);
+      if (aPoint && (!aPoint->textX().empty() || !aPoint->textY().empty())) {
+        // Create new parametric constraint
+        SolverConstraintPtr aConstraint =
+            SketchSolver_Builder::getInstance()->createParametricConstraint(*anAttrIt);
+        if (!aConstraint)
+          continue;
+        aConstraint->setGroup(this);
+        aConstraint->setStorage(myStorage);
+        myParametricConstraints[*anAttrIt] = aConstraint;
+      }
+    }
   }
   return true;
 }
 
 void SketchSolver_Group::moveFeature(std::shared_ptr<SketchPlugin_Feature> theFeature)
 {
-  updateFeature(theFeature);
-  // Temporary rigid constraint
+  // Firstly, create temporary rigid constraint
   SolverConstraintPtr aConstraint =
-      SketchSolver_Builder::getInstance()->createRigidConstraint(theFeature);
+      SketchSolver_Builder::getInstance()->createMovementConstraint(theFeature);
   if (!aConstraint)
     return;
   aConstraint->setGroup(this);
   aConstraint->setStorage(myStorage);
-  myTempConstraints.insert(aConstraint);
+  if (aConstraint->error().empty())
+    setTemporary(aConstraint);
+  // Secondly, update the feature
+  updateFeature(theFeature);
 }
 
-////// ============================================================================
-//////  Function: changeRigidConstraint
-//////  Class:    SketchSolver_Group
-//////  Purpose:  create/update the "Rigid" constraint in the group
-////// ============================================================================
-////bool SketchSolver_Group::changeRigidConstraint(
-////    std::shared_ptr<SketchPlugin_Constraint> theConstraint)
-////{
-////  // Search this constraint in the current group to update it
-////  ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint);
-////  std::vector<Slvs_Constraint>::iterator aConstrIter;
-////  if (aConstrMapIter != myConstraintMap.end()) {
-////    int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints);
-////    aConstrIter = myConstraints.begin() + aConstrPos;
-////  }
-////
-////  // Get constraint type and verify the constraint parameters are correct
-////  SketchSolver_Constraint aConstraint(theConstraint);
-////  int aConstrType = aConstraint.getType();
-////  if (aConstrType == SLVS_C_UNKNOWN
-////      || (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType))
-////    return false;
-////  const std::vector<std::string>& aConstraintAttributes = aConstraint.getAttributes();
-////
-////  Slvs_hEntity aConstrEnt = SLVS_E_UNKNOWN;
-////  std::shared_ptr<ModelAPI_AttributeRefAttr> aConstrAttr = std::dynamic_pointer_cast<
-////      ModelAPI_AttributeRefAttr>(
-////      theConstraint->data()->attribute(aConstraintAttributes[0]));
-////  if (!aConstrAttr)
-////    return false;
-////
-////  // Convert the object of the attribute to the feature
-////  FeaturePtr aFeature;
-////  if (aConstrAttr->isObject() && aConstrAttr->object()) {
-////    ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
-////        aConstrAttr->object());
-////    if (!aRC)
-////      return false;
-////    std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
-////    aFeature = aDoc->feature(aRC);
-////  }
-////
-////  aConstrEnt = aConstrAttr->isObject() ? changeEntityFeature(aFeature) : changeEntity(aConstrAttr->attr());
-////
-////  if (aConstrMapIter == myConstraintMap.end()) { // Add new constraint
-////    // Check the fixed entity is not a point.
-////    std::shared_ptr<ModelAPI_AttributeRefAttr> aConstrAttr = std::dynamic_pointer_cast<
-////        ModelAPI_AttributeRefAttr>(theConstraint->data()->attribute(aConstraintAttributes[0]));
-////    std::shared_ptr<GeomDataAPI_Point> aPoint =
-////        std::dynamic_pointer_cast<GeomDataAPI_Point>(aConstrAttr->attr());
-////    std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
-////        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aConstrAttr->attr());
-////    if (aPoint || aPoint2D) {
-////      // Create SolveSpace constraint structure
-////      Slvs_Constraint aConstraint = Slvs_MakeConstraint(
-////          ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0,
-////          aConstrEnt, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
-////      myConstraints.push_back(aConstraint);
-////      myConstraintMap[theConstraint] = std::vector<Slvs_hEntity>(1, aConstraint.h);
-////      int aConstrPos = Search(aConstraint.h, myConstraints);
-////      aConstrIter = myConstraints.begin() + aConstrPos;
-////      myNeedToSolve = true;
-////    } else {
-////      myConstraintMap[theConstraint] = std::vector<Slvs_hConstraint>();
-////
-////      // To avoid SolveSpace problems:
-////      // * if the circle is rigid, we will fix its center and radius;
-////      // * if the arc is rigid, we will fix its start and end points and radius.
-////      double aRadius = 0.0;
-////      bool isArc = false;
-////      bool isCircle = false;
-////      if (aFeature) {
-////        if (aFeature->getKind() == SketchPlugin_Arc::ID()) {
-////          std::shared_ptr<GeomDataAPI_Point2D> aCenter =
-////              std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-////              aFeature->data()->attribute(SketchPlugin_Arc::CENTER_ID()));
-////          std::shared_ptr<GeomDataAPI_Point2D> aStart =
-////              std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-////              aFeature->data()->attribute(SketchPlugin_Arc::START_ID()));
-////          aRadius = aStart->pnt()->distance(aCenter->pnt());
-////          isArc = true;
-////        } else if (aFeature->getKind() == SketchPlugin_Circle::ID()) {
-////          aRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
-////              aFeature->data()->attribute(SketchPlugin_Circle::RADIUS_ID()))->value();
-////          isCircle = true;
-////        }
-////      }
-////
-////      // Get list of already fixed points
-////      std::set<Slvs_hEntity> anAlreadyFixed;
-////      std::vector<Slvs_Constraint>::const_iterator aCIter = myConstraints.begin();
-////      for (; aCIter != myConstraints.end(); aCIter++)
-////        if (aCIter->type == SLVS_C_WHERE_DRAGGED)
-////          anAlreadyFixed.insert(aCIter->ptA);
-////
-////      // Create constraints to fix the parameters of the entity
-////      int aEntPos = Search(aConstrEnt, myEntities);
-////      Slvs_hEntity* aPointsPtr = myEntities[aEntPos].point;
-////      if (isArc) aPointsPtr++; // avoid to fix center of arc
-////      while (*aPointsPtr != 0) {
-////        // Avoid to create additional "Rigid" constraints for coincident points
-////        bool isCoincAlreadyFixed = false;
-////        if (!anAlreadyFixed.empty()) {
-////          if (anAlreadyFixed.find(*aPointsPtr) != anAlreadyFixed.end())
-////            isCoincAlreadyFixed = true;
-////
-////          std::vector<std::set<Slvs_hEntity> >::const_iterator aCoincIter =
-////              myCoincidentPoints.begin();
-////          for (; !isCoincAlreadyFixed && aCoincIter != myCoincidentPoints.end(); aCoincIter++) {
-////            if (aCoincIter->find(*aPointsPtr) == aCoincIter->end())
-////              continue;
-////            std::set<Slvs_hEntity>::const_iterator anIter = anAlreadyFixed.begin();
-////            for (; !isCoincAlreadyFixed && anIter != anAlreadyFixed.end(); anIter++)
-////              if (aCoincIter->find(*anIter) != aCoincIter->end())
-////                isCoincAlreadyFixed = true;
-////          }
-////        }
-////
-////        if (!isCoincAlreadyFixed) {
-////          Slvs_Constraint aConstraint = Slvs_MakeConstraint(
-////              ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0,
-////              *aPointsPtr, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
-////          myConstraints.push_back(aConstraint);
-////          myConstraintMap[theConstraint].push_back(aConstraint.h);
-////        }
-////        aPointsPtr++;
-////      }
-////
-////      if (isArc || isCircle) { // add radius constraint
-////        Slvs_Constraint aConstraint = Slvs_MakeConstraint(
-////            ++myConstrMaxID, myID, SLVS_C_DIAMETER, myWorkplane.h, 2.0 * aRadius,
-////            SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aConstrEnt, SLVS_E_UNKNOWN);
-////        myConstraints.push_back(aConstraint);
-////        myConstraintMap[theConstraint].push_back(aConstraint.h);
-////      }
-////
-////      // The object is already rigid, so there is no constraints added
-////      if (myConstraintMap[theConstraint].empty()) {
-////        myConstraintMap.erase(theConstraint);
-////        myNeedToSolve = false;
-////      }
-////      else
-////        myNeedToSolve = true;
-////    }
-////  }
-////  return true;
-////}
-////
-////// ============================================================================
-//////  Function: changeMirrorConstraint
-//////  Class:    SketchSolver_Group
-//////  Purpose:  create/update the "Mirror" constraint in the group
-////// ============================================================================
-////bool SketchSolver_Group::changeMirrorConstraint(
-////    std::shared_ptr<SketchPlugin_Constraint> theConstraint)
-////{
-////  DataPtr aConstrData = theConstraint->data();
-////
-////  // Search this constraint in the current group to update it
-////  ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint);
-////  std::vector<Slvs_Constraint>::iterator aConstrIter;
-////  if (aConstrMapIter != myConstraintMap.end()) {
-////    int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints);
-////    aConstrIter = myConstraints.begin() + aConstrPos;
-////  }
-////
-////  // Get constraint type and verify the constraint parameters are correct
-////  SketchSolver_Constraint aConstraint(theConstraint);
-////  int aConstrType = aConstraint.getType();
-////  if (aConstrType == SLVS_C_UNKNOWN
-////      || (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType))
-////    return false;
-////  const std::vector<std::string>& aConstraintAttributes = aConstraint.getAttributes();
-////
-////  Slvs_hEntity aMirrorLineEnt = SLVS_E_UNKNOWN;
-////  AttributeRefAttrPtr aConstrAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
-////      aConstrData->attribute(aConstraintAttributes[0]));
-////  if (!aConstrAttr)
-////    return false;
-////
-////  // Convert the object of the attribute to the feature
-////  FeaturePtr aMirrorLineFeat;
-////  if (aConstrAttr->isObject() && aConstrAttr->object()) {
-////    ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
-////        aConstrAttr->object());
-////    if (!aRC)
-////      return false;
-////    std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
-////    aMirrorLineFeat = aDoc->feature(aRC);
-////  }
-////  aMirrorLineEnt = aConstrAttr->isObject() ?
-////      changeEntityFeature(aMirrorLineFeat) : changeEntity(aConstrAttr->attr());
-////
-////  if (aConstrMapIter == myConstraintMap.end()) { // Add new constraint
-////    // Append symmetric constraint for each point of mirroring features
-////    AttributeRefListPtr aBaseRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
-////        aConstrData->attribute(aConstraintAttributes[1]));
-////    AttributeRefListPtr aMirroredRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
-////        aConstrData->attribute(aConstraintAttributes[2]));
-////    if (!aBaseRefList || !aMirroredRefList)
-////      return false;
-////
-////    std::list<ObjectPtr> aBaseList = aBaseRefList->list();
-////    std::list<ObjectPtr> aMirroredList = aMirroredRefList->list();
-////    if (aBaseList.size() != aMirroredList.size())
-////      return false;
-////
-////    myConstraintMap[theConstraint] = std::vector<Slvs_hConstraint>();
-////
-////    FeaturePtr aBaseFeature, aMirrorFeature;
-////    ResultConstructionPtr aRC;
-////    std::list<ObjectPtr>::iterator aBaseIter = aBaseList.begin();
-////    std::list<ObjectPtr>::iterator aMirIter = aMirroredList.begin();
-////    for ( ; aBaseIter != aBaseList.end(); aBaseIter++, aMirIter++) {
-////      aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aBaseIter);
-////      aBaseFeature = aRC ? aRC->document()->feature(aRC) :
-////          std::dynamic_pointer_cast<SketchPlugin_Feature>(*aBaseIter);
-////      aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aMirIter);
-////      aMirrorFeature = aRC ? aRC->document()->feature(aRC) :
-////          std::dynamic_pointer_cast<SketchPlugin_Feature>(*aMirIter);
-////
-////      if (!aBaseFeature || !aMirrorFeature || 
-////          aBaseFeature->getKind() != aMirrorFeature->getKind())
-////        return false;
-////      Slvs_hEntity aBaseEnt = changeEntityFeature(aBaseFeature);
-////      Slvs_hEntity aMirrorEnt = changeEntityFeature(aMirrorFeature);
-////      // Make aMirrorEnt parameters to be symmetric with aBaseEnt
-////      makeMirrorEntity(aBaseEnt, aMirrorEnt, aMirrorLineEnt);
-////
-////      if (aBaseFeature->getKind() == SketchPlugin_Point::ID()) {
-////        Slvs_Constraint aConstraint = Slvs_MakeConstraint(++myConstrMaxID, myID, aConstrType,
-////            myWorkplane.h, 0.0, aBaseEnt, aMirrorEnt, aMirrorLineEnt, SLVS_E_UNKNOWN);
-////        myConstraints.push_back(aConstraint);
-////        myConstraintMap[theConstraint].push_back(aConstraint.h);
-////      } else {
-////        int aBasePos = Search(aBaseEnt, myEntities);
-////        int aMirrorPos = Search(aMirrorEnt, myEntities);
-////        if (aBaseFeature->getKind() == SketchPlugin_Line::ID()) {
-////          for (int ind = 0; ind < 2; ind++) {
-////            Slvs_Constraint aConstraint = Slvs_MakeConstraint(
-////                ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0,
-////                myEntities[aBasePos].point[ind], myEntities[aMirrorPos].point[ind],
-////                aMirrorLineEnt, SLVS_E_UNKNOWN);
-////            myConstraints.push_back(aConstraint);
-////            myConstraintMap[theConstraint].push_back(aConstraint.h);
-////          }
-////        } else if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) {
-////          Slvs_Constraint aConstraint = Slvs_MakeConstraint(
-////              ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0,
-////              myEntities[aBasePos].point[0], myEntities[aMirrorPos].point[0],
-////              aMirrorLineEnt, SLVS_E_UNKNOWN);
-////          myConstraints.push_back(aConstraint);
-////          myConstraintMap[theConstraint].push_back(aConstraint.h);
-////          // Additional constraint for equal radii
-////          Slvs_Constraint anEqRadConstr = Slvs_MakeConstraint(
-////              ++myConstrMaxID, myID, SLVS_C_EQUAL_RADIUS, myWorkplane.h, 0.0,
-////              SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aBaseEnt, aMirrorEnt);
-////          myConstraints.push_back(anEqRadConstr);
-////          myConstraintMap[theConstraint].push_back(anEqRadConstr.h);
-////        } else if (aBaseFeature->getKind() == SketchPlugin_Arc::ID()) {
-////          // Workaround to avoid problems in SolveSpace.
-////          // The symmetry of two arcs will be done using symmetry of three points on these arcs:
-////          // start point, end point, and any other point on the arc
-////          Slvs_hEntity aBaseArcPoints[3] = {
-////              myEntities[aBasePos].point[1],
-////              myEntities[aBasePos].point[2],
-////              SLVS_E_UNKNOWN};
-////          Slvs_hEntity aMirrorArcPoints[3] = { // indices of points of arc, center corresponds center, first point corresponds last point
-////              myEntities[aMirrorPos].point[2],
-////              myEntities[aMirrorPos].point[1],
-////              SLVS_E_UNKNOWN};
-////          Slvs_hEntity aBothArcs[2] = {aBaseEnt, aMirrorEnt};
-////          Slvs_hEntity aBothMiddlePoints[2];
-////          for (int i = 0; i < 2; i++) {
-////            double x, y;
-////            calculateMiddlePoint(aBothArcs[i], x, y);
-////            std::vector<Slvs_Param>::iterator aParamIter = myParams.end();
-////            Slvs_hParam u = changeParameter(x, aParamIter);
-////            Slvs_hParam v = changeParameter(y, aParamIter);
-////            Slvs_Entity aPoint = Slvs_MakePoint2d(++myEntityMaxID, myID, myWorkplane.h, u, v);
-////            myEntities.push_back(aPoint);
-////            aBothMiddlePoints[i] = aPoint.h;
-////            // additional constraint point-on-curve
-////            Slvs_Constraint aPonCircConstr = Slvs_MakeConstraint(
-////                ++myConstrMaxID, myID, SLVS_C_PT_ON_CIRCLE, myWorkplane.h, 0.0,
-////                aPoint.h, SLVS_E_UNKNOWN, aBothArcs[i], SLVS_E_UNKNOWN);
-////            myConstraints.push_back(aPonCircConstr);
-////            myConstraintMap[theConstraint].push_back(aPonCircConstr.h);
-////          }
-////
-////          aBaseArcPoints[2] = aBothMiddlePoints[0];
-////          aMirrorArcPoints[2] = aBothMiddlePoints[1];
-////          for (int ind = 0; ind < 3; ind++) {
-////            Slvs_Constraint aConstraint = Slvs_MakeConstraint(
-////                ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0,
-////                aBaseArcPoints[ind], aMirrorArcPoints[ind], aMirrorLineEnt, SLVS_E_UNKNOWN);
-////            myConstraints.push_back(aConstraint);
-////            myConstraintMap[theConstraint].push_back(aConstraint.h);
-////          }
-////        }
-////      }
-////    }
-////
-////    // Set the mirror line unchanged during constraint recalculation
-////    int aMirrorLinePos = Search(aMirrorLineEnt, myEntities);
-////    Slvs_Constraint aRigidStart = Slvs_MakeConstraint(
-////        ++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED, myWorkplane.h, 0,
-////        myEntities[aMirrorLinePos].point[0], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
-////    myConstraints.push_back(aRigidStart);
-////    myConstraintMap[theConstraint].push_back(aRigidStart.h);
-////    Slvs_Constraint aRigidEnd = Slvs_MakeConstraint(
-////        ++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED, myWorkplane.h, 0,
-////        myEntities[aMirrorLinePos].point[1], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
-////    myConstraints.push_back(aRigidEnd);
-////    myConstraintMap[theConstraint].push_back(aRigidEnd.h);
-////
-////    // Add temporary constraints for initial objects to be unchanged
-////    for (aBaseIter = aBaseList.begin(); aBaseIter != aBaseList.end(); aBaseIter++) {
-////      aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aBaseIter);
-////      aBaseFeature = aRC ? aRC->document()->feature(aRC) :
-////          std::dynamic_pointer_cast<SketchPlugin_Feature>(*aBaseIter);
-////      if (!aBaseFeature) continue;
-////      std::list<AttributePtr> aPoints = aBaseFeature->data()->attributes(GeomDataAPI_Point2D::type());
-////      std::list<AttributePtr>::iterator anIt = aPoints.begin();
-////      for ( ; anIt != aPoints.end(); anIt++) {
-////        // Arcs are fixed by center and start points only (to avoid solving errors in SolveSpace)
-////        if (aBaseFeature->getKind() == SketchPlugin_Arc::ID() &&
-////            (*anIt)->id() == SketchPlugin_Arc::END_ID())
-////          continue;
-////        addTemporaryConstraintWhereDragged(*anIt);
-////      }
-////    }
-////  }
-////  return true;
-////}
-////
-////// ============================================================================
-//////  Function: changeFilletConstraint
-//////  Class:    SketchSolver_Group
-//////  Purpose:  create/update the "Fillet" constraint in the group
-////// ============================================================================
-////bool SketchSolver_Group::changeFilletConstraint(
-////    std::shared_ptr<SketchPlugin_Constraint> theConstraint)
-////{
-////  DataPtr aConstrData = theConstraint->data();
-////
-////  // Search this constraint in the current group to update it
-////  ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint);
-////  std::vector<Slvs_Constraint>::iterator aConstrIter;
-////  if (aConstrMapIter != myConstraintMap.end()) {
-////    int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints);
-////    aConstrIter = myConstraints.begin() + aConstrPos;
-////  }
-////
-////  // Get constraint type and verify the constraint parameters are correct
-////  SketchSolver_Constraint aConstraint(theConstraint);
-////  int aConstrType = aConstraint.getType();
-////  if (aConstrType == SLVS_C_UNKNOWN)
-////    return false;
-////  const std::vector<std::string>& aConstraintAttributes = aConstraint.getAttributes();
-////
-////  // Obtain hEntity for basic objects of fillet
-////  Slvs_hEntity aBaseObject[2];
-////  FeaturePtr aBaseFeature[2];
-////  for (unsigned int indAttr = 0; indAttr < 2; indAttr++) {
-////    AttributeRefAttrPtr aConstrAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
-////        aConstrData->attribute(aConstraintAttributes[indAttr]));
-////    if (!aConstrAttr)
-////      return false;
-////    if (aConstrAttr->isObject() && aConstrAttr->object()) {
-////      ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
-////          aConstrAttr->object());
-////      if (!aRC)
-////        return false;
-////      std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
-////      aBaseFeature[indAttr] = aDoc->feature(aRC);
-////    }
-////    aBaseObject[indAttr] = aConstrAttr->isObject() ?
-////        changeEntityFeature(aBaseFeature[indAttr]) : changeEntity(aConstrAttr->attr());
-////  }
-////  // Check the base entities have a coincident point
-////  int aBaseObjInd[2] = {
-////      Search(aBaseObject[0], myEntities),
-////      Search(aBaseObject[1], myEntities)
-////    };
-////  int aShift[2] = { // shift for calculating correct start and end points for different types of objects
-////      myEntities[aBaseObjInd[0]].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0,
-////      myEntities[aBaseObjInd[1]].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0,
-////    };
-////  Slvs_hEntity aFirstObjPoints[2] = { // indices of start and end point of first object
-////      myEntities[aBaseObjInd[0]].point[aShift[0]],
-////      myEntities[aBaseObjInd[0]].point[1+aShift[0]]
-////    };
-////  Slvs_hEntity aSecondObjPoints[2] = { // indices of start and end point of second object
-////      myEntities[aBaseObjInd[1]].point[aShift[1]],
-////      myEntities[aBaseObjInd[1]].point[1+aShift[1]]
-////    };
-////  bool isCoincidentFound = false;
-////  int aBaseCoincInd[2] = {0, 0}; // indices in aFirstObjPoint and aSecondObjPoint identifying coincident points
-////  std::vector<std::set<Slvs_hEntity> >::iterator aCPIter = myCoincidentPoints.begin();
-////  for ( ; aCPIter != myCoincidentPoints.end() && !isCoincidentFound; aCPIter++)
-////    for (int ind1 = 0; ind1 < 2 && !isCoincidentFound; ind1++)
-////      for (int ind2 = 0; ind2 < 2 && !isCoincidentFound; ind2++)
-////        if (aCPIter->find(aFirstObjPoints[ind1]) != aCPIter->end() &&
-////            aCPIter->find(aSecondObjPoints[ind2]) != aCPIter->end()) {
-////          aBaseCoincInd[0] = ind1;
-////          aBaseCoincInd[1] = ind2;
-////          isCoincidentFound = true;
-////        }
-////  if (!isCoincidentFound) {
-////    // There is no coincident points between objects. Generate error message
-////    Events_Error::send(SketchSolver_Error::NO_COINCIDENT_POINTS(), this);
-////    return false;
-////  }
-////
-////  // Create fillet entities
-////  // - first object is placed on the first base 
-////  // - second object is on the second base 
-////  // - third object is a filleting arc
-////  static const int aNbFilletEnt = 3;
-////  Slvs_hEntity aFilletEnt[aNbFilletEnt];
-////  int aFilletObjInd[aNbFilletEnt];
-////  AttributeRefListPtr aFilletRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
-////      aConstrData->attribute(aConstraintAttributes[2]));
-////  if (!aFilletRefList)
-////    return false;
-////  std::list<ObjectPtr> aFilletList = aFilletRefList->list();
-////  if (aFilletList.size() < aNbFilletEnt)
-////    return false;
-////  FeaturePtr aFilletFeature;
-////  ResultConstructionPtr aRC;
-////  std::list<ObjectPtr>::iterator aFilIter = aFilletList.begin();
-////  for (int indEnt = 0; aFilIter != aFilletList.end(); aFilIter++, indEnt++) {
-////    aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aFilIter);
-////    aFilletFeature = aRC ? aRC->document()->feature(aRC) :
-////        std::dynamic_pointer_cast<SketchPlugin_Feature>(*aFilIter);
-////    if (!aFilletFeature)
-////      return false;
-////    aFilletEnt[indEnt] = changeEntityFeature(aFilletFeature);
-////    aFilletObjInd[indEnt] = Search(aFilletEnt[indEnt], myEntities);
-////  }
-////  // At first time, for correct result, move floating points of fillet on the middle points of base objects
-////  if (myConstraintMap.find(theConstraint) == myConstraintMap.end()) {
-////    double anArcPoints[6];
-////    for (int indEnt = 0; indEnt < aNbFilletEnt - 1; indEnt++) {
-////      int anIndShift = myEntities[aFilletObjInd[indEnt]].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0;
-////      int aPointsPos[2] = {
-////          Search(myEntities[aFilletObjInd[indEnt]].point[anIndShift], myEntities),
-////          Search(myEntities[aFilletObjInd[indEnt]].point[1+anIndShift], myEntities)
-////        };
-////      int aParamPos[2] = {
-////          Search(myEntities[aPointsPos[0]].param[0], myParams),
-////          Search(myEntities[aPointsPos[1]].param[0], myParams)
-////        };
-////      int anIndex = aParamPos[aBaseCoincInd[indEnt]];
-////      if (anIndShift == 0) {
-////        myParams[anIndex].val =
-////            0.5 * (myParams[aParamPos[0]].val + myParams[aParamPos[1]].val);
-////        myParams[1 + anIndex].val =
-////            0.5 * (myParams[1 + aParamPos[0]].val + myParams[1 + aParamPos[1]].val);
-////      } else { // place the changed point on the arc
-////        double x = 0, y = 0;
-////        calculateMiddlePoint(aFilletEnt[indEnt], x, y);
-////        myParams[anIndex].val = x;
-////        myParams[1 + anIndex].val = y;
-////      }
-////      anArcPoints[indEnt*2+2] = myParams[anIndex].val;
-////      anArcPoints[indEnt*2+3] = myParams[1 + anIndex].val;
-////    }
-////    anArcPoints[0] = 0.5 * (anArcPoints[2] + anArcPoints[4]);
-////    anArcPoints[1] = 0.5 * (anArcPoints[3] + anArcPoints[5]);
-////    for (int indArcPt = 0; indArcPt < 3; indArcPt++) {
-////      int aPtPos = Search(myEntities[aFilletObjInd[2]].point[indArcPt], myEntities);
-////      int aParamPos = Search(myEntities[aPtPos].param[0], myParams);
-////      myParams[aParamPos].val = anArcPoints[indArcPt * 2];
-////      myParams[aParamPos + 1].val = anArcPoints[indArcPt * 2 + 1];
-////    }
-////  }
-////
-////  // Check the fillet arc which point to be connected to
-////  bool isArcInversed = false; // indicates that start and end points of arc should be connected to second and first object respectively
-////  Slvs_hEntity hEnt = myEntities[aFilletObjInd[2]].point[1];
-////  int aPos = Search(hEnt, myEntities);
-////  Slvs_hParam anArcStartPoint = myEntities[aPos].param[0];
-////  aPos = Search(anArcStartPoint, myParams);
-////  double anArcPtCoord[2] = {myParams[aPos].val, myParams[aPos+1].val};
-////  double aSqDistances[2];
-////  int aPtInd;
-////  for (int indEnt = 0; indEnt < aNbFilletEnt - 1; indEnt++) {
-////    aPtInd = aBaseCoincInd[indEnt]+aShift[indEnt];
-////    hEnt = myEntities[aFilletObjInd[indEnt]].point[aPtInd];
-////    aPos = Search(hEnt, myEntities);
-////    Slvs_hParam anObjectPoint = myEntities[aPos].param[0];
-////    aPos = Search(anObjectPoint, myParams);
-////    double aPtCoord[2] = {myParams[aPos].val, myParams[aPos+1].val};
-////    aSqDistances[indEnt] = 
-////        (anArcPtCoord[0] - aPtCoord[0]) * (anArcPtCoord[0] - aPtCoord[0]) +
-////        (anArcPtCoord[1] - aPtCoord[1]) * (anArcPtCoord[1] - aPtCoord[1]);
-////  }
-////  if (aSqDistances[1] < aSqDistances[0])
-////    isArcInversed = true;
-////
-////  // Create list of constraints to generate fillet
-////  std::vector<Slvs_hConstraint> aConstrList;
-////  bool isExists = myConstraintMap.find(theConstraint) != myConstraintMap.end(); // constraint already exists
-////  std::vector<Slvs_hConstraint>::iterator aCMapIter =
-////    isExists ? myConstraintMap[theConstraint].begin() : aConstrList.begin();
-////  int aCurConstrPos = isExists ? Search(*aCMapIter, myConstraints) : 0;
-////  for (int indEnt = 0; indEnt < aNbFilletEnt - 1; indEnt++) {
-////    // one point of fillet object should be coincident with the point on base, non-coincident with another base object
-////    aPtInd = 1-aBaseCoincInd[indEnt]+aShift[indEnt]; // (1-aBaseCoincInd[indEnt]) = index of non-coincident point, aShift is used to process all types of shapes
-////    Slvs_hEntity aPtBase = myEntities[aBaseObjInd[indEnt]].point[aPtInd];
-////    Slvs_hEntity aPtFillet = myEntities[aFilletObjInd[indEnt]].point[aPtInd];
-////    if (isExists) {
-////      myConstraints[aCurConstrPos].ptA = aPtBase;
-////      myConstraints[aCurConstrPos].ptB = aPtFillet;
-////      aCMapIter++;
-////      aCurConstrPos = Search(*aCMapIter, myConstraints);
-////    } else {
-////      Slvs_Constraint aCoincConstr = Slvs_MakeConstraint(
-////          ++myConstrMaxID, myID, SLVS_C_POINTS_COINCIDENT, myWorkplane.h,
-////          0, aPtBase, aPtFillet, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
-////      myConstraints.push_back(aCoincConstr);
-////      aConstrList.push_back(aCoincConstr.h);
-////    }
-////
-////    // another point of fillet object should be placed on the base object
-////    Slvs_Constraint aPonCurveConstr;
-////    int aTangentType;
-////    if (myEntities[aFilletObjInd[indEnt]].type == SLVS_E_ARC_OF_CIRCLE) {
-////      // centers of arcs should be coincident
-////      aPtBase = myEntities[aBaseObjInd[indEnt]].point[0];
-////      aPtFillet = myEntities[aFilletObjInd[indEnt]].point[0];
-////      if (isExists) {
-////        myConstraints[aCurConstrPos].ptA = aPtBase;
-////        myConstraints[aCurConstrPos].ptB = aPtFillet;
-////        aCMapIter++;
-////        aCurConstrPos = Search(*aCMapIter, myConstraints);
-////      } else {
-////        aPonCurveConstr = Slvs_MakeConstraint(
-////            ++myConstrMaxID, myID, SLVS_C_POINTS_COINCIDENT, myWorkplane.h,
-////            0, aPtBase, aPtFillet, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
-////      }
-////      aPtFillet = myEntities[aFilletObjInd[indEnt]].point[1+aBaseCoincInd[indEnt]]; // !!! will be used below
-////      aTangentType = SLVS_C_CURVE_CURVE_TANGENT;
-////    } else {
-////      aPtInd = aBaseCoincInd[indEnt];
-////      aPtFillet = myEntities[aFilletObjInd[indEnt]].point[aPtInd];
-////      if (isExists) {
-////        myConstraints[aCurConstrPos].ptA = aPtFillet;
-////        aCMapIter++;
-////        aCurConstrPos = Search(*aCMapIter, myConstraints);
-////      } else {
-////        aPonCurveConstr = Slvs_MakeConstraint(
-////            ++myConstrMaxID, myID, SLVS_C_PT_ON_LINE, myWorkplane.h,
-////            0, aPtFillet, SLVS_E_UNKNOWN, aBaseObject[indEnt], SLVS_E_UNKNOWN);
-////      }
-////      aTangentType = SLVS_C_ARC_LINE_TANGENT;
-////    }
-////    if (!isExists) {
-////      myConstraints.push_back(aPonCurveConstr);
-////      aConstrList.push_back(aPonCurveConstr.h);
-////    }
-////
-////    // Bound point of fillet arc should be tangently coincident with a bound point of fillet object
-////    aPtInd = 1 + (isArcInversed ? 1-indEnt : indEnt);
-////    Slvs_hEntity aPtArc = myEntities[aFilletObjInd[2]].point[aPtInd];
-////    if (isExists) {
-////      myConstraints[aCurConstrPos].ptA = aPtArc;
-////      myConstraints[aCurConstrPos].ptB = aPtFillet;
-////      aCMapIter++;
-////      aCurConstrPos = Search(*aCMapIter, myConstraints);
-////      myConstraints[aCurConstrPos].entityA = aFilletEnt[2];
-////      myConstraints[aCurConstrPos].entityB = aFilletEnt[indEnt];
-////      myConstraints[aCurConstrPos].other = (isArcInversed ? 1-indEnt : indEnt);
-////      aCMapIter++;
-////      aCurConstrPos = Search(*aCMapIter, myConstraints);
-////    } else {
-////      Slvs_Constraint aCoincConstr = Slvs_MakeConstraint(
-////          ++myConstrMaxID, myID, SLVS_C_POINTS_COINCIDENT, myWorkplane.h,
-////          0, aPtArc, aPtFillet, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
-////      myConstraints.push_back(aCoincConstr);
-////      aConstrList.push_back(aCoincConstr.h);
-////      Slvs_Constraint aTangency = Slvs_MakeConstraint(
-////          ++myConstrMaxID, myID, aTangentType, myWorkplane.h,
-////          0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aFilletEnt[2], aFilletEnt[indEnt]);
-////      aTangency.other = (isArcInversed ? 1-indEnt : indEnt);
-////      aTangency.other2 = aTangentType == SLVS_C_CURVE_CURVE_TANGENT ? aBaseCoincInd[indEnt] : 0;
-////      myConstraints.push_back(aTangency);
-////      aConstrList.push_back(aTangency.h);
-////    }
-////  }
-////
-////  // Additional constraint for fillet diameter
-////  double aRadius = 0.0;  // scalar value of the constraint
-////  AttributeDoublePtr aDistAttr = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
-////      aConstrData->attribute(SketchPlugin_Constraint::VALUE()));
-////  aRadius = aDistAttr->value();
-////  if (isExists) {
-////    myConstraints[aCurConstrPos].entityA = aFilletEnt[2];
-////    myConstraints[aCurConstrPos].valA = aRadius * 2.0;
-////    aCMapIter++;
-////  } else {
-////    Slvs_Constraint aDiamConstr = Slvs_MakeConstraint(
-////        ++myConstrMaxID, myID, SLVS_C_DIAMETER, myWorkplane.h, aRadius * 2.0,
-////        SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aFilletEnt[2], SLVS_E_UNKNOWN);
-////    myConstraints.push_back(aDiamConstr);
-////    aConstrList.push_back(aDiamConstr.h);
-////
-////    myConstraintMap[theConstraint] = aConstrList;
-////  }
-////
-////  // Additional temporary constraints for base objects to be fixed
-////  for (unsigned int indAttr = 0; indAttr < 2; indAttr++) {
-////    if (!aBaseFeature[indAttr]) {
-////      AttributeRefAttrPtr aConstrAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
-////          aConstrData->attribute(aConstraintAttributes[indAttr]));
-////      addTemporaryConstraintWhereDragged(aConstrAttr->attr());
-////      continue;
-////    }
-////    std::list<AttributePtr> anAttributes =
-////        aBaseFeature[indAttr]->data()->attributes(GeomDataAPI_Point2D::type());
-////    std::list<AttributePtr>::iterator anIt = anAttributes.begin();
-////    for ( ; anIt != anAttributes.end(); anIt++) {
-////      // Arc should be fixed by center and start points only (to avoid "conflicting constraints" message)
-////      if (aBaseFeature[indAttr]->getKind() == SketchPlugin_Arc::ID() &&
-////          (*anIt)->id() == SketchPlugin_Arc::END_ID())
-////        continue;
-////      addTemporaryConstraintWhereDragged(*anIt);
-////    }
-////  }
-////  return true;
-////}
-////
-////// ============================================================================
-//////  Function: changeEntity
-//////  Class:    SketchSolver_Group
-//////  Purpose:  create/update the element affected by any constraint
-////// ============================================================================
-////Slvs_hEntity SketchSolver_Group::changeEntity(
-////    std::shared_ptr<ModelAPI_Attribute> theEntity)
-////{
-////  // If the entity is already in the group, try to find it
-////  std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator aEntIter =
-////      myEntityAttrMap.find(theEntity);
-////  int aEntPos;
-////  std::vector<Slvs_Param>::const_iterator aParamIter;  // looks at first parameter of already existent entity or at the end of vector otherwise
-////  if (aEntIter == myEntityAttrMap.end())  // no such entity => should be created
-////    aParamIter = myParams.end();
-////  else {  // the entity already exists
-////    aEntPos = Search(aEntIter->second, myEntities);
-////    int aParamPos = Search(myEntities[aEntPos].param[0], myParams);
-////    aParamIter = myParams.begin() + aParamPos;
-////  }
-////  const bool isEntExists = (aEntIter != myEntityAttrMap.end());  // defines that the entity already exists
-////  const bool isNeedToSolve = myNeedToSolve;
-////  myNeedToSolve = false;
-////
-////  if (isEntExists) {
-////    // Verify that the entity is not used by "Rigid" constraint.
-////    // If it is used, the object should not move.
-////    std::vector<std::set<Slvs_hEntity> >::iterator aCoincIter = myCoincidentPoints.begin();
-////    for (; aCoincIter != myCoincidentPoints.end(); aCoincIter++)
-////      if (aCoincIter->find(aEntIter->second) != aCoincIter->end())
-////        break;
-////    std::set<Slvs_hEntity> aCoincident;
-////    if (aCoincIter != myCoincidentPoints.end()) {
-////      aCoincident = *aCoincIter;
-////      aCoincident.erase(aEntIter->second);
-////
-////      std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
-////      for (; aConstrIter != myConstraints.end(); aConstrIter++)
-////        if (aConstrIter->type == SLVS_C_WHERE_DRAGGED &&
-////            aCoincident.find(aConstrIter->ptA) != aCoincident.end()) {
-////          myNeedToSolve = true;
-////          return aEntIter->second;
-////        }
-////    }
-////  }
-////
-////  // Look over supported types of entities
-////  Slvs_Entity aNewEntity;
-////  aNewEntity.h = SLVS_E_UNKNOWN;
-////
-////  // Point in 3D
-////  std::shared_ptr<GeomDataAPI_Point> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point>(
-////      theEntity);
-////  if (aPoint) {
-////    Slvs_hParam aX = changeParameter(aPoint->x(), aParamIter);
-////    Slvs_hParam aY = changeParameter(aPoint->y(), aParamIter);
-////    Slvs_hParam aZ = changeParameter(aPoint->z(), aParamIter);
-////    if (!isEntExists) // New entity
-////      aNewEntity = Slvs_MakePoint3d(++myEntityMaxID, myID, aX, aY, aZ);
-////  } else {
-////    // All entities except 3D points are created on workplane. So, if there is no workplane yet, then error
-////    if (myWorkplane.h == SLVS_E_UNKNOWN)
-////      return SLVS_E_UNKNOWN;
-////
-////    // Point in 2D
-////    std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
-////        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theEntity);
-////    if (aPoint2D) {
-////      Slvs_hParam aU = changeParameter(aPoint2D->x(), aParamIter);
-////      Slvs_hParam aV = changeParameter(aPoint2D->y(), aParamIter);
-////      if (!isEntExists) // New entity
-////        aNewEntity = Slvs_MakePoint2d(++myEntityMaxID, myID, myWorkplane.h, aU, aV);
-////    } else {
-////      // Scalar value (used for the distance entities)
-////      AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theEntity);
-////      if (aScalar) {
-////        Slvs_hParam aValue = changeParameter(aScalar->value(), aParamIter);
-////        if (!isEntExists) // New entity
-////          aNewEntity = Slvs_MakeDistance(++myEntityMaxID, myID, myWorkplane.h, aValue);
-////      }
-////    }
-////  }
-////  /// \todo Other types of entities
-////
-////  Slvs_hEntity aResult = SLVS_E_UNKNOWN; // Unsupported or wrong entity type
-////
-////  if (isEntExists) {
-////    myNeedToSolve = myNeedToSolve || isNeedToSolve;
-////    aResult = aEntIter->second;
-////  } else if (aNewEntity.h != SLVS_E_UNKNOWN) {
-////    myEntities.push_back(aNewEntity);
-////    myEntOfConstr.push_back(false);
-////    myEntityAttrMap[theEntity] = aNewEntity.h;
-////    aResult = aNewEntity.h;
-////  }
-////
-////  // If the attribute was changed by the user, we need to fix it before solving
-////  if (myNeedToSolve && theEntity->isImmutable())
-////    addTemporaryConstraintWhereDragged(theEntity, false);
-////
-////  return aResult;
-////}
-////
-////// ============================================================================
-//////  Function: changeEntity
-//////  Class:    SketchSolver_Group
-//////  Purpose:  create/update the element defined by the feature affected by any constraint
-////// ============================================================================
-////Slvs_hEntity SketchSolver_Group::changeEntityFeature(FeaturePtr theEntity)
-////{
-////  if (!theEntity->data()->isValid())
-////    return SLVS_E_UNKNOWN;
-////  // If the entity is already in the group, try to find it
-////  std::map<FeaturePtr, Slvs_hEntity>::const_iterator aEntIter = myEntityFeatMap.find(theEntity);
-////  // defines that the entity already exists
-////  const bool isEntExists = (myEntityFeatMap.find(theEntity) != myEntityFeatMap.end());
-////  
-////  Slvs_Entity aNewEntity;
-////  aNewEntity.h = SLVS_E_UNKNOWN;
-////
-////  // SketchPlugin features
-////  std::shared_ptr<SketchPlugin_Feature> aFeature = std::dynamic_pointer_cast<
-////      SketchPlugin_Feature>(theEntity);
-////  if (aFeature) {  // Verify the feature by its kind
-////    const std::string& aFeatureKind = aFeature->getKind();
-////    AttributePtr anAttribute;
-////
-////    // Line
-////    if (aFeatureKind.compare(SketchPlugin_Line::ID()) == 0) {
-////      anAttribute = aFeature->data()->attribute(SketchPlugin_Line::START_ID());
-////      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
-////      Slvs_hEntity aStart = changeEntity(anAttribute);
-////
-////      anAttribute = aFeature->data()->attribute(SketchPlugin_Line::END_ID());
-////      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
-////      Slvs_hEntity aEnd = changeEntity(anAttribute);
-////
-////      if (!isEntExists) // New entity
-////        aNewEntity = Slvs_MakeLineSegment(++myEntityMaxID, myID, myWorkplane.h, aStart, aEnd);
-////    }
-////    // Circle
-////    else if (aFeatureKind.compare(SketchPlugin_Circle::ID()) == 0) {
-////      anAttribute = aFeature->data()->attribute(SketchPlugin_Circle::CENTER_ID());
-////      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
-////      Slvs_hEntity aCenter = changeEntity(anAttribute);
-////
-////      anAttribute = aFeature->data()->attribute(SketchPlugin_Circle::RADIUS_ID());
-////      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
-////      Slvs_hEntity aRadius = changeEntity(anAttribute);
-////
-////      if (!isEntExists) // New entity
-////        aNewEntity = Slvs_MakeCircle(++myEntityMaxID, myID, myWorkplane.h, aCenter,
-////                                     myWorkplane.normal, aRadius);
-////    }
-////    // Arc
-////    else if (aFeatureKind.compare(SketchPlugin_Arc::ID()) == 0) {
-////      anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::CENTER_ID());
-////      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
-////      Slvs_hEntity aCenter = changeEntity(anAttribute);
-////
-////      anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::START_ID());
-////      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
-////      Slvs_hEntity aStart = changeEntity(anAttribute);
-////
-////      anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::END_ID());
-////      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
-////      Slvs_hEntity aEnd = changeEntity(anAttribute);
-////
-////      if (!isEntExists)
-////        aNewEntity = Slvs_MakeArcOfCircle(++myEntityMaxID, myID, myWorkplane.h,
-////                                          myWorkplane.normal, aCenter, aStart, aEnd);
-////    }
-////    // Point (it has low probability to be an attribute of constraint, so it is checked at the end)
-////    else if (aFeatureKind.compare(SketchPlugin_Point::ID()) == 0) {
-////      anAttribute = aFeature->data()->attribute(SketchPlugin_Point::COORD_ID());
-////      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
-////      Slvs_hEntity aPoint = changeEntity(anAttribute);
-////
-////      if (isEntExists)
-////        return aEntIter->second;
-////
-////      // Both the sketch point and its attribute (coordinates) link to the same SolveSpace point identifier
-////      myEntityFeatMap[theEntity] = aPoint;
-////      myNeedToSolve = true;
-////      return aPoint;
-////    }
-////  }
-////  /// \todo Other types of features
-////
-////  if (isEntExists)
-////    return aEntIter->second;
-////
-////  if (aNewEntity.h != SLVS_E_UNKNOWN) {
-////    myEntities.push_back(aNewEntity);
-////    myEntOfConstr.push_back(false);
-////    myEntityFeatMap[theEntity] = aNewEntity.h;
-////    myNeedToSolve = true;
-////    return aNewEntity.h;
-////  }
-////
-////  // Unsupported or wrong entity type
-////  return SLVS_E_UNKNOWN;
-////}
+// ============================================================================
+//  Function: fixFeaturesList
+//  Class:    SketchSolver_Group
+//  Purpose:  Apply temporary rigid constraints for the list of features
+// ============================================================================
+void SketchSolver_Group::fixFeaturesList(AttributeRefListPtr theList)
+{
+  std::list<ObjectPtr> aList = theList->list();
+  std::list<ObjectPtr>::iterator anIt = aList.begin();
+  std::list<FeaturePtr> aFeatures;
+  // Sort features, at begining there are features used by Equal constraint
+  for (; anIt != aList.end(); anIt++) {
+    if (!(*anIt))
+      continue;
+    FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
+    std::set<ConstraintPtr> aConstraints = myFeatureStorage->getConstraints(aFeature);
+    std::set<ConstraintPtr>::iterator aCIter = aConstraints.begin();
+    for (; aCIter != aConstraints.end(); aCIter++)
+      if ((*aCIter)->getKind() == SketchPlugin_ConstraintEqual::ID())
+        break;
+    if (aCIter != aConstraints.end())
+      aFeatures.push_front(aFeature);
+    else
+      aFeatures.push_back(aFeature);
+  }
+
+  std::list<FeaturePtr>::iterator aFeatIter = aFeatures.begin();
+  for (; aFeatIter != aFeatures.end(); aFeatIter++) {
+    SolverConstraintPtr aConstraint =
+        SketchSolver_Builder::getInstance()->createRigidConstraint(*aFeatIter);
+    if (!aConstraint)
+      continue;
+    aConstraint->setGroup(this);
+    aConstraint->setStorage(myStorage);
+    setTemporary(aConstraint);
+  }
+}
 
 // ============================================================================
 //  Function: addWorkplane
@@ -1320,13 +516,13 @@ bool SketchSolver_Group::updateWorkplane()
     std::vector<Slvs_Param>::iterator aParIter = aParams.begin();
     for (; aParIter != aParams.end(); aParIter++) {
       aParIter->h = SLVS_E_UNKNOWN; // the ID should be generated by storage
-      aParIter->group = myID;
+      aParIter->group = SLVS_G_OUTOFGROUP;
       aParIter->h = myStorage->addParameter(*aParIter);
     }
     std::vector<Slvs_Entity>::iterator anEntIter = anEntities.begin();
     for (; anEntIter != anEntities.end(); anEntIter++) {
       anEntIter->h = SLVS_E_UNKNOWN; // the ID should be generated by storage
-      anEntIter->group = myID;
+      anEntIter->group = SLVS_G_OUTOFGROUP;
       anEntIter->wrkpl = myWorkplaneID;
       for (int i = 0; i < 4; i++)
         if (anEntIter->param[i] != SLVS_E_UNKNOWN)
@@ -1356,33 +552,6 @@ bool SketchSolver_Group::updateWorkplane()
   return myWorkplaneID > 0;
 }
 
-////// ============================================================================
-//////  Function: changeParameter
-//////  Class:    SketchSolver_Group
-//////  Purpose:  create/update value of parameter
-////// ============================================================================
-////Slvs_hParam SketchSolver_Group::changeParameter(
-////    const double& theParam, std::vector<Slvs_Param>::const_iterator& thePrmIter)
-////{
-////  if (thePrmIter != myParams.end()) {  // Parameter should be updated
-////    int aParamPos = thePrmIter - myParams.begin();
-////    if (fabs(thePrmIter->val - theParam) > tolerance) {
-////      myNeedToSolve = true;  // parameter is changed, need to resolve constraints
-////      myParams[aParamPos].val = theParam;
-////    }
-////    thePrmIter++;
-////    return myParams[aParamPos].h;
-////  }
-////
-////  // Newly created parameter
-////  Slvs_Param aParam = Slvs_MakeParam(++myParamMaxID, myID, theParam);
-////  myParams.push_back(aParam);
-////  myNeedToSolve = true;
-////  // The list of parameters is changed, move iterator to the end of the list to avoid problems
-////  thePrmIter = myParams.end();
-////  return aParam.h;
-////}
-
 // ============================================================================
 //  Function: resolveConstraints
 //  Class:    SketchSolver_Group
@@ -1390,20 +559,76 @@ bool SketchSolver_Group::updateWorkplane()
 // ============================================================================
 bool SketchSolver_Group::resolveConstraints()
 {
+  if (!myChangedConstraints.empty())
+    updateConstraints();
+
   bool aResolved = false;
   if (myStorage->isNeedToResolve() && !isEmpty()) {
     myConstrSolver.setGroupID(myID);
+    myConstrSolver.calculateFailedConstraints(false);
     myStorage->initializeSolver(myConstrSolver);
 
-    int aResult = myConstrSolver.solve();
+    int aResult = SLVS_RESULT_OKAY;
+    try {
+      if (myStorage->hasDuplicatedConstraint())
+        aResult = SLVS_RESULT_INCONSISTENT;
+      else {
+        // To avoid overconstraint situation, we will remove temporary constraints one-by-one
+        // and try to find the case without overconstraint
+        bool isLastChance = false;
+        int aNbTemp = myStorage->numberTemporary();
+        while (true) {
+          aResult = myConstrSolver.solve();
+          if (aResult == SLVS_RESULT_OKAY || isLastChance)
+            break;
+          if (aNbTemp <= 0) {
+            // try to update parameters and resolve once again
+            ConstraintConstraintMap::iterator aConstrIt = myConstraints.begin();
+            for (; aConstrIt != myConstraints.end(); ++aConstrIt)
+              aConstrIt->second->update();
+            isLastChance = true;
+          } else
+            aNbTemp = myStorage->deleteTemporaryConstraint();
+          myConstrSolver.calculateFailedConstraints(true); // something failed => need to find it
+          myStorage->initializeSolver(myConstrSolver);
+        }
+      }
+    } catch (...) {
+//      Events_Error::send(SketchSolver_Error::SOLVESPACE_CRASH(), this);
+      getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue(SketchSolver_Error::SOLVESPACE_CRASH());
+      if (myPrevSolved) {
+        // the error message should be changed before sending the message
+        sendMessage(EVENT_SOLVER_FAILED);
+        myPrevSolved = false;
+      }
+      return false;
+    }
     if (aResult == SLVS_RESULT_OKAY) {  // solution succeeded, store results into correspondent attributes
       myFeatureStorage->blockEvents(true);
+      // First refresh parametric constraints to satisfy parameters
+      std::map<AttributePtr, SolverConstraintPtr>::iterator aParIter = myParametricConstraints.begin();
+      for (; aParIter != myParametricConstraints.end(); ++aParIter)
+        aParIter->second->refresh();
+      // Update all other constraints
       ConstraintConstraintMap::iterator aConstrIter = myConstraints.begin();
-      for (; aConstrIter != myConstraints.end(); aConstrIter++)
+      for (; aConstrIter != myConstraints.end(); ++aConstrIter)
         aConstrIter->second->refresh();
       myFeatureStorage->blockEvents(false);
-    } else if (!myConstraints.empty())
-      Events_Error::send(SketchSolver_Error::CONSTRAINTS(), this);
+      if (!myPrevSolved) {
+        getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue("");
+        // the error message should be changed before sending the message
+        sendMessage(EVENT_SOLVER_REPAIRED);
+        myPrevSolved = true;
+      }
+    } else if (!myConstraints.empty()) {
+//      Events_Error::send(SketchSolver_Error::CONSTRAINTS(), this);
+      getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue(SketchSolver_Error::CONSTRAINTS());
+      if (myPrevSolved) {
+        // the error message should be changed before sending the message
+        sendMessage(EVENT_SOLVER_FAILED);
+        myPrevSolved = false;
+      }
+    }
 
     aResolved = true;
   }
@@ -1425,9 +650,19 @@ void SketchSolver_Group::mergeGroups(const SketchSolver_Group& theGroup)
   if (!myFeatureStorage)
     myFeatureStorage = FeatureStoragePtr(new SketchSolver_FeatureStorage);
 
+  std::set<ObjectPtr> aConstraints;
   ConstraintConstraintMap::const_iterator aConstrIter = theGroup.myConstraints.begin();
   for (; aConstrIter != theGroup.myConstraints.end(); aConstrIter++)
-    changeConstraint(aConstrIter->first);
+    aConstraints.insert(aConstrIter->first);
+
+  std::list<FeaturePtr> aSortedConstraints = selectApplicableFeatures(aConstraints);
+  std::list<FeaturePtr>::iterator aSCIter = aSortedConstraints.begin();
+  for (; aSCIter != aSortedConstraints.end(); ++aSCIter) {
+    ConstraintPtr aConstr = std::dynamic_pointer_cast<SketchPlugin_Constraint>(*aSCIter);
+    if (!aConstr)
+      continue;
+    changeConstraint(aConstr);
+  }
 }
 
 // ============================================================================
@@ -1451,8 +686,20 @@ void SketchSolver_Group::splitGroup(std::vector<SketchSolver_Group*>& theCuts)
         anUnusedConstraints.push_back(*anIter);
   }
 
-  std::vector<SketchSolver_Group*>::iterator aCutsIter;
+  // Check the unused constraints once again, because they may become interacted with new storage since adding constraints
   std::vector<ConstraintPtr>::iterator aUnuseIt = anUnusedConstraints.begin();
+  while (aUnuseIt != anUnusedConstraints.end()) {
+    if (aNewFeatStorage->isInteract(*aUnuseIt)) {
+      aNewFeatStorage->changeConstraint(*aUnuseIt);
+      anUnusedConstraints.erase(aUnuseIt);
+      aUnuseIt = anUnusedConstraints.begin();
+      continue;
+    }
+    aUnuseIt++;
+  }
+
+  std::vector<SketchSolver_Group*>::iterator aCutsIter;
+  aUnuseIt = anUnusedConstraints.begin();
   for ( ; aUnuseIt != anUnusedConstraints.end(); aUnuseIt++) {
     // Remove unused constraints
     removeConstraint(*aUnuseIt);
@@ -1469,6 +716,9 @@ void SketchSolver_Group::splitGroup(std::vector<SketchSolver_Group*>& theCuts)
       theCuts.push_back(aGroup);
     }
   }
+
+  // Update feature storage
+  myFeatureStorage = aNewFeatStorage;
 }
 
 // ============================================================================
@@ -1484,181 +734,19 @@ bool SketchSolver_Group::isConsistent()
   bool aResult = myFeatureStorage->isConsistent();
   if (!aResult) {
     // remove invalid entities
+    std::set<ConstraintPtr> anInvalidConstraints;
     ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
-    while (aCIter != myConstraints.end()) {
-      std::list<ConstraintPtr> aConstraints = aCIter->second->constraints();
-      std::list<ConstraintPtr>::iterator anIt = aConstraints.begin();
-      for (; anIt != aConstraints.end(); anIt++)
-        if (!(*anIt)->data() || !(*anIt)->data()->isValid())
-          if (aCIter->second->remove(*anIt)) {
-            // the constraint is fully removed, detach it from the list
-            ConstraintConstraintMap::iterator aTmpIt = aCIter++;
-            myFeatureStorage->removeConstraint(aTmpIt->first);
-            myConstraints.erase(aTmpIt);
-            break;
-          }
-      if (anIt == aConstraints.end())
-        aCIter++;
+    for (; aCIter != myConstraints.end(); ++aCIter) {
+      if (!aCIter->first->data() || !aCIter->first->data()->isValid())
+        anInvalidConstraints.insert(aCIter->first);
     }
+    std::set<ConstraintPtr>::const_iterator aRemoveIt = anInvalidConstraints.begin();
+    for (; aRemoveIt != anInvalidConstraints.end(); ++aRemoveIt)
+      removeConstraint(*aRemoveIt);
   }
   return aResult;
 }
 
-////// ============================================================================
-//////  Function: updateAttribute
-//////  Class:    SketchSolver_Group
-//////  Purpose:  update features of sketch after resolving constraints
-////// ============================================================================
-////bool SketchSolver_Group::updateAttribute(
-////    std::shared_ptr<ModelAPI_Attribute> theAttribute, const Slvs_hEntity& theEntityID)
-////{
-////  // Search the position of the first parameter of the entity
-////  int anEntPos = Search(theEntityID, myEntities);
-////  int aFirstParamPos = Search(myEntities[anEntPos].param[0], myParams);
-////
-////  // Look over supported types of entities
-////
-////  // Point in 3D
-////  std::shared_ptr<GeomDataAPI_Point> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point>(
-////      theAttribute);
-////  if (aPoint) {
-////    if (fabs(aPoint->x() - myParams[aFirstParamPos].val) > tolerance
-////        || fabs(aPoint->y() - myParams[aFirstParamPos + 1].val) > tolerance
-////        || fabs(aPoint->z() - myParams[aFirstParamPos + 2].val) > tolerance) {
-////      aPoint->setValue(myParams[aFirstParamPos].val, myParams[aFirstParamPos + 1].val,
-////                       myParams[aFirstParamPos + 2].val);
-////      return true;
-////    }
-////    return false;
-////  }
-////
-////  // Point in 2D
-////  std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
-////      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
-////  if (aPoint2D) {
-////    if (fabs(aPoint2D->x() - myParams[aFirstParamPos].val) > tolerance
-////        || fabs(aPoint2D->y() - myParams[aFirstParamPos + 1].val) > tolerance) {
-////      aPoint2D->setValue(myParams[aFirstParamPos].val, myParams[aFirstParamPos + 1].val);
-////      return true;
-////    }
-////    return false;
-////  }
-////
-////  // Scalar value
-////  AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
-////  if (aScalar) {
-////    if (fabs(aScalar->value() - myParams[aFirstParamPos].val) > tolerance) {
-////      aScalar->setValue(myParams[aFirstParamPos].val);
-////      return true;
-////    }
-////    return false;
-////  }
-////
-////  /// \todo Support other types of entities
-////  return false;
-////}
-////
-////// ============================================================================
-//////  Function: updateEntityIfPossible
-//////  Class:    SketchSolver_Group
-//////  Purpose:  search the entity in this group and update it
-////// ============================================================================
-////void SketchSolver_Group::updateEntityIfPossible(
-////    std::shared_ptr<ModelAPI_Attribute> theEntity)
-////{
-////  if (myEntityAttrMap.find(theEntity) != myEntityAttrMap.end()) {
-////    // If the attribute is a point and it is changed (the group needs to rebuild),
-////    // probably user has dragged this point into this position,
-////    // so it is necessary to add constraint which will guarantee the point will not change
-////
-////    // Store myNeedToSolve flag to verify the entity is really changed
-////    bool aNeedToSolveCopy = myNeedToSolve;
-////    myNeedToSolve = false;
-////
-////    changeEntity(theEntity);
-////
-////    if (myNeedToSolve)  // the entity is changed
-////    {
-////      // Verify the entity is a point and add temporary constraint of permanency
-////      std::shared_ptr<GeomDataAPI_Point> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point>(
-////          theEntity);
-////      std::shared_ptr<GeomDataAPI_Point2D> aPoint2D = std::dynamic_pointer_cast<
-////          GeomDataAPI_Point2D>(theEntity);
-////      if (aPoint || aPoint2D)
-////        addTemporaryConstraintWhereDragged(theEntity);
-////    }
-////
-////    // Restore flag of changes
-////    myNeedToSolve = myNeedToSolve || aNeedToSolveCopy;
-////
-////    if (myNeedToSolve)
-////      updateRelatedConstraints(theEntity);
-////  }
-////}
-////
-////// ============================================================================
-//////  Function: addTemporaryConstraintWhereDragged
-//////  Class:    SketchSolver_Group
-//////  Purpose:  add transient constraint SLVS_C_WHERE_DRAGGED for the entity, 
-//////            which was moved by user
-////// ============================================================================
-////void SketchSolver_Group::addTemporaryConstraintWhereDragged(
-////    std::shared_ptr<ModelAPI_Attribute> theEntity,
-////    bool theAllowToFit)
-////{
-////  // Find identifier of the entity
-////  std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator anEntIter =
-////      myEntityAttrMap.find(theEntity);
-////  if (anEntIter == myEntityAttrMap.end())
-////    return;
-////
-////  // Get identifiers of all dragged points
-////  std::set<Slvs_hEntity> aDraggedPntID;
-////  aDraggedPntID.insert(myTempPointWDrgdID);
-////  std::list<Slvs_hConstraint>::const_iterator aTmpCoIter = myTempConstraints.begin();
-////  for (; aTmpCoIter != myTempConstraints.end(); aTmpCoIter++) {
-////    unsigned int aConstrPos = Search(*aTmpCoIter, myConstraints);
-////    if (aConstrPos < myConstraints.size())
-////      aDraggedPntID.insert(myConstraints[aConstrPos].ptA);
-////  }
-////  std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
-////  for (; aConstrIter != myConstraints.end(); aConstrIter++)
-////    if (aConstrIter->type == SLVS_C_WHERE_DRAGGED)
-////      aDraggedPntID.insert(aConstrIter->ptA);
-////  // Find whether there is a point coincident with theEntity, which already has SLVS_C_WHERE_DRAGGED
-////  std::vector<std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
-////  for (; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++) {
-////    if (aCoPtIter->find(anEntIter->second) == aCoPtIter->end())
-////      continue;  // the entity was not found in current set
-////
-////    // Find one of already created SLVS_C_WHERE_DRAGGED constraints in current set of coincident points
-////    std::set<Slvs_hEntity>::const_iterator aDrgIter = aDraggedPntID.begin();
-////    for (; aDrgIter != aDraggedPntID.end(); aDrgIter++)
-////      if (aCoPtIter->find(*aDrgIter) != aCoPtIter->end())
-////        return;  // the SLVS_C_WHERE_DRAGGED constraint already exists
-////  }
-////  if (aDraggedPntID.find(anEntIter->second) != aDraggedPntID.end())
-////    return;
-////
-////  // If this is a first dragged point, its parameters should be placed 
-////  // into Slvs_System::dragged field to avoid system inconsistense
-////  if (myTempPointWhereDragged.empty() && theAllowToFit) {
-////    int anEntPos = Search(anEntIter->second, myEntities);
-////    Slvs_hParam* aDraggedParam = myEntities[anEntPos].param;
-////    for (int i = 0; i < 4; i++, aDraggedParam++)
-////      if (*aDraggedParam != 0)
-////        myTempPointWhereDragged.push_back(*aDraggedParam);
-////    myTempPointWDrgdID = myEntities[anEntPos].h;
-////    return;
-////  }
-////
-////  // Create additional SLVS_C_WHERE_DRAGGED constraint if myTempPointWhereDragged field is not empty
-////  Slvs_Constraint aWDConstr = Slvs_MakeConstraint(++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED,
-////                                                  myWorkplane.h, 0.0, anEntIter->second, 0, 0, 0);
-////  myConstraints.push_back(aWDConstr);
-////  myTempConstraints.push_back(aWDConstr.h);
-////}
-
 // ============================================================================
 //  Function: removeTemporaryConstraints
 //  Class:    SketchSolver_Group
@@ -1667,12 +755,19 @@ bool SketchSolver_Group::isConsistent()
 // ============================================================================
 void SketchSolver_Group::removeTemporaryConstraints()
 {
+  std::set<SolverConstraintPtr>::iterator aTmpIt = myTempConstraints.begin();
+  for (; aTmpIt != myTempConstraints.end(); ++aTmpIt)
+    (*aTmpIt)->remove();
   myTempConstraints.clear();
+
+  while (myStorage->numberTemporary())
+    myStorage->deleteTemporaryConstraint();
   // Clean lists of removed entities in the storage
   std::set<Slvs_hParam> aRemPar;
   std::set<Slvs_hEntity> aRemEnt;
   std::set<Slvs_hConstraint> aRemCon;
   myStorage->getRemoved(aRemPar, aRemEnt, aRemCon);
+  myStorage->setNeedToResolve(false);
 }
 
 // ============================================================================
@@ -1682,300 +777,183 @@ void SketchSolver_Group::removeTemporaryConstraints()
 // ============================================================================
 void SketchSolver_Group::removeConstraint(ConstraintPtr theConstraint)
 {
+  bool isFullyRemoved = true;
   myFeatureStorage->removeConstraint(theConstraint);
   ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
   for (; aCIter != myConstraints.end(); aCIter++)
     if (aCIter->second->hasConstraint(theConstraint)) {
       if (!aCIter->second->remove(theConstraint)) // the constraint is not fully removed
-        aCIter = myConstraints.end();
+        isFullyRemoved = false;
       break;
     }
-  if (aCIter != myConstraints.end())
+  if (aCIter == myConstraints.end())
+    return;
+
+  // Remove entities not used by constraints
+  myStorage->removeUnusedEntities();
+
+  if (isFullyRemoved)
     myConstraints.erase(aCIter);
+  else if (aCIter != myConstraints.end() &&
+           aCIter->first->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
+    // Update multicoincidence
+    std::list<ConstraintPtr> aMultiCoinc;
+    SolverConstraintPtr aCoincidence = aCIter->second;
+    while (aCIter != myConstraints.end()) {
+      if (aCIter->second != aCoincidence) {
+        ++aCIter;
+        continue;
+      }
+      if (aCIter->first != theConstraint)
+        aMultiCoinc.push_back(aCIter->first);
+      aCIter->second->remove(aCIter->first);
+      ConstraintConstraintMap::iterator aRemoveIt = aCIter++;
+      myConstraints.erase(aRemoveIt);
+    }
+
+    std::list<ConstraintPtr>::iterator anIt = aMultiCoinc.begin();
+    for (; anIt != aMultiCoinc.end(); ++anIt)
+      changeConstraint(*anIt);
+
+    notifyMultiConstraints();
+  }
+}
+
+// ============================================================================
+//  Function: isComplexConstraint
+//  Class:    SketchSolver_Group
+//  Purpose:  verifies the constraint is complex, i.e. it needs another constraints to be created before
+// ============================================================================
+bool SketchSolver_Group::isComplexConstraint(FeaturePtr theConstraint)
+{
+  return theConstraint->getKind() == SketchPlugin_ConstraintFillet::ID() ||
+         theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID() ||
+         theConstraint->getKind() == SketchPlugin_ConstraintTangent::ID();
+}
+
+// ============================================================================
+//  Function: setTemporary
+//  Class:    SketchSolver_Group
+//  Purpose:  append given constraint to th group of temporary constraints
+// ============================================================================
+void SketchSolver_Group::setTemporary(SolverConstraintPtr theConstraint)
+{
+  theConstraint->makeTemporary();
+  myTempConstraints.insert(theConstraint);
 }
 
-////// ============================================================================
-//////  Function: removeEntitiesById
-//////  Class:    SketchSolver_Group
-//////  Purpose:  Removes specified entities and their parameters
-////// ============================================================================
-////void SketchSolver_Group::removeEntitiesById(const std::set<Slvs_hEntity>& theEntities)
-////{
-////  std::set<Slvs_hEntity>::const_reverse_iterator aRemIter = theEntities.rbegin();
-////  for (; aRemIter != theEntities.rend(); aRemIter++) {
-////    unsigned int anEntPos = Search(*aRemIter, myEntities);
-////    if (anEntPos >= myEntities.size())
-////      continue;
-////    if (myEntities[anEntPos].param[0] != 0) {
-////      unsigned int aParamPos = Search(myEntities[anEntPos].param[0], myParams);
-////      if (aParamPos >= myParams.size())
-////        continue;
-////      int aNbParams = 0;
-////      while (myEntities[anEntPos].param[aNbParams] != 0)
-////        aNbParams++;
-////      if (myEntities[anEntPos].param[aNbParams - 1] == myParamMaxID)
-////        myParamMaxID -= aNbParams;
-////      myParams.erase(myParams.begin() + aParamPos, myParams.begin() + aParamPos + aNbParams);
-////      if (*aRemIter == myEntityMaxID)
-////        myEntityMaxID--;
-////    }
-////    myEntities.erase(myEntities.begin() + anEntPos);
-////    myEntOfConstr.erase(myEntOfConstr.begin() + anEntPos);
-////
-////    // Remove entity's ID from the lists of conincident points
-////    std::vector<std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
-////    for (; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++)
-////      aCoPtIter->erase(*aRemIter);
-////  }
-////}
-////
-////// ============================================================================
-//////  Function: addCoincidentPoints
-//////  Class:    SketchSolver_Group
-//////  Purpose:  add coincident point the appropriate list of such points
-////// ============================================================================
-////bool SketchSolver_Group::addCoincidentPoints(const Slvs_hEntity& thePoint1,
-////                                                       const Slvs_hEntity& thePoint2)
-////{
-////  std::vector<std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
-////  std::vector<std::set<Slvs_hEntity> >::iterator aFirstFound = myCoincidentPoints.end();
-////  while (aCoPtIter != myCoincidentPoints.end()) {
-////    bool isFound[2] = {  // indicate which point ID was already in coincidence constraint
-////        aCoPtIter->find(thePoint1) != aCoPtIter->end(), aCoPtIter->find(thePoint2)
-////            != aCoPtIter->end(), };
-////    if (isFound[0] && isFound[1])  // points are already connected by coincidence constraints => no need additional one
-////      return false;
-////    if ((isFound[0] && !isFound[1]) || (!isFound[0] && isFound[1])) {
-////      if (aFirstFound != myCoincidentPoints.end()) {  // there are two groups of coincident points connected by created constraint => merge them
-////        int aFirstFoundShift = aFirstFound - myCoincidentPoints.begin();
-////        int aCurrentShift = aCoPtIter - myCoincidentPoints.begin();
-////        aFirstFound->insert(aCoPtIter->begin(), aCoPtIter->end());
-////        myCoincidentPoints.erase(aCoPtIter);
-////        aFirstFound = myCoincidentPoints.begin() + aFirstFoundShift;
-////        aCoPtIter = myCoincidentPoints.begin() + aCurrentShift;
-////        continue;
-////      } else {
-////        aCoPtIter->insert(isFound[0] ? thePoint2 : thePoint1);
-////        aFirstFound = aCoPtIter;
-////      }
-////    }
-////    aCoPtIter++;
-////  }
-////  // No points were found, need to create new set
-////  if (aFirstFound == myCoincidentPoints.end()) {
-////    std::set<Slvs_hEntity> aNewSet;
-////    aNewSet.insert(thePoint1);
-////    aNewSet.insert(thePoint2);
-////    myCoincidentPoints.push_back(aNewSet);
-////  }
-////
-////  return true;
-////}
-////
-////// ============================================================================
-//////  Function: updateRelatedConstraints
-//////  Class:    SketchSolver_Group
-//////  Purpose:  emit the signal to update constraints
-////// ============================================================================
-////void SketchSolver_Group::updateRelatedConstraints(
-////    std::shared_ptr<ModelAPI_Attribute> theEntity) const
-////{
-////  ConstraintMap::const_iterator aConstrIter = myConstraintMap.begin();
-////  for (; aConstrIter != myConstraintMap.end(); aConstrIter++) {
-////    std::list<std::shared_ptr<ModelAPI_Attribute> > anAttributes = aConstrIter->first->data()
-////        ->attributes(std::string());
-////
-////    std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttrIter = anAttributes.begin();
-////    for (; anAttrIter != anAttributes.end(); anAttrIter++) {
-////      bool isUpd = (*anAttrIter == theEntity);
-////      std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr = std::dynamic_pointer_cast<
-////          ModelAPI_AttributeRefAttr>(*anAttrIter);
-////      if (aRefAttr && !aRefAttr->isObject() && aRefAttr->attr() == theEntity)
-////        isUpd = true;
-////
-////      if (isUpd) {
-////        static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
-////        ModelAPI_EventCreator::get()->sendUpdated(aConstrIter->first, anEvent);
-////        break;
-////      }
-////    }
-////  }
-////}
-////
-////void SketchSolver_Group::updateRelatedConstraintsFeature(
-////    std::shared_ptr<ModelAPI_Feature> theFeature) const
-////{
-////  ConstraintMap::const_iterator aConstrIter = myConstraintMap.begin();
-////  for (; aConstrIter != myConstraintMap.end(); aConstrIter++) {
-////    std::list<std::shared_ptr<ModelAPI_Attribute> > anAttributes = aConstrIter->first->data()
-////        ->attributes(std::string());
-////
-////    std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttrIter = anAttributes.begin();
-////    for (; anAttrIter != anAttributes.end(); anAttrIter++) {
-////      std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr = std::dynamic_pointer_cast<
-////          ModelAPI_AttributeRefAttr>(*anAttrIter);
-////      if (aRefAttr && aRefAttr->isObject() && aRefAttr->object() == theFeature) {
-////        static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
-////        ModelAPI_EventCreator::get()->sendUpdated(aConstrIter->first, anEvent);
-////        break;
-////      }
-////    }
-////  }
-////}
-////
-////// ============================================================================
-//////  Function: updateFilletConstraints
-//////  Class:    SketchSolver_Group
-//////  Purpose:  change fillet arc to be less than 180 degree
-////// ============================================================================
-////void SketchSolver_Group::updateFilletConstraints()
-////{
-////  ConstraintMap::const_iterator aConstrIter = myConstraintMap.begin();
-////  for (; aConstrIter != myConstraintMap.end(); aConstrIter++)
-////    if (aConstrIter->first->getKind() == SketchPlugin_ConstraintFillet::ID()) {
-////      AttributeRefListPtr aFilletRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
-////          aConstrIter->first->data()->attribute(SketchPlugin_ConstraintFillet::ENTITY_C()));
-////      if (!aFilletRefList)
-////        return;
-////      ObjectPtr anArcObj = aFilletRefList->object(2);
-////      std::shared_ptr<GeomDataAPI_Point2D> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-////          anArcObj->data()->attribute(SketchPlugin_Arc::CENTER_ID()));
-////      std::shared_ptr<GeomDataAPI_Point2D> aStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-////          anArcObj->data()->attribute(SketchPlugin_Arc::START_ID()));
-////      std::shared_ptr<GeomDataAPI_Point2D> aEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-////          anArcObj->data()->attribute(SketchPlugin_Arc::END_ID()));
-////      double aCosA = aStart->x() - aCenter->x();
-////      double aSinA = aStart->y() - aCenter->y();
-////      double aCosB = aEnd->x() - aCenter->x();
-////      double aSinB = aEnd->y() - aCenter->y();
-////      if (aCosA * aSinB - aSinA * aCosB <= 0.0) {
-////        anArcObj->data()->blockSendAttributeUpdated(true);
-////        double x = aStart->x();
-////        double y = aStart->y();
-////        aStart->setValue(aEnd->x(), aEnd->y());
-////        aEnd->setValue(x, y);
-////        // Update constraint data
-////        changeFilletConstraint(aConstrIter->first);
-////        anArcObj->data()->blockSendAttributeUpdated(false);
-////      }
-////    }
-////}
-////
-////// ============================================================================
-//////  Function: makeMirrorEntity
-//////  Class:    SketchSolver_Group
-//////  Purpose:  change entities parameters to make them symmetric relating to the mirror line
-////// ============================================================================
-////void SketchSolver_Group::makeMirrorEntity(const Slvs_hEntity& theBase,
-////                                                    const Slvs_hEntity& theMirror,
-////                                                    const Slvs_hEntity& theMirrorLine)
-////{
-////  Slvs_Entity aBase = myEntities[Search(theBase, myEntities)];
-////  Slvs_Entity aMirror = myEntities[Search(theMirror, myEntities)];
-////  int i = 0;
-////  while (aBase.point[i] != 0 && aMirror.point[i] != 0) {
-////    makeMirrorEntity(aBase.point[i], aMirror.point[i], theMirrorLine);
-////    i++;
-////  }
-////  if (aBase.param[0] != 0 && aMirror.param[0] != 0) { // this is a point, copy it
-////    Slvs_Entity aMirrorLine = myEntities[Search(theMirrorLine, myEntities)];
-////    std::shared_ptr<GeomAPI_XY> aLinePoints[2];
-////    for (i = 0; i < 2; i++) {
-////      Slvs_Entity aPoint = myEntities[Search(aMirrorLine.point[i], myEntities)];
-////      int aParamPos = Search(aPoint.param[0], myParams);
-////      aLinePoints[i] = std::shared_ptr<GeomAPI_XY>(
-////          new GeomAPI_XY(myParams[aParamPos].val, myParams[1+aParamPos].val));
-////    }
-////    int aBaseParamPos = Search(aBase.param[0], myParams);
-////    int aMirrorParamPos = Search(aMirror.param[0], myParams);
-////    std::shared_ptr<GeomAPI_XY> aPoint = std::shared_ptr<GeomAPI_XY>(
-////        new GeomAPI_XY(myParams[aBaseParamPos].val, myParams[1+aBaseParamPos].val));
-////
-////    // direction of a mirror line
-////    std::shared_ptr<GeomAPI_Dir2d> aDir = std::shared_ptr<GeomAPI_Dir2d>(
-////        new GeomAPI_Dir2d(aLinePoints[1]->added(aLinePoints[0]->multiplied(-1.0))));
-////    // orthogonal direction
-////    aDir = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(aDir->y(), -aDir->x()));
-////
-////    std::shared_ptr<GeomAPI_XY> aVec = std::shared_ptr<GeomAPI_XY>(
-////        new GeomAPI_XY(aPoint->x() - aLinePoints[0]->x(), aPoint->y() - aLinePoints[0]->y()));
-////    double aDist = aVec->dot(aDir->xy());
-////    std::shared_ptr<GeomAPI_XY> aMirrorPoint = aPoint->added(aDir->xy()->multiplied(-2.0 * aDist));
-////
-////    myParams[aMirrorParamPos].val = aMirrorPoint->x();
-////    myParams[1+aMirrorParamPos].val = aMirrorPoint->y();
-////  }
-////}
-////
-////// ============================================================================
-//////  Function: calculateMiddlePoint
-//////  Class:    SketchSolver_Group
-//////  Purpose:  calculates middle point on line or arc
-////// ============================================================================
-////void SketchSolver_Group::calculateMiddlePoint(
-////    const Slvs_hEntity& theEntity,
-////    double& theX,
-////    double& theY) const
-////{
-////  int anInd = Search(theEntity, myEntities);
-////  if (myEntities[anInd].type == SLVS_E_LINE_SEGMENT) {
-////    int aLineParams[2];
-////    for (int i = 0; i < 2; i++) {
-////      int aPtPos = Search(myEntities[anInd].point[i], myEntities);
-////      aLineParams[i] = Search(myEntities[aPtPos].param[0], myParams);
-////    }
-////    theX = 0.5 * (myParams[aLineParams[0]].val + myParams[aLineParams[1]].val);
-////    theY = 0.5 * (myParams[1 + aLineParams[0]].val + myParams[1 + aLineParams[1]].val);
-////  } else if (myEntities[anInd].type == SLVS_E_ARC_OF_CIRCLE) {
-////    double anArcPoint[3][2];
-////    for (int i = 0; i < 3; i++) {
-////      int aPtPos = Search(myEntities[anInd].point[i], myEntities);
-////      int anArcParam = Search(myEntities[aPtPos].param[0], myParams);
-////      anArcPoint[i][0] = myParams[anArcParam].val;
-////      anArcPoint[i][1] = myParams[1 + anArcParam].val;
-////    }
-////    // project last point of arc on the arc
-////    double x = anArcPoint[1][0] - anArcPoint[0][0];
-////    double y = anArcPoint[1][1] - anArcPoint[0][1];
-////    double aRad = sqrt(x*x + y*y);
-////    x = anArcPoint[2][0] - anArcPoint[0][0];
-////    y = anArcPoint[2][1] - anArcPoint[0][1];
-////    double aNorm = sqrt(x*x + y*y);
-////    if (aNorm >= tolerance) {
-////      anArcPoint[2][0] = anArcPoint[0][0] + x * aRad / aNorm;
-////      anArcPoint[2][1] = anArcPoint[0][1] + y * aRad / aNorm;
-////    }
-////
-////    x = anArcPoint[1][0] + anArcPoint[2][0] - 2.0 * anArcPoint[0][0];
-////    y = anArcPoint[1][1] + anArcPoint[2][1] - 2.0 * anArcPoint[0][1];
-////    aNorm = sqrt(x*x + y*y);
-////    if (aNorm >= tolerance) {
-////      x *= aRad / aNorm;
-////      y *= aRad / aNorm;
-////    } else { // obtain orthogonal direction
-////      x = 0.5 * (anArcPoint[2][1] - anArcPoint[1][1]);
-////      y = -0.5 * (anArcPoint[2][0] - anArcPoint[1][0]);
-////    }
-////    theX = anArcPoint[0][0] + x;
-////    theY = anArcPoint[0][1] + y;
-////  }
-////}
 
+// ============================================================================
+//  Function: checkFeatureValidity
+//  Class:    SketchSolver_Group
+//  Purpose:  verifies is the feature valid
+// ============================================================================
+bool SketchSolver_Group::checkFeatureValidity(FeaturePtr theFeature)
+{
+  if (!theFeature || !theFeature->data()->isValid())
+    return true;
 
-// ========================================================
-// =========      Auxiliary functions       ===============
-// ========================================================
+  SessionPtr aMgr = ModelAPI_Session::get();
+  ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
+  return aFactory->validate(theFeature);
+}
+
+// ============================================================================
+//  Function: notifyMultiConstraints
+//  Class:    SketchSolver_Group
+//  Purpose:  Update Multi-Translation/-Rotation constraints due to multi coincidence appears/disappears
+// ============================================================================
+void SketchSolver_Group::notifyMultiConstraints()
+{
+  ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
+  for (; aCIter != myConstraints.end(); ++aCIter) {
+    if (aCIter->first->getKind() == SketchPlugin_MultiRotation::ID() ||
+        aCIter->first->getKind() == SketchPlugin_MultiTranslation::ID()) {
+      std::shared_ptr<SketchSolver_ConstraintMulti> aMulti = 
+          std::dynamic_pointer_cast<SketchSolver_ConstraintMulti>(aCIter->second);
+      aMulti->checkCoincidence();
+    }
+  }
+}
+
+
+
+
+// ===========   Auxiliary functions   ========================================
+static double featureToVal(FeaturePtr theFeature)
+{
+  if (theFeature->getKind() == SketchPlugin_Sketch::ID())
+    return 0.0; // sketch
+  ConstraintPtr aConstraint = std::dynamic_pointer_cast<SketchPlugin_Constraint>(theFeature);
+  if (!aConstraint)
+    return 1.0; // features (arc, circle, line, point)
+
+  const std::string& anID = aConstraint->getKind();
+  if (anID == SketchPlugin_ConstraintCoincidence::ID()) {
+    AttributeRefAttrPtr anAttrA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+        aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
+    AttributeRefAttrPtr anAttrB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+        aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
+    if (anAttrA && anAttrB && (anAttrA->isObject() || anAttrB->isObject()))
+      return 2.0; // point-on-line and point-on-circle should go before points coincidence constraint
+    return 2.5;
+  }
+  if (anID == SketchPlugin_ConstraintDistance::ID() ||
+      anID == SketchPlugin_ConstraintLength::ID() ||
+      anID == SketchPlugin_ConstraintRadius::ID())
+    return 3.0;
+  if (anID == SketchPlugin_ConstraintAngle::ID())
+    return 3.5;
+  if (anID == SketchPlugin_ConstraintHorizontal::ID() ||
+      anID == SketchPlugin_ConstraintVertical::ID() ||
+      anID == SketchPlugin_ConstraintParallel::ID() ||
+      anID == SketchPlugin_ConstraintPerpendicular::ID())
+    return 4.0;
+  if (anID == SketchPlugin_ConstraintEqual::ID())
+    return 5.0;
+  if (anID == SketchPlugin_ConstraintTangent::ID() ||
+      anID == SketchPlugin_ConstraintMirror::ID())
+    return 6.0;
+  if (anID == SketchPlugin_ConstraintRigid::ID())
+    return 7.0;
+  if (anID == SketchPlugin_MultiRotation::ID() ||
+      anID == SketchPlugin_MultiTranslation::ID())
+    return 8.0;
+
+  // all other constraints are placed between Equal and Tangent constraints
+  return 5.5;
+}
 
-template<typename T>
-int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities)
+static bool isLess(FeaturePtr theFeature1, FeaturePtr theFeature2)
 {
-  int aResIndex = theEntityID <= theEntities.size() ? theEntityID - 1 : 0;
-  int aVecSize = theEntities.size();
-  while (aResIndex >= 0 && theEntities[aResIndex].h > theEntityID)
-    aResIndex--;
-  while (aResIndex < aVecSize && aResIndex >= 0 && theEntities[aResIndex].h < theEntityID)
-    aResIndex++;
-  if (aResIndex == -1)
-    aResIndex = aVecSize;
-  return aResIndex;
+  return featureToVal(theFeature1) < featureToVal(theFeature2);
 }
+
+std::list<FeaturePtr> SketchSolver_Group::selectApplicableFeatures(const std::set<ObjectPtr>& theObjects)
+{
+  std::list<FeaturePtr> aResult;
+  std::list<FeaturePtr>::iterator aResIt;
+
+  std::set<ObjectPtr>::const_iterator anObjIter = theObjects.begin();
+  for (; anObjIter != theObjects.end(); ++anObjIter) {
+    // Operate sketch itself and SketchPlugin features only.
+    // Also, the Fillet need to be skipped, because there are several separated constraints composing it.
+    FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*anObjIter);
+    if (!aFeature)
+      continue;
+    std::shared_ptr<SketchPlugin_Feature> aSketchFeature = 
+        std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
+    if ((aFeature->getKind() != SketchPlugin_Sketch::ID() && !aSketchFeature) ||
+        aFeature->getKind() == SketchPlugin_ConstraintFillet::ID())
+      continue;
+
+    // Find the place where to insert a feature
+    for (aResIt = aResult.begin(); aResIt != aResult.end(); ++aResIt)
+      if (isLess(aFeature, *aResIt))
+        break;
+    aResult.insert(aResIt, aFeature);
+  }
+
+  return aResult;
+}
+