Salome HOME
Issue #601: Impossible to modify segment with constraint
[modules/shaper.git] / src / SketchSolver / SketchSolver_Group.cpp
index 7fdc32a4c5e74b5c2c1ee514339fd2d28f60e298..11f334f51922cf00be3712b150d2560a9f06f34a 100644 (file)
@@ -25,6 +25,7 @@
 #include <ModelAPI_ResultConstruction.h>
 
 #include <SketchPlugin_Constraint.h>
+#include <SketchPlugin_ConstraintEqual.h>
 #include <SketchPlugin_ConstraintFillet.h>
 #include <SketchPlugin_ConstraintLength.h>
 #include <SketchPlugin_ConstraintCoincidence.h>
@@ -179,7 +180,8 @@ bool SketchSolver_Group::changeConstraint(
   if (!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);
@@ -215,7 +217,7 @@ bool SketchSolver_Group::changeConstraint(
     myConstraints[theConstraint]->update();
 
   // Fix base features for fillet
-  if (theConstraint->getKind() == SketchPlugin_ConstraintFillet::ID()) {
+  if (isNewConstraint && theConstraint->getKind() == SketchPlugin_ConstraintFillet::ID()) {
     std::list<AttributePtr> anAttrList =
         theConstraint->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
     std::list<AttributePtr>::iterator anAttrIter = anAttrList.begin();
@@ -234,11 +236,22 @@ bool SketchSolver_Group::changeConstraint(
       setTemporary(aConstraint);
     }
   }
-  // Fix base features for mirror
+  // Fix mirror line
   if (theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID()) {
-    AttributeRefListPtr aRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
-        theConstraint->attribute(SketchPlugin_ConstraintMirror::ENTITY_B()));
-    fixFeaturesList(aRefList);
+    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)
@@ -258,6 +271,11 @@ bool SketchSolver_Group::updateFeature(std::shared_ptr<SketchPlugin_Feature> the
   std::set<ConstraintPtr>::iterator aCIter = aConstraints.begin();
   for (; aCIter != aConstraints.end(); aCIter++) {
     ConstraintConstraintMap::iterator aSolConIter = myConstraints.find(*aCIter);
+    if (aSolConIter == myConstraints.end() || !aSolConIter->first->data() ||
+        !aSolConIter->first->data()->isValid())
+      continue;
+    myFeatureStorage->changeFeature(theFeature, aSolConIter->first);
+    aSolConIter->second->addFeature(theFeature);
     aSolConIter->second->update();
   }
   return true;
@@ -265,15 +283,17 @@ bool SketchSolver_Group::updateFeature(std::shared_ptr<SketchPlugin_Feature> the
 
 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);
-  setTemporary(aConstraint);
+  if (aConstraint->error().empty())
+    setTemporary(aConstraint);
+  // Secondly, update the feature
+  updateFeature(theFeature);
 }
 
 // ============================================================================
@@ -285,12 +305,27 @@ 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(aFeature);
+        SketchSolver_Builder::getInstance()->createRigidConstraint(*aFeatIter);
     if (!aConstraint)
       continue;
     aConstraint->setGroup(this);
@@ -384,7 +419,26 @@ bool SketchSolver_Group::resolveConstraints()
     myConstrSolver.setGroupID(myID);
     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
+        int aNbTemp = myStorage->numberTemporary();
+        while (true) {
+          aResult = myConstrSolver.solve();
+          if (aResult == SLVS_RESULT_OKAY || aNbTemp <= 0)
+            break;
+          aNbTemp = myStorage->deleteTemporaryConstraint();
+          myStorage->initializeSolver(myConstrSolver);
+        }
+      }
+    } catch (...) {
+      Events_Error::send(SketchSolver_Error::SOLVESPACE_CRASH(), this);
+      return false;
+    }
     if (aResult == SLVS_RESULT_OKAY) {  // solution succeeded, store results into correspondent attributes
       myFeatureStorage->blockEvents(true);
       ConstraintConstraintMap::iterator aConstrIter = myConstraints.begin();
@@ -523,7 +577,8 @@ bool SketchSolver_Group::isConsistent()
 void SketchSolver_Group::removeTemporaryConstraints()
 {
   myTempConstraints.clear();
-  myStorage->removeTemporaryConstraints();
+  while (myStorage->numberTemporary())
+    myStorage->deleteTemporaryConstraint();
   // Clean lists of removed entities in the storage
   std::set<Slvs_hParam> aRemPar;
   std::set<Slvs_hEntity> aRemEnt;