Salome HOME
Fix compilation problems
[modules/shaper.git] / src / SketchSolver / SketchSolver_ConstraintManager.cpp
index 68bc58b3c9e31a5cb3a6b4f8601410837438c354..dba0d550c36942d1b7a8bb3e304db6a255347016 100644 (file)
@@ -12,6 +12,7 @@
 #include <ModelAPI_AttributeRefList.h>
 #include <ModelAPI_Data.h>
 #include <Model_Events.h>
+
 #include <SketchPlugin_Constraint.h>
 #include <SketchPlugin_ConstraintCoincidence.h>
 #include <SketchPlugin_Line.h>
@@ -19,6 +20,9 @@
 #include <SketchPlugin_Sketch.h>
 
 #include <math.h>
+#include <assert.h>
+
+#include <set>
 
 /// Tolerance for value of parameters
 const double tolerance = 1.e-10;
@@ -26,7 +30,7 @@ const double tolerance = 1.e-10;
 // Initialization of constraint manager self pointer
 SketchSolver_ConstraintManager* SketchSolver_ConstraintManager::_self = 0;
 
-/// Global constaint manager object
+/// Global constraint manager object
 SketchSolver_ConstraintManager* myManager = SketchSolver_ConstraintManager::Instance();
 
 /// This value is used to give unique index to the groups
@@ -60,6 +64,7 @@ SketchSolver_ConstraintManager::SketchSolver_ConstraintManager()
   Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_CREATED));
   Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_UPDATED));
   Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_DELETED));
+  Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_FEATURES_MOVED));
 }
 
 SketchSolver_ConstraintManager::~SketchSolver_ConstraintManager()
@@ -70,48 +75,75 @@ SketchSolver_ConstraintManager::~SketchSolver_ConstraintManager()
 void SketchSolver_ConstraintManager::processEvent(const Events_Message* theMessage)
 {
   if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_CREATED) ||
-      theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_UPDATED))
+      theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_UPDATED) || 
+      theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURES_MOVED))
   {
-    const Model_FeatureUpdatedMessage* aUpdateMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
+    const Model_FeatureUpdatedMessage* anUpdateMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
+    std::set< boost::shared_ptr<ModelAPI_Feature> > aFeatures = anUpdateMsg->features();
 
-    // Only sketches and constraints can be added by Create event
-    boost::shared_ptr<SketchPlugin_Sketch> aSketch = 
-      boost::dynamic_pointer_cast<SketchPlugin_Sketch>(aUpdateMsg->feature());
-    if (aSketch)
+    bool isModifiedEvt = theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURES_MOVED);
+    if (!isModifiedEvt)
     {
-      changeWorkplane(aSketch);
-      return ;
-    }
-    boost::shared_ptr<SketchPlugin_Constraint> aConstraint = 
-      boost::dynamic_pointer_cast<SketchPlugin_Constraint>(aUpdateMsg->feature());
-    if (aConstraint)
-    {
-      changeConstraint(aConstraint);
-
-      // Solve the set of constraints
-      ResolveConstraints();
-      return ;
+      std::set< boost::shared_ptr<ModelAPI_Feature> >::iterator aFeatIter;
+      for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++)
+      {
+        // Only sketches and constraints can be added by Create event
+        const std::string& aFeatureKind = (*aFeatIter)->getKind();
+        if (aFeatureKind.compare("Sketch") == 0)
+        {
+          boost::shared_ptr<SketchPlugin_Feature> aSketch =
+            boost::dynamic_pointer_cast<SketchPlugin_Feature>(*aFeatIter);
+          changeWorkplane(aSketch);
+          return ;
+        }
+        boost::shared_ptr<SketchPlugin_Constraint> aConstraint =
+          boost::dynamic_pointer_cast<SketchPlugin_Constraint>(*aFeatIter);
+        if (aConstraint)
+          changeConstraint(aConstraint);
+        else
+        {
+          // Sketch plugin features can be only updated
+          boost::shared_ptr<SketchPlugin_Feature> aFeature =
+            boost::dynamic_pointer_cast<SketchPlugin_Feature>(*aFeatIter);
+          if (aFeature)
+            updateEntity(aFeature);
+        }
+      }
     }
 
-    /// \todo Implement feature update handling
-    boost::shared_ptr<SketchPlugin_Feature> aFeature = 
-      boost::dynamic_pointer_cast<SketchPlugin_Feature>(aUpdateMsg->feature());
-    if (aFeature)
-    {
-      updateEntity(aFeature);
-
-      // Solve the set of constraints
-      ResolveConstraints();
-    }
+    // Solve the set of constraints
+    resolveConstraints(isModifiedEvt);
   }
   else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_DELETED))
   {
     const Model_FeatureDeletedMessage* aDeleteMsg = dynamic_cast<const Model_FeatureDeletedMessage*>(theMessage);
-    /// \todo Implement deleting objects on event
+    const std::set<std::string>& aFeatureGroups = aDeleteMsg->groups();
+
+    // Find "Sketch" in groups. The constraint groups should be updated when an object removed from Sketch
+    std::set<std::string>::const_iterator aFGrIter;
+    for (aFGrIter = aFeatureGroups.begin(); aFGrIter != aFeatureGroups.end(); aFGrIter++)
+      if (aFGrIter->compare("Sketch") == 0)
+        break;
+    
+    if (aFGrIter != aFeatureGroups.end())
+    {
+      std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter = myGroups.begin();
+      while (aGroupIter != myGroups.end())
+      {
+        if ((*aGroupIter)->updateGroup())
+        { // the group should be removed
+          delete *aGroupIter;
+          int aShift = aGroupIter - myGroups.begin();
+          myGroups.erase(aGroupIter);
+          aGroupIter = myGroups.begin() + aShift;
+        }
+        else aGroupIter++;
+      }
+    }
   }
 }
 
-bool SketchSolver_ConstraintManager::changeWorkplane(boost::shared_ptr<SketchPlugin_Sketch> theSketch)
+bool SketchSolver_ConstraintManager::changeWorkplane(boost::shared_ptr<SketchPlugin_Feature> theSketch)
 {
   bool aResult = true; // changed when a workplane wrongly updated
   bool isUpdated = false;
@@ -149,7 +181,7 @@ bool SketchSolver_ConstraintManager::changeConstraint(
   // Process the groups list
   if (aGroups.size() == 0)
   { // There are no groups applicable for this constraint => create new one
-    boost::shared_ptr<SketchPlugin_Sketch> aWP = findWorkplaneForConstraint(theConstraint);
+    boost::shared_ptr<SketchPlugin_Feature> aWP = findWorkplaneForConstraint(theConstraint);
     if (!aWP) return false;
     SketchSolver_ConstraintGroup* aGroup = new SketchSolver_ConstraintGroup(aWP);
     if (!aGroup->changeConstraint(theConstraint))
@@ -181,15 +213,12 @@ void SketchSolver_ConstraintManager::updateEntity(boost::shared_ptr<SketchPlugin
 {
   // Create list of attributes depending on type of the feature
   std::vector<std::string> anAttrList;
+  const std::string& aFeatureKind = theFeature->getKind();
   // Point
-  boost::shared_ptr<SketchPlugin_Point> aPoint = 
-    boost::dynamic_pointer_cast<SketchPlugin_Point>(theFeature);
-  if (aPoint)
+  if (aFeatureKind.compare("SketchPoint") == 0)
     anAttrList.push_back(POINT_ATTR_COORD);
   // Line
-  boost::shared_ptr<SketchPlugin_Line> aLine = 
-    boost::dynamic_pointer_cast<SketchPlugin_Line>(theFeature);
-  if (aLine)
+  else if (aFeatureKind.compare("SketchLine") == 0)
   {
     anAttrList.push_back(LINE_ATTR_START);
     anAttrList.push_back(LINE_ATTR_END);
@@ -203,7 +232,7 @@ void SketchSolver_ConstraintManager::updateEntity(boost::shared_ptr<SketchPlugin
     std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
     for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
     {
-      boost::shared_ptr<ModelAPI_Attribute> anAttribute = 
+      boost::shared_ptr<ModelAPI_Attribute> anAttribute =
         boost::dynamic_pointer_cast<ModelAPI_Attribute>(theFeature->data()->attribute(*anAttrIter));
       (*aGroupIter)->updateEntityIfPossible(anAttribute);
     }
@@ -212,10 +241,10 @@ void SketchSolver_ConstraintManager::updateEntity(boost::shared_ptr<SketchPlugin
 
 
 void SketchSolver_ConstraintManager::findGroups(
-              boost::shared_ptr<SketchPlugin_Constraint> theConstraint, 
+              boost::shared_ptr<SketchPlugin_Constraint> theConstraint,
               std::vector<Slvs_hGroup>&                  theGroupIDs) const
 {
-  boost::shared_ptr<SketchPlugin_Sketch> aWP = findWorkplaneForConstraint(theConstraint);
+  boost::shared_ptr<SketchPlugin_Feature> aWP = findWorkplaneForConstraint(theConstraint);
 
   std::vector<SketchSolver_ConstraintGroup*>::const_iterator aGroupIter;
   for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
@@ -223,30 +252,41 @@ void SketchSolver_ConstraintManager::findGroups(
       theGroupIDs.push_back((*aGroupIter)->getId());
 }
 
-boost::shared_ptr<SketchPlugin_Sketch> SketchSolver_ConstraintManager::findWorkplaneForConstraint(
+boost::shared_ptr<SketchPlugin_Feature> SketchSolver_ConstraintManager::findWorkplaneForConstraint(
               boost::shared_ptr<SketchPlugin_Constraint> theConstraint) const
 {
+  // Already verified workplanes
+  std::set< boost::shared_ptr<SketchPlugin_Feature> > aVerified;
+
   std::vector<SketchSolver_ConstraintGroup*>::const_iterator aGroupIter;
   for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
   {
-    boost::shared_ptr<SketchPlugin_Sketch> aWP = (*aGroupIter)->getWorkplane();
-    boost::shared_ptr<ModelAPI_AttributeRefList> aWPFeatures = 
+    boost::shared_ptr<SketchPlugin_Feature> aWP = (*aGroupIter)->getWorkplane();
+    if (aVerified.find(aWP) != aVerified.end())
+      continue;
+
+    boost::shared_ptr<ModelAPI_AttributeRefList> aWPFeatures =
       boost::dynamic_pointer_cast<ModelAPI_AttributeRefList>(aWP->data()->attribute(SKETCH_ATTR_FEATURES));
     std::list< boost::shared_ptr<ModelAPI_Feature> > aFeaturesList = aWPFeatures->list();
     std::list< boost::shared_ptr<ModelAPI_Feature> >::const_iterator anIter;
     for (anIter = aFeaturesList.begin(); anIter != aFeaturesList.end(); anIter++)
       if (*anIter == theConstraint)
         return aWP; // workplane is found
+    aVerified.insert(aWP);
   }
 
-  return boost::shared_ptr<SketchPlugin_Sketch>();
+  return boost::shared_ptr<SketchPlugin_Feature>();
 }
 
-void SketchSolver_ConstraintManager::ResolveConstraints()
+void SketchSolver_ConstraintManager::resolveConstraints(const bool needEvent)
 {
-  std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter; 
+  std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
   for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
-    (*aGroupIter)->ResolveConstraints();
+    (*aGroupIter)->resolveConstraints();
+
+  // Features may be updated => send events
+  if (needEvent)
+    Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_FEATURE_UPDATED));
 }
 
 
@@ -256,7 +296,7 @@ void SketchSolver_ConstraintManager::ResolveConstraints()
 // ========================================================
 
 SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::
-  SketchSolver_ConstraintGroup(boost::shared_ptr<SketchPlugin_Sketch> theWorkplane)
+  SketchSolver_ConstraintGroup(boost::shared_ptr<SketchPlugin_Feature> theWorkplane)
   : myID(++myGroupIndexer),
     myParamMaxID(0),
     myEntityMaxID(0),
@@ -271,7 +311,7 @@ SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::
 
   // Initialize workplane
   myWorkplane.h = SLVS_E_UNKNOWN;
-  addWorkplane(theWorkplane);
+  assert(addWorkplane(theWorkplane));
 }
 
 SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::~SketchSolver_ConstraintGroup()
@@ -280,10 +320,14 @@ SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::~SketchSolver_Cons
   myEntities.clear();
   myConstraints.clear();
   myConstraintMap.clear();
+
+  // If the group with maximal identifier is deleted, decrease the indexer
+  if (myID == myGroupIndexer)
+    myGroupIndexer--;
 }
 
 bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::isBaseWorkplane(
-                boost::shared_ptr<SketchPlugin_Sketch> theWorkplane) const
+                boost::shared_ptr<SketchPlugin_Feature> theWorkplane) const
 {
   return theWorkplane == mySketch;
 }
@@ -295,7 +339,19 @@ bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::isInteract(
   if (myWorkplane.h != SLVS_E_UNKNOWN && myConstraints.empty())
     return true;
 
-  /// \todo Should be implemented
+  // Go through constraint entities and verify if some of them already in the group
+  for (int i = 0; i < CONSTRAINT_ATTR_SIZE; i++)
+  {
+    boost::shared_ptr<ModelAPI_AttributeRefAttr> aCAttrRef =
+      boost::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+        theConstraint->data()->attribute(CONSTRAINT_ATTRIBUTES[i])
+      );
+    if (!aCAttrRef) continue;
+    if (myEntityMap.find(aCAttrRef->attr()) != myEntityMap.end())
+      return true;
+  }
+
+  // Entities did not found
   return false;
 }
 
@@ -318,7 +374,7 @@ bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::changeConstra
 
   // Get constraint type and verify the constraint parameters are correct
   int aConstrType = getConstraintType(theConstraint);
-  if (aConstrType == SLVS_C_UNKNOWN || 
+  if (aConstrType == SLVS_C_UNKNOWN ||
      (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType))
     return false;
 
@@ -329,7 +385,7 @@ bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::changeConstra
   if (aDistAttr)
   {
     aDistance = aDistAttr->value();
-    if (aConstrMapIter != myConstraintMap.end() && aConstrIter->valA != aDistance)
+    if (aConstrMapIter != myConstraintMap.end() && fabs(aConstrIter->valA - aDistance) > tolerance)
     {
       myNeedToSolve = true;
       aConstrIter->valA = aDistance;
@@ -340,7 +396,7 @@ bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::changeConstra
   for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++)
   {
     aConstrEnt[indAttr] = SLVS_E_UNKNOWN;
-    boost::shared_ptr<ModelAPI_AttributeRefAttr> aConstrAttr = 
+    boost::shared_ptr<ModelAPI_AttributeRefAttr> aConstrAttr =
       boost::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
         theConstraint->data()->attribute(CONSTRAINT_ATTRIBUTES[indAttr])
       );
@@ -351,8 +407,8 @@ bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::changeConstra
   if (aConstrMapIter == myConstraintMap.end())
   {
     // Create SolveSpace constraint structure
-    Slvs_Constraint aConstraint = 
-      Slvs_MakeConstraint(++myConstrMaxID, myID, aConstrType, myWorkplane.h, 
+    Slvs_Constraint aConstraint =
+      Slvs_MakeConstraint(++myConstrMaxID, myID, aConstrType, myWorkplane.h,
                           aDistance, aConstrEnt[0], aConstrEnt[1], aConstrEnt[2], aConstrEnt[3]);
     myConstraints.push_back(aConstraint);
     myConstraintMap[theConstraint] = aConstraint.h;
@@ -379,7 +435,7 @@ Slvs_hEntity SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::chang
   // Look over supported types of entities
 
   // Point in 3D
-  boost::shared_ptr<GeomDataAPI_Point> aPoint = 
+  boost::shared_ptr<GeomDataAPI_Point> aPoint =
     boost::dynamic_pointer_cast<GeomDataAPI_Point>(theEntity);
   if (aPoint)
   {
@@ -398,7 +454,7 @@ Slvs_hEntity SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::chang
   }
 
   // Point in 2D
-  boost::shared_ptr<GeomDataAPI_Point2D> aPoint2D = 
+  boost::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
     boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(theEntity);
   if (aPoint2D)
   {
@@ -419,29 +475,29 @@ Slvs_hEntity SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::chang
   }
 
   /// \todo Other types of entities
-  
+
   // Unsupported or wrong entity type
   return SLVS_E_UNKNOWN;
 }
 
 Slvs_hEntity SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::changeNormal(
-                boost::shared_ptr<ModelAPI_Attribute> theDirX, 
-                boost::shared_ptr<ModelAPI_Attribute> theDirY, 
+                boost::shared_ptr<ModelAPI_Attribute> theDirX,
+                boost::shared_ptr<ModelAPI_Attribute> theDirY,
                 boost::shared_ptr<ModelAPI_Attribute> theNorm)
 {
-  boost::shared_ptr<GeomDataAPI_Dir> aDirX = 
+  boost::shared_ptr<GeomDataAPI_Dir> aDirX =
     boost::dynamic_pointer_cast<GeomDataAPI_Dir>(theDirX);
-  boost::shared_ptr<GeomDataAPI_Dir> aDirY = 
+  boost::shared_ptr<GeomDataAPI_Dir> aDirY =
     boost::dynamic_pointer_cast<GeomDataAPI_Dir>(theDirY);
-  if (!aDirX || !aDirY || 
+  if (!aDirX || !aDirY ||
      (fabs(aDirX->x()) + fabs(aDirX->y()) + fabs(aDirX->z()) < tolerance) ||
      (fabs(aDirY->x()) + fabs(aDirY->y()) + fabs(aDirY->z()) < tolerance))
     return SLVS_E_UNKNOWN;
 
   // quaternion parameters of normal vector
   double qw, qx, qy, qz;
-  Slvs_MakeQuaternion(aDirX->x(), aDirX->y(), aDirX->z(), 
-                      aDirY->x(), aDirY->y(), aDirY->z(), 
+  Slvs_MakeQuaternion(aDirX->x(), aDirX->y(), aDirX->z(),
+                      aDirY->x(), aDirY->y(), aDirY->z(),
                       &qw, &qx, &qy, &qz);
   double aNormCoord[4] = {qw, qx, qy, qz};
 
@@ -467,7 +523,7 @@ Slvs_hEntity SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::chang
     return aEntIter->second;
 
   // Create a normal
-  Slvs_Entity aNormal = Slvs_MakeNormal3d(++myEntityMaxID, myID, 
+  Slvs_Entity aNormal = Slvs_MakeNormal3d(++myEntityMaxID, myID,
                 aNormParams[0], aNormParams[1], aNormParams[2], aNormParams[3]);
   myEntities.push_back(aNormal);
   myEntityMap[theNorm] = aNormal.h;
@@ -476,13 +532,14 @@ Slvs_hEntity SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::chang
 
 
 bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::addWorkplane(
-                boost::shared_ptr<SketchPlugin_Sketch> theSketch)
+                boost::shared_ptr<SketchPlugin_Feature> theSketch)
 {
-  if (myWorkplane.h)
-    return false; // the workplane already exists
+  if (myWorkplane.h || theSketch->getKind().compare("Sketch") != 0)
+    return false; // the workplane already exists or the function parameter is not Sketch
 
   mySketch = theSketch;
-  return updateWorkplane();
+  updateWorkplane();
+  return true;
 }
 
 bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::updateWorkplane()
@@ -510,15 +567,17 @@ bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::updateWorkpla
 
 
 Slvs_hParam SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::changeParameter(
-                const double&                            theParam, 
+                const double&                            theParam,
                 std::vector<Slvs_Param>::const_iterator& thePrmIter)
 {
   if (thePrmIter != myParams.end())
   { // Parameter should be updated
-    if (thePrmIter->val != theParam)
-      myNeedToSolve = true; // parameter is changed, need to resolve constraints
     int aParamPos = thePrmIter - myParams.begin();
-    myParams[aParamPos].val = theParam;
+    if (fabs(thePrmIter->val - theParam) > tolerance)
+    {
+      myNeedToSolve = true; // parameter is changed, need to resolve constraints
+      myParams[aParamPos].val = theParam;
+    }
     thePrmIter++;
     return myParams[aParamPos].h;
   }
@@ -535,23 +594,22 @@ Slvs_hParam SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::change
 int SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::getConstraintType(
                 const boost::shared_ptr<SketchPlugin_Constraint>& theConstraint) const
 {
+  const std::string& aConstraintKind = theConstraint->getKind();
   // Constraint for coincidence of two points
-  boost::shared_ptr<SketchPlugin_ConstraintCoincidence> aPtEquiv = 
-    boost::dynamic_pointer_cast<SketchPlugin_ConstraintCoincidence>(theConstraint);
-  if (aPtEquiv)
+  if (aConstraintKind.compare("SketchConstraintCoincidence") == 0)
   {
     // Verify the constraint has only two attributes and they are points
-    int aPt2d = 0; // bit-mapped field, each bit indicates whether the attribute is 2D point 
+    int aPt2d = 0; // bit-mapped field, each bit indicates whether the attribute is 2D point
     int aPt3d = 0; // bit-mapped field, the same information for 3D points
     for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++)
     {
-      boost::shared_ptr<ModelAPI_AttributeRefAttr> anAttr = 
+      boost::shared_ptr<ModelAPI_AttributeRefAttr> anAttr =
         boost::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
           theConstraint->data()->attribute(CONSTRAINT_ATTRIBUTES[indAttr])
         );
       if (!anAttr) continue;
       // Verify the attribute is a 2D point
-      boost::shared_ptr<GeomDataAPI_Point2D> aPoint2D = 
+      boost::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
         boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr->attr());
       if (aPoint2D)
       {
@@ -559,7 +617,7 @@ int SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::getConstraintT
         continue;
       }
       // Verify the attribute is a 3D point
-      boost::shared_ptr<GeomDataAPI_Point> aPoint3D = 
+      boost::shared_ptr<GeomDataAPI_Point> aPoint3D =
         boost::dynamic_pointer_cast<GeomDataAPI_Point>(anAttr->attr());
       if (aPoint3D)
       {
@@ -582,7 +640,7 @@ int SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::getConstraintT
   return SLVS_C_UNKNOWN;
 }
 
-void SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::ResolveConstraints()
+void SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::resolveConstraints()
 {
   if (!myNeedToSolve)
     return;
@@ -605,12 +663,99 @@ void SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::ResolveConstr
   }
   /// \todo Implement error handling
 
+  removeTemporaryConstraints();
   myNeedToSolve = false;
 }
 
+bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::updateGroup()
+{
+  // Check for valid sketch
+  if (!mySketch->data()->isValid())
+    return true;
+
+  // Fast check for constraint validity. If all constraints are valid, no need to update the group
+  std::map<boost::shared_ptr<SketchPlugin_Constraint>, Slvs_hConstraint>::reverse_iterator
+    aConstrIter = myConstraintMap.rbegin();
+  bool isAllValid = true;
+  for ( ; isAllValid && aConstrIter != myConstraintMap.rend(); aConstrIter++)
+    if (!aConstrIter->first->data()->isValid())
+      isAllValid = false;
+  if (isAllValid)
+    return false;
+
+  // Remove invalid constraints.
+  // There only constraint will be deleted (parameters and entities) will be removed below
+  std::list< boost::shared_ptr<SketchPlugin_Constraint> > aConstrToDelete;
+  std::map<Slvs_hEntity, bool> anEntToDelete; // entities will be removed if no valid constraints use them
+  for (aConstrIter = myConstraintMap.rbegin(); aConstrIter != myConstraintMap.rend(); aConstrIter++)
+  {
+    bool isValid = aConstrIter->first->data()->isValid();
+
+    int aConstrPos = Search(aConstrIter->second, myConstraints);
+    if (aConstrPos < (int)myConstraints.size())
+    {
+      Slvs_hEntity aConstrEnt[] = {
+        myConstraints[aConstrPos].ptA,     myConstraints[aConstrPos].ptB,
+        myConstraints[aConstrPos].entityA, myConstraints[aConstrPos].entityB};
+      for (int i = 0; i < 4; i++)
+        if (aConstrEnt[i] != SLVS_E_UNKNOWN)
+        {
+          if (anEntToDelete.find(aConstrEnt[i]) == anEntToDelete.end())
+            anEntToDelete[aConstrEnt[i]] = !isValid;
+          else if (isValid) // constraint is valid => no need to remove its entities
+            anEntToDelete[aConstrEnt[i]] = false;
+        }
+      if (!isValid)
+      {
+        myConstraints.erase(myConstraints.begin() + aConstrPos);
+        if (aConstrIter->second == myConstrMaxID) // When the constraint with highest ID is removed, decrease indexer
+          myConstrMaxID--;
+        aConstrToDelete.push_front(aConstrIter->first);
+      }
+    }
+  }
+  std::list< boost::shared_ptr<SketchPlugin_Constraint> >::iterator aDelIter;
+  for (aDelIter = aConstrToDelete.begin(); aDelIter != aConstrToDelete.end(); aDelIter++)
+    myConstraintMap.erase(*aDelIter);
+
+  // Remove invalid and unused entities
+  std::map<Slvs_hEntity, bool>::reverse_iterator aEDelIter;
+  for (aEDelIter = anEntToDelete.rbegin(); aEDelIter != anEntToDelete.rend(); aEDelIter++)
+    if (aEDelIter->second)
+    {
+      int anEntPos = Search(aEDelIter->first, myEntities);
+      std::vector<Slvs_Entity>::iterator aEntIter = myEntities.begin() + anEntPos;
+      // Number of parameters for the entity
+      int aNbParams = 0;
+      while (aEntIter->param[aNbParams]) aNbParams++;
+      if (aNbParams == 0) continue;
+      // Decrease parameter indexer if there are deleted parameter with higher IDs
+      if (aEntIter->param[aNbParams-1] == myParamMaxID)
+        myParamMaxID -= aNbParams;
+      // Remove parameters of the entity
+      int aParamPos = Search(aEntIter->param[0], myParams);
+      myParams.erase(myParams.begin() + aParamPos,
+                     myParams.begin() + aParamPos + aNbParams);
+
+      // Remove entity
+      if (aEDelIter->first == myEntityMaxID)
+        myEntityMaxID--;
+      myEntities.erase(myEntities.begin() + anEntPos);
+      // Remove such entity from myEntityMap
+      std::map<boost::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator
+        anEntMapIter = myEntityMap.begin();
+      for ( ; anEntMapIter != myEntityMap.end(); anEntMapIter++)
+        if (anEntMapIter->second == aEDelIter->first)
+          break;
+      if (anEntMapIter != myEntityMap.end())
+        myEntityMap.erase(anEntMapIter);
+    }
+
+  return false;
+}
 
 void SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::updateAttribute(
-                boost::shared_ptr<ModelAPI_Attribute> theAttribute, 
+                boost::shared_ptr<ModelAPI_Attribute> theAttribute,
                 const Slvs_hEntity&                   theEntityID)
 {
   // Search the position of the first parameter of the entity
@@ -620,7 +765,7 @@ void SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::updateAttribu
   // Look over supported types of entities
 
   // Point in 3D
-  boost::shared_ptr<GeomDataAPI_Point> aPoint = 
+  boost::shared_ptr<GeomDataAPI_Point> aPoint =
     boost::dynamic_pointer_cast<GeomDataAPI_Point>(theAttribute);
   if (aPoint)
   {
@@ -631,7 +776,7 @@ void SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::updateAttribu
   }
 
   // Point in 2D
-  boost::shared_ptr<GeomDataAPI_Point2D> aPoint2D = 
+  boost::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
     boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
   if (aPoint2D)
   {
@@ -647,7 +792,60 @@ void SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::updateEntityI
                 boost::shared_ptr<ModelAPI_Attribute> theEntity)
 {
   if (myEntityMap.find(theEntity) != myEntityMap.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
+      boost::shared_ptr<GeomDataAPI_Point> aPoint =
+        boost::dynamic_pointer_cast<GeomDataAPI_Point>(theEntity);
+      boost::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
+        boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(theEntity);
+      if (aPoint || aPoint2D)
+        addTemporaryConstraintWhereDragged(theEntity);
+    }
+
+    // Restore flag of changes
+    myNeedToSolve = myNeedToSolve || aNeedToSolveCopy;
+  }
+}
+
+void SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::addTemporaryConstraintWhereDragged(
+                boost::shared_ptr<ModelAPI_Attribute> theEntity)
+{
+  // Find identifier of the entity
+  std::map<boost::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator
+    anEntIter = myEntityMap.find(theEntity);
+
+  // Create WHERE_DRAGGED constraint
+  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);
+}
+
+void SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::removeTemporaryConstraints()
+{
+  std::list<Slvs_hConstraint>::reverse_iterator aTmpConstrIter;
+  for (aTmpConstrIter = myTempConstraints.rbegin(); aTmpConstrIter != myTempConstraints.rend(); aTmpConstrIter++)
+  {
+    int aConstrPos = Search(*aTmpConstrIter, myConstraints);
+    myConstraints.erase(myConstraints.begin() + aConstrPos);
+
+    // If the removing constraint has higher index, decrease the indexer
+    if (*aTmpConstrIter == myConstrMaxID)
+      myConstrMaxID--;
+  }
+  myTempConstraints.clear();
 }
 
 
@@ -659,12 +857,13 @@ void SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::updateEntityI
 template <typename T>
 int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities)
 {
-  std::vector<T>::const_iterator aEntIter = theEntities.begin() + theEntityID - 1;
-  while (aEntIter != theEntities.end() && aEntIter->h > theEntityID)
-    aEntIter--;
-  while (aEntIter != theEntities.end() && aEntIter->h < theEntityID)
-    aEntIter++;
-  if (aEntIter == theEntities.end())
-    return -1;
-  return aEntIter - theEntities.begin();
+  int aResIndex = theEntityID <= theEntities.size() ? theEntityID - 1 : 0;
+  int aVecSize = theEntities.size();
+  while (aResIndex >= 0 && theEntities[aResIndex].h > theEntityID)
+    aResIndex--;
+  while (aResIndex < aVecSize && theEntities[aResIndex].h < theEntityID)
+    aResIndex++;
+  if (aResIndex == -1)
+    aResIndex = aVecSize;
+  return aResIndex;
 }