Salome HOME
Issue #604 Creation of an unexpected line in the Sketcher
[modules/shaper.git] / src / SketchSolver / SketchSolver_Group.cpp
index 2c6d8f5763627c0d5c012814ce687a4d463d6741..11f334f51922cf00be3712b150d2560a9f06f34a 100644 (file)
 #include <ModelAPI_ResultConstruction.h>
 
 #include <SketchPlugin_Constraint.h>
+#include <SketchPlugin_ConstraintEqual.h>
 #include <SketchPlugin_ConstraintFillet.h>
 #include <SketchPlugin_ConstraintLength.h>
 #include <SketchPlugin_ConstraintCoincidence.h>
 #include <SketchPlugin_ConstraintMirror.h>
 #include <SketchPlugin_ConstraintRigid.h>
+#include <SketchPlugin_ConstraintTangent.h>
 #include <SketchPlugin_Feature.h>
 
 #include <SketchPlugin_Arc.h>
@@ -178,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);
@@ -214,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();
@@ -230,14 +233,25 @@ bool SketchSolver_Group::changeConstraint(
         continue;
       aConstraint->setGroup(this);
       aConstraint->setStorage(myStorage);
-      myTempConstraints.insert(aConstraint);
+      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)
@@ -257,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;
@@ -264,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);
-  myTempConstraints.insert(aConstraint);
+  if (aConstraint->error().empty())
+    setTemporary(aConstraint);
+  // Secondly, update the feature
+  updateFeature(theFeature);
 }
 
 // ============================================================================
@@ -284,17 +305,32 @@ 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);
     aConstraint->setStorage(myStorage);
-    myTempConstraints.insert(aConstraint);
+    setTemporary(aConstraint);
   }
 }
 
@@ -383,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();
@@ -413,9 +468,18 @@ void SketchSolver_Group::mergeGroups(const SketchSolver_Group& theGroup)
   if (!myFeatureStorage)
     myFeatureStorage = FeatureStoragePtr(new SketchSolver_FeatureStorage);
 
+  std::vector<ConstraintPtr> aComplexConstraints;
   ConstraintConstraintMap::const_iterator aConstrIter = theGroup.myConstraints.begin();
+  // append simple constraints
   for (; aConstrIter != theGroup.myConstraints.end(); aConstrIter++)
-    changeConstraint(aConstrIter->first);
+    if (isComplexConstraint(aConstrIter->first))
+      aComplexConstraints.push_back(aConstrIter->first);
+    else
+      changeConstraint(aConstrIter->first);
+  // append complex constraints
+  std::vector<ConstraintPtr>::iterator aComplexIter = aComplexConstraints.begin();
+  for (; aComplexIter != aComplexConstraints.end(); aComplexIter++)
+      changeConstraint(*aComplexIter);
 }
 
 // ============================================================================
@@ -439,8 +503,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)) {
+      size_t aShift = aUnuseIt - anUnusedConstraints.begin();
+      anUnusedConstraints.erase(aUnuseIt);
+      aUnuseIt = anUnusedConstraints.begin() + aShift;
+      continue;
+    }
+    aUnuseIt++;
+  }
+
+  std::vector<SketchSolver_Group*>::iterator aCutsIter;
+  aUnuseIt = anUnusedConstraints.begin();
   for ( ; aUnuseIt != anUnusedConstraints.end(); aUnuseIt++) {
     // Remove unused constraints
     removeConstraint(*aUnuseIt);
@@ -501,6 +577,8 @@ bool SketchSolver_Group::isConsistent()
 void SketchSolver_Group::removeTemporaryConstraints()
 {
   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;
@@ -527,3 +605,27 @@ void SketchSolver_Group::removeConstraint(ConstraintPtr theConstraint)
   if (aCIter != myConstraints.end())
     myConstraints.erase(aCIter);
 }
+
+// ============================================================================
+//  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);
+}
+