Salome HOME
Sketcher: merge errors when merging two groups (issue #1893)
[modules/shaper.git] / src / SketchSolver / SketchSolver_Group.cpp
index 285a55cbb364cc0d79f1ea183d9aa87ce71680a8..867775e50d2301b9defd228c2831157cfe4c37a8 100644 (file)
@@ -32,6 +32,7 @@
 #include <SketchPlugin_ConstraintPerpendicular.h>
 #include <SketchPlugin_ConstraintRadius.h>
 #include <SketchPlugin_ConstraintRigid.h>
+#include <SketchPlugin_ConstraintSplit.h>
 #include <SketchPlugin_ConstraintTangent.h>
 #include <SketchPlugin_ConstraintVertical.h>
 #include <SketchPlugin_MultiRotation.h>
@@ -130,8 +131,21 @@ bool SketchSolver_Group::isInteract(FeaturePtr theFeature) const
   ConstraintConstraintMap::const_iterator anIt = myConstraints.begin();
   for (; !isInteracted && anIt != myConstraints.end(); ++anIt)
     if (anIt->first->getKind() == SketchPlugin_MultiRotation::ID() ||
-        anIt->first->getKind() == SketchPlugin_MultiTranslation::ID())
+        anIt->first->getKind() == SketchPlugin_MultiTranslation::ID()) {
       isInteracted = anIt->second->isUsed(theFeature);
+      if (isInteracted)
+        break;
+      // if theFeature is a constraint, check its attributes
+      ConstraintPtr aConstraint = std::dynamic_pointer_cast<SketchPlugin_Constraint>(theFeature);
+      if (!aConstraint)
+        continue;
+      for (int i = 0; i < 4 && !isInteracted; ++i) {
+        AttributeRefAttrPtr aRefAttr = aConstraint->refattr(aConstraint->ATTRIBUTE(i));
+        if (!aRefAttr)
+          continue;
+        isInteracted = anIt->second->isUsed((AttributePtr)aRefAttr);
+      }
+    }
   return isInteracted;
 }
 
@@ -206,7 +220,7 @@ static void updateMultiConstraints(ConstraintConstraintMap& theConstraints, Feat
          aType == CONSTRAINT_MULTI_TRANSLATION)
         && aCIt->second->isUsed(theFeature))
       std::dynamic_pointer_cast<SketchSolver_ConstraintMulti>(aCIt->second)->update(true);
-    else if ((aType == CONSTRAINT_TANGENT_CIRCLE_LINE ||
+    else if ((aType == CONSTRAINT_TANGENT_CIRCLE_LINE || aType == CONSTRAINT_TANGENT_ARC_ARC ||
               aType == CONSTRAINT_SYMMETRIC || aType == CONSTRAINT_ANGLE)
              && aCIt->second->isUsed(theFeature))
       aCIt->second->update();
@@ -364,7 +378,8 @@ bool SketchSolver_Group::resolveConstraints()
       }
     } catch (...) {
 //      Events_Error::send(SketchSolver_Error::SOLVESPACE_CRASH(), this);
-      getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue(SketchSolver_Error::SOLVESPACE_CRASH());
+      getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())
+        ->setValue(SketchSolver_Error::SOLVESPACE_CRASH());
       if (myPrevResult == STATUS_OK || myPrevResult == STATUS_UNKNOWN) {
         // the error message should be changed before sending the message
         sendMessage(EVENT_SOLVER_FAILED);
@@ -373,9 +388,15 @@ bool SketchSolver_Group::resolveConstraints()
       mySketchSolver->undo();
       return false;
     }
-    if (aResult == STATUS_OK || aResult == STATUS_EMPTYSET) {  // solution succeeded, store results into correspondent attributes
+    // solution succeeded, store results into correspondent attributes
+    if (aResult == STATUS_OK || aResult == STATUS_EMPTYSET) {
+      myStorage->setNeedToResolve(false);
       myStorage->refresh();
       updateMultiConstraints(myConstraints);
+      // multi-constraints updated some parameters, need to store them
+      if (myStorage->isNeedToResolve())
+        resolveConstraints();
+
       if (myPrevResult != STATUS_OK || myPrevResult == STATUS_UNKNOWN) {
         getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue("");
         std::set<ObjectPtr> aConflicting = myConflictingConstraints;
@@ -388,14 +409,15 @@ bool SketchSolver_Group::resolveConstraints()
       mySketchSolver->undo();
       if (!myConstraints.empty()) {
         // the error message should be changed before sending the message
-        getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue(SketchSolver_Error::CONSTRAINTS());
-        if (myPrevResult != aResult || myPrevResult == STATUS_UNKNOWN) {
+        getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())
+          ->setValue(SketchSolver_Error::CONSTRAINTS());
+        if (myPrevResult != aResult ||
+            myPrevResult == STATUS_UNKNOWN ||
+            myPrevResult == STATUS_FAILED) {
           // Obtain list of conflicting constraints
           std::set<ObjectPtr> aConflicting = myStorage->getConflictingConstraints(mySketchSolver);
 
-          if (myConflictingConstraints.empty())
-            sendMessage(EVENT_SOLVER_FAILED, aConflicting);
-          else {
+          if (!myConflictingConstraints.empty()) {
             std::set<ObjectPtr>::iterator anIt = aConflicting.begin();
             for (; anIt != aConflicting.end(); ++anIt)
               myConflictingConstraints.erase(*anIt);
@@ -405,6 +427,8 @@ bool SketchSolver_Group::resolveConstraints()
             }
           }
           myConflictingConstraints = aConflicting;
+          if (!myConflictingConstraints.empty())
+            sendMessage(EVENT_SOLVER_FAILED, myConflictingConstraints);
           myPrevResult = aResult;
         }
       }
@@ -412,14 +436,15 @@ bool SketchSolver_Group::resolveConstraints()
 
     aResolved = true;
   } else if (!isGroupEmpty) {
-    // Check there are constraints Fixed. If they exist, update parameters by stored values
+    // Check if the group contains only constraints Fixed, update parameters by stored values
+    aResolved = true;
     ConstraintConstraintMap::iterator aCIt = myConstraints.begin();
     for (; aCIt != myConstraints.end(); ++aCIt)
-      if (aCIt->first->getKind() == SketchPlugin_ConstraintRigid::ID()) {
-        aResolved = true;
+      if (aCIt->first->getKind() != SketchPlugin_ConstraintRigid::ID()) {
+        aResolved = false;
         break;
       }
-    if (aCIt != myConstraints.end())
+    if (aCIt == myConstraints.end())
       myStorage->refresh();
   }
   removeTemporaryConstraints();
@@ -452,6 +477,11 @@ void SketchSolver_Group::mergeGroups(const SketchSolver_Group& theGroup)
       continue;
     changeConstraint(aConstr);
   }
+
+  // merge previous states of groups => use the worst state,
+  // so the group after rebuilt may discard error messages if exist
+  if (theGroup.myPrevResult > myPrevResult)
+    myPrevResult = theGroup.myPrevResult;
 }
 
 // ============================================================================
@@ -463,7 +493,8 @@ void SketchSolver_Group::splitGroup(std::list<SketchSolver_Group*>& theCuts)
 {
   // New storage will be used in trimmed way to store the list of constraint interacted together.
   StoragePtr aNewStorage = SketchSolver_Manager::instance()->builder()->createStorage(getId());
-  std::list<ConstraintWrapperPtr> aDummyVec; // empty vector to avoid creation of solver's constraints
+  // empty vector to avoid creation of solver's constraints
+  std::list<ConstraintWrapperPtr> aDummyVec;
 
   // Obtain constraints, which should be separated
   std::list<ConstraintPtr> anUnusedConstraints;
@@ -475,7 +506,8 @@ void SketchSolver_Group::splitGroup(std::list<SketchSolver_Group*>& theCuts)
       anUnusedConstraints.push_back(aCIter->first);
   }
 
-  // Check the unused constraints once again, because they may become interacted with new storage since adding constraints
+  // Check the unused constraints once again,
+  // because they may become interacted with new storage since adding constraints
   std::list<ConstraintPtr>::iterator aUnuseIt = anUnusedConstraints.begin();
   while (aUnuseIt != anUnusedConstraints.end()) {
     if (aNewStorage->isInteract(FeaturePtr(*aUnuseIt))) {
@@ -603,6 +635,12 @@ void SketchSolver_Group::removeConstraint(ConstraintPtr theConstraint)
     }
   if (aCIter != myConstraints.end())
     myConstraints.erase(aCIter);
+  // empty group => clear storage
+  if (myConstraints.empty()) {
+    myStorage = StoragePtr();
+    mySketchSolver = SolverPtr();
+    updateWorkplane();
+  }
 }
 
 // ============================================================================
@@ -650,7 +688,8 @@ static double featureToVal(FeaturePtr theFeature)
     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
+      // point-on-line and point-on-circle should go before points coincidence constraint
+      return 2.0;
     return 2.5;
   }
   if (anID == SketchPlugin_ConstraintDistance::ID() ||
@@ -670,7 +709,7 @@ static double featureToVal(FeaturePtr theFeature)
       anID == SketchPlugin_ConstraintMirror::ID())
     return 6.0;
   if (anID == SketchPlugin_ConstraintRigid::ID())
-    return 7.0;
+    return 0.5;
   if (anID == SketchPlugin_MultiRotation::ID() ||
       anID == SketchPlugin_MultiTranslation::ID())
     return 8.0;
@@ -684,7 +723,8 @@ static bool isLess(FeaturePtr theFeature1, FeaturePtr theFeature2)
   return featureToVal(theFeature1) < featureToVal(theFeature2);
 }
 
-std::list<FeaturePtr> SketchSolver_Group::selectApplicableFeatures(const std::set<ObjectPtr>& theObjects)
+std::list<FeaturePtr> SketchSolver_Group::
+  selectApplicableFeatures(const std::set<ObjectPtr>& theObjects)
 {
   std::list<FeaturePtr> aResult;
   std::list<FeaturePtr>::iterator aResIt;
@@ -692,14 +732,16 @@ std::list<FeaturePtr> SketchSolver_Group::selectApplicableFeatures(const std::se
   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.
+    // Also, the Fillet and Split 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::shared_ptr<SketchPlugin_Feature> aSketchFeature =
         std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
     if ((aFeature->getKind() != SketchPlugin_Sketch::ID() && !aSketchFeature) ||
-        aFeature->getKind() == SketchPlugin_ConstraintFillet::ID())
+        aFeature->getKind() == SketchPlugin_ConstraintFillet::ID() ||
+        aFeature->getKind() == SketchPlugin_ConstraintSplit::ID())
       continue;
 
     // Find the place where to insert a feature