Salome HOME
#1095 line does not stop on arc end
[modules/shaper.git] / src / SketchSolver / SketchSolver_Group.cpp
index 5bce44595b775ffba4e86e6b01407eff52da7dff..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>
@@ -75,7 +76,7 @@ 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)
@@ -137,6 +138,15 @@ bool SketchSolver_Group::isInteract(
   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;
+}
+
 // ============================================================================
 //  Function: getFeatureId
 //  Class:    SketchSolver_Group
@@ -147,19 +157,21 @@ Slvs_hEntity SketchSolver_Group::getFeatureId(FeaturePtr theFeature) const
   Slvs_hEntity aResult = SLVS_E_UNKNOWN;
   if (!myFeatureStorage)
     return aResult;
-  std::set<ConstraintPtr> aConstraints = myFeatureStorage->getConstraints(theFeature);
-  if (aConstraints.empty())
-    return aResult;
-  std::set<ConstraintPtr>::iterator aConstrIter = aConstraints.begin();
-  for (; aConstrIter != aConstraints.end(); aConstrIter++) {
-    ConstraintConstraintMap::const_iterator aCIter = myConstraints.find(*aConstrIter);
-    if (aCIter == myConstraints.end())
-      continue;
+  // 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;
   }
-  return SLVS_E_UNKNOWN;
+  // 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;
 }
 
 // ============================================================================
@@ -172,19 +184,28 @@ Slvs_hEntity SketchSolver_Group::getAttributeId(AttributePtr theAttribute) const
   Slvs_hEntity aResult = SLVS_E_UNKNOWN;
   if (!myFeatureStorage)
     return aResult;
-  std::set<ConstraintPtr> aConstraints = myFeatureStorage->getConstraints(theAttribute);
-  if (aConstraints.empty())
-    return aResult;
-  std::set<ConstraintPtr>::iterator aConstrIter = aConstraints.begin();
-  for (; aConstrIter != aConstraints.end(); aConstrIter++) {
-    ConstraintConstraintMap::const_iterator aCIter = myConstraints.find(*aConstrIter);
-    if (aCIter == myConstraints.end())
-      continue;
+  // 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;
   }
-  return SLVS_E_UNKNOWN;
+  // 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;
 }
 
 // ============================================================================
@@ -199,7 +220,7 @@ bool SketchSolver_Group::changeConstraint(
   if (myWorkplaneID == SLVS_E_UNKNOWN)
     return false;
 
-  if (!theConstraint)
+  if (!theConstraint || !theConstraint->data())
     return false;
 
   if (!checkFeatureValidity(theConstraint))
@@ -222,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)
@@ -238,8 +260,12 @@ bool SketchSolver_Group::changeConstraint(
             if (anIt->second == aCIter->second)
               anIt->second = aCoinc2;
           aCIter->second = aCoinc2;
+          hasMultiCoincidence = true;
         }
       }
+
+      if (hasMultiCoincidence)
+        notifyMultiConstraints();
     }
     myConstraints[theConstraint] = aConstraint;
   }
@@ -288,6 +314,43 @@ bool SketchSolver_Group::changeConstraint(
     myFeatureStorage = FeatureStoragePtr(new SketchSolver_FeatureStorage);
   myFeatureStorage->changeConstraint(theConstraint);
 
+  // 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;
 }
 
@@ -335,6 +398,31 @@ bool SketchSolver_Group::updateFeature(std::shared_ptr<SketchPlugin_Feature> the
     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;
 }
 
@@ -428,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)
@@ -477,6 +565,7 @@ bool SketchSolver_Group::resolveConstraints()
   bool aResolved = false;
   if (myStorage->isNeedToResolve() && !isEmpty()) {
     myConstrSolver.setGroupID(myID);
+    myConstrSolver.calculateFailedConstraints(false);
     myStorage->initializeSolver(myConstrSolver);
 
     int aResult = SLVS_RESULT_OKAY;
@@ -500,36 +589,45 @@ bool SketchSolver_Group::resolveConstraints()
             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;
       }
-      getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue(SketchSolver_Error::SOLVESPACE_CRASH());
       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);
       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;
-        getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue("");
       }
     } 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;
       }
-      getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue(SketchSolver_Error::CONSTRAINTS());
     }
 
     aResolved = true;
@@ -592,9 +690,9 @@ void SketchSolver_Group::splitGroup(std::vector<SketchSolver_Group*>& theCuts)
   std::vector<ConstraintPtr>::iterator aUnuseIt = anUnusedConstraints.begin();
   while (aUnuseIt != anUnusedConstraints.end()) {
     if (aNewFeatStorage->isInteract(*aUnuseIt)) {
-      size_t aShift = aUnuseIt - anUnusedConstraints.begin();
+      aNewFeatStorage->changeConstraint(*aUnuseIt);
       anUnusedConstraints.erase(aUnuseIt);
-      aUnuseIt = anUnusedConstraints.begin() + aShift;
+      aUnuseIt = anUnusedConstraints.begin();
       continue;
     }
     aUnuseIt++;
@@ -618,6 +716,9 @@ void SketchSolver_Group::splitGroup(std::vector<SketchSolver_Group*>& theCuts)
       theCuts.push_back(aGroup);
     }
   }
+
+  // Update feature storage
+  myFeatureStorage = aNewFeatStorage;
 }
 
 // ============================================================================
@@ -654,7 +755,11 @@ 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
@@ -684,6 +789,9 @@ void SketchSolver_Group::removeConstraint(ConstraintPtr theConstraint)
   if (aCIter == myConstraints.end())
     return;
 
+  // Remove entities not used by constraints
+  myStorage->removeUnusedEntities();
+
   if (isFullyRemoved)
     myConstraints.erase(aCIter);
   else if (aCIter != myConstraints.end() &&
@@ -706,6 +814,8 @@ void SketchSolver_Group::removeConstraint(ConstraintPtr theConstraint)
     std::list<ConstraintPtr>::iterator anIt = aMultiCoinc.begin();
     for (; anIt != aMultiCoinc.end(); ++anIt)
       changeConstraint(*anIt);
+
+    notifyMultiConstraints();
   }
 }
 
@@ -748,6 +858,23 @@ bool SketchSolver_Group::checkFeatureValidity(FeaturePtr theFeature)
   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();
+    }
+  }
+}