Salome HOME
Adaptation to new data structure
[modules/shaper.git] / src / SketchSolver / SketchSolver_ConstraintGroup.cpp
index 7c0bd37845879ea5df3015d550a1645a013eefdb..954c6c5963fb779fba5116bbe9132eab4e6cba89 100644 (file)
@@ -6,15 +6,18 @@
 
 #include <SketchSolver_Constraint.h>
 
+#include <Events_Error.h>
 #include <Events_Loop.h>
 #include <GeomDataAPI_Dir.h>
 #include <GeomDataAPI_Point.h>
 #include <GeomDataAPI_Point2D.h>
 #include <ModelAPI_AttributeDouble.h>
 #include <ModelAPI_AttributeRefList.h>
-#include <Model_Events.h>
+#include <ModelAPI_Events.h>
 
 #include <SketchPlugin_Constraint.h>
+#include <SketchPlugin_ConstraintLength.h>
+#include <SketchPlugin_ConstraintCoincidence.h>
 
 #include <SketchPlugin_Arc.h>
 #include <SketchPlugin_Circle.h>
@@ -28,6 +31,8 @@
 /// Tolerance for value of parameters
 const double tolerance = 1.e-10;
 
+const std::string ERROR_SOLVE_CONSTRAINTS = "Conflicting constraints";
+
 /// This value is used to give unique index to the groups
 static Slvs_hGroup myGroupIndexer = 0;
 
@@ -116,11 +121,12 @@ bool SketchSolver_ConstraintGroup::isInteract(
         theConstraint->data()->attribute(CONSTRAINT_ATTRIBUTES[i])
       );
     if (!aCAttrRef) continue;
-    if (!aCAttrRef->isFeature() && 
+    if (!aCAttrRef->isObject() && 
         myEntityAttrMap.find(aCAttrRef->attr()) != myEntityAttrMap.end())
       return true;
-    if (aCAttrRef->isFeature() && 
-        myEntityFeatMap.find(aCAttrRef->feature()) != myEntityFeatMap.end())
+    if (aCAttrRef->isObject() && 
+        myEntityFeatMap.find(boost::dynamic_pointer_cast<ModelAPI_Feature>(aCAttrRef->object())) 
+        != myEntityFeatMap.end())
       return true;
   }
 
@@ -160,19 +166,19 @@ bool SketchSolver_ConstraintGroup::changeConstraint(
 
   // Create constraint parameters
   double aDistance = 0.0; // scalar value of the constraint
-  boost::shared_ptr<ModelAPI_AttributeDouble> aDistAttr =
+  AttributeDoublePtr aDistAttr =
     boost::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theConstraint->data()->attribute(CONSTRAINT_ATTR_VALUE));
   if (aDistAttr)
   {
     aDistance = aDistAttr->value();
+    // SketchPlugin circle defined by its radius, but SolveSpace uses constraint for diameter
+    if (aConstrType == SLVS_C_DIAMETER)
+      aDistance *= 2.0;
     if (aConstrMapIter != myConstraintMap.end() && fabs(aConstrIter->valA - aDistance) > tolerance)
     {
       myNeedToSolve = true;
       aConstrIter->valA = aDistance;
     }
-    // SketchPlugin circle defined by its radius, but SolveSpace uses constraint for diameter
-    if (aConstrType == SLVS_C_DIAMETER)
-      aDistance *= 2.0;
   }
 
   Slvs_hEntity aConstrEnt[CONSTRAINT_ATTR_SIZE]; // parameters of the constraint
@@ -186,15 +192,17 @@ bool SketchSolver_ConstraintGroup::changeConstraint(
     if (!aConstrAttr) continue;
 
     // For the length constraint the start and end points of the line should be added to the entities list instead of line
-    if (aConstrType == SLVS_C_PT_PT_DISTANCE && theConstraint->getKind().compare("SketchConstraintLength") == 0)
+    if (aConstrType == SLVS_C_PT_PT_DISTANCE && theConstraint->getKind().compare(SKETCH_CONSTRAINT_LENGTH_KIND) == 0)
     {
-      boost::shared_ptr<ModelAPI_Data> aData = aConstrAttr->feature()->data();
+      boost::shared_ptr<ModelAPI_Data> aData = aConstrAttr->object()->data();
       aConstrEnt[indAttr]   = changeEntity(aData->attribute(LINE_ATTR_START));
       aConstrEnt[indAttr+1] = changeEntity(aData->attribute(LINE_ATTR_END));
+       // measured object is added into the map of objects to avoid problems with interaction betwee constraint and group
+      myEntityFeatMap[boost::dynamic_pointer_cast<ModelAPI_Feature>(aConstrAttr->object())] = 0;
       break; // there should be no other entities
     }
-    else if (aConstrAttr->isFeature())
-      aConstrEnt[indAttr] = changeEntity(aConstrAttr->feature());
+    else if (aConstrAttr->isObject())
+      aConstrEnt[indAttr] = changeEntity(boost::dynamic_pointer_cast<ModelAPI_Feature>(aConstrAttr->object()));
     else
       aConstrEnt[indAttr] = changeEntity(aConstrAttr->attr());
   }
@@ -203,11 +211,17 @@ bool SketchSolver_ConstraintGroup::changeConstraint(
   {
     // Several points may be coincident, it is not necessary to store all constraints between them.
     // Try to find sequence of coincident points which connects the points of new constraint
-    if (aConstrType == SLVS_C_POINTS_COINCIDENT &&
-        !addCoincidentPoints(aConstrEnt[0], aConstrEnt[1]))
+    if (aConstrType == SLVS_C_POINTS_COINCIDENT)
     {
-      myExtraCoincidence.insert(theConstraint); // the constraint is stored for further purposes
-      return false;
+      if (aConstrEnt[0] == aConstrEnt[1]) // no need to add self coincidence
+      {
+        return false;
+      }
+      if (!addCoincidentPoints(aConstrEnt[0], aConstrEnt[1]))
+      {
+        myExtraCoincidence.insert(theConstraint); // the constraint is stored for further purposes
+        return false;
+      }
     }
 
     // Create SolveSpace constraint structure
@@ -286,7 +300,7 @@ Slvs_hEntity SketchSolver_ConstraintGroup::changeEntity(
   }
 
   // Scalar value (used for the distance entities)
-  boost::shared_ptr<ModelAPI_AttributeDouble> aScalar = 
+  AttributeDoublePtr aScalar = 
     boost::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theEntity);
   if (aScalar)
   {
@@ -315,23 +329,23 @@ Slvs_hEntity SketchSolver_ConstraintGroup::changeEntity(
 //  Purpose:  create/update the element defined by the feature affected by any constraint
 // ============================================================================
 Slvs_hEntity SketchSolver_ConstraintGroup::changeEntity(
-                boost::shared_ptr<ModelAPI_Feature> theEntity)
+                FeaturePtr theEntity)
 {
   // If the entity is already in the group, try to find it
-  std::map<boost::shared_ptr<ModelAPI_Feature>, Slvs_hEntity>::const_iterator
+  std::map<FeaturePtr, Slvs_hEntity>::const_iterator
     aEntIter = myEntityFeatMap.find(theEntity);
   // defines that the entity already exists
   const bool isEntExists = (myEntityFeatMap.find(theEntity) != myEntityFeatMap.end());
 
   // SketchPlugin features
-  boost::shared_ptr<SketchPlugin_Feature> aFeature;
+  boost::shared_ptr<SketchPlugin_Feature> aFeature =
     boost::dynamic_pointer_cast<SketchPlugin_Feature>(theEntity);
   if (aFeature)
   { // Verify the feature by its kind
     const std::string& aFeatureKind = aFeature->getKind();
 
     // Line
-    if (aFeatureKind.compare("SketchLine") == 0)
+    if (aFeatureKind.compare(SKETCH_LINE_KIND) == 0)
     {
       Slvs_hEntity aStart = changeEntity(aFeature->data()->attribute(LINE_ATTR_START));
       Slvs_hEntity aEnd   = changeEntity(aFeature->data()->attribute(LINE_ATTR_END));
@@ -346,7 +360,7 @@ Slvs_hEntity SketchSolver_ConstraintGroup::changeEntity(
       return aLineEntity.h;
     }
     // Circle
-    else if (aFeatureKind.compare("SketchCircle") == 0)
+    else if (aFeatureKind.compare(SKETCH_CIRCLE_KIND) == 0)
     {
       Slvs_hEntity aCenter = changeEntity(aFeature->data()->attribute(CIRCLE_ATTR_CENTER));
       Slvs_hEntity aRadius = changeEntity(aFeature->data()->attribute(CIRCLE_ATTR_RADIUS));
@@ -362,7 +376,7 @@ Slvs_hEntity SketchSolver_ConstraintGroup::changeEntity(
       return aCircleEntity.h;
     }
     // Arc
-    else if (aFeatureKind.compare("SketchArc") == 0)
+    else if (aFeatureKind.compare(SKETCH_ARC_KIND) == 0)
     {
       Slvs_hEntity aCenter = changeEntity(aFeature->data()->attribute(ARC_ATTR_CENTER));
       Slvs_hEntity aStart  = changeEntity(aFeature->data()->attribute(ARC_ATTR_START));
@@ -378,7 +392,7 @@ Slvs_hEntity SketchSolver_ConstraintGroup::changeEntity(
       return anArcEntity.h;
     }
     // Point (it has low probability to be an attribute of constraint, so it is checked at the end)
-    else if (aFeatureKind.compare("SketchPoint") == 0)
+    else if (aFeatureKind.compare(SKETCH_POINT_KIND) == 0)
     {
       Slvs_hEntity aPoint = changeEntity(aFeature->data()->attribute(POINT_ATTR_COORD));
 
@@ -461,7 +475,7 @@ Slvs_hEntity SketchSolver_ConstraintGroup::changeNormal(
 bool SketchSolver_ConstraintGroup::addWorkplane(
                 boost::shared_ptr<SketchPlugin_Feature> theSketch)
 {
-  if (myWorkplane.h || theSketch->getKind().compare("Sketch") != 0)
+  if (myWorkplane.h || theSketch->getKind().compare(SKETCH_KIND) != 0)
     return false; // the workplane already exists or the function parameter is not Sketch
 
   mySketch = theSketch;
@@ -554,9 +568,11 @@ void SketchSolver_ConstraintGroup::resolveConstraints()
     std::map<boost::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator
       anEntIter = myEntityAttrMap.begin();
     for ( ; anEntIter != myEntityAttrMap.end(); anEntIter++)
-      updateAttribute(anEntIter->first, anEntIter->second);
+      if (updateAttribute(anEntIter->first, anEntIter->second))
+        updateRelatedConstraints(anEntIter->first);
   }
-  /// \todo Implement error handling
+  else if (!myConstraints.empty())
+    Events_Error::send(ERROR_SOLVE_CONSTRAINTS, this);
 
   removeTemporaryConstraints();
   myNeedToSolve = false;
@@ -744,7 +760,7 @@ bool SketchSolver_ConstraintGroup::updateGroup()
   {
     if (!aConstrIter->first->data()->isValid())
     {
-      if (aConstrIter->first->getKind().compare("SketchConstraintCoincidence") == 0)
+      if (aConstrIter->first->getKind().compare(SKETCH_CONSTRAINT_COINCIDENCE_KIND) == 0)
         isCCRemoved = true;
       std::map<boost::shared_ptr<SketchPlugin_Constraint>, Slvs_hConstraint>::reverse_iterator
         aCopyIter = aConstrIter++;
@@ -776,7 +792,7 @@ bool SketchSolver_ConstraintGroup::updateGroup()
 //  Class:    SketchSolver_ConstraintGroup
 //  Purpose:  update features of sketch after resolving constraints
 // ============================================================================
-void SketchSolver_ConstraintGroup::updateAttribute(
+bool SketchSolver_ConstraintGroup::updateAttribute(
                 boost::shared_ptr<ModelAPI_Attribute> theAttribute,
                 const Slvs_hEntity&                   theEntityID)
 {
@@ -791,10 +807,16 @@ void SketchSolver_ConstraintGroup::updateAttribute(
     boost::dynamic_pointer_cast<GeomDataAPI_Point>(theAttribute);
   if (aPoint)
   {
-    aPoint->setValue(myParams[aFirstParamPos].val,
-                     myParams[aFirstParamPos+1].val,
-                     myParams[aFirstParamPos+2].val);
-    return ;
+    if (fabs(aPoint->x() - myParams[aFirstParamPos].val) > tolerance ||
+        fabs(aPoint->y() - myParams[aFirstParamPos+1].val) > tolerance ||
+        fabs(aPoint->z() - myParams[aFirstParamPos+2].val) > tolerance)
+    {
+      aPoint->setValue(myParams[aFirstParamPos].val,
+                       myParams[aFirstParamPos+1].val,
+                       myParams[aFirstParamPos+2].val);
+      return true;
+    }
+    return false;
   }
 
   // Point in 2D
@@ -802,21 +824,31 @@ void SketchSolver_ConstraintGroup::updateAttribute(
     boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
   if (aPoint2D)
   {
-    aPoint2D->setValue(myParams[aFirstParamPos].val,
-                       myParams[aFirstParamPos+1].val);
-    return ;
+    if (fabs(aPoint2D->x() - myParams[aFirstParamPos].val) > tolerance ||
+        fabs(aPoint2D->y() - myParams[aFirstParamPos+1].val) > tolerance)
+    {
+      aPoint2D->setValue(myParams[aFirstParamPos].val,
+                         myParams[aFirstParamPos+1].val);
+      return true;
+    }
+    return false;
   }
 
   // Scalar value
-  boost::shared_ptr<ModelAPI_AttributeDouble> aScalar = 
+  AttributeDoublePtr aScalar = 
     boost::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
   if (aScalar)
   {
-    aScalar->setValue(myParams[aFirstParamPos].val);
-    return ;
+    if (fabs(aScalar->value() - myParams[aFirstParamPos].val) > tolerance)
+    {
+      aScalar->setValue(myParams[aFirstParamPos].val);
+      return true;
+    }
+    return false;
   }
 
   /// \todo Support other types of entities
+  return false;
 }
 
 // ============================================================================
@@ -852,6 +884,9 @@ void SketchSolver_ConstraintGroup::updateEntityIfPossible(
 
     // Restore flag of changes
     myNeedToSolve = myNeedToSolve || aNeedToSolveCopy;
+
+    if (myNeedToSolve)
+      updateRelatedConstraints(theEntity);
   }
 }
 
@@ -994,13 +1029,13 @@ void SketchSolver_ConstraintGroup::removeConstraint(boost::shared_ptr<SketchPlug
     }
     else anEntAttrIter++;
   }
-  std::map<boost::shared_ptr<ModelAPI_Feature>, Slvs_hEntity>::iterator
+  std::map<FeaturePtr, Slvs_hEntity>::iterator
     anEntFeatIter = myEntityFeatMap.begin();
   while (anEntFeatIter != myEntityFeatMap.end())
   {
     if (anEntToRemove.find(anEntFeatIter->second) != anEntToRemove.end())
     {
-      std::map<boost::shared_ptr<ModelAPI_Feature>, Slvs_hEntity>::iterator
+      std::map<FeaturePtr, Slvs_hEntity>::iterator
         aRemovedIter = anEntFeatIter;
       anEntFeatIter++;
       myEntityFeatMap.erase(aRemovedIter);
@@ -1087,6 +1122,67 @@ bool SketchSolver_ConstraintGroup::addCoincidentPoints(
 }
 
 
+// ============================================================================
+//  Function: updateRelatedConstraints
+//  Class:    SketchSolver_ConstraintGroup
+//  Purpose:  emit the signal to update constraints
+// ============================================================================
+void SketchSolver_ConstraintGroup::updateRelatedConstraints(
+                    boost::shared_ptr<ModelAPI_Attribute> theEntity) const
+{
+  std::map<boost::shared_ptr<SketchPlugin_Constraint>, Slvs_hConstraint>::const_iterator
+    aConstrIter = myConstraintMap.begin();
+  for ( ; aConstrIter != myConstraintMap.end(); aConstrIter++)
+  {
+    std::list< boost::shared_ptr<ModelAPI_Attribute> > anAttributes = 
+      aConstrIter->first->data()->attributes(std::string());
+
+    std::list< boost::shared_ptr<ModelAPI_Attribute> >::iterator
+      anAttrIter = anAttributes.begin();
+    for ( ; anAttrIter != anAttributes.end(); anAttrIter++)
+    {
+      bool isUpd = (*anAttrIter == theEntity);
+      boost::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr = 
+        boost::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttrIter);
+      if (aRefAttr && !aRefAttr->isObject() && aRefAttr->attr() == theEntity)
+        isUpd = true;
+
+      if (isUpd)
+      {
+        static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
+        ModelAPI_EventCreator::get()->sendUpdated(aConstrIter->first, anEvent);
+        break;
+      }
+    }
+  }
+}
+
+void SketchSolver_ConstraintGroup::updateRelatedConstraints(
+                    boost::shared_ptr<ModelAPI_Feature> theFeature) const
+{
+  std::map<boost::shared_ptr<SketchPlugin_Constraint>, Slvs_hConstraint>::const_iterator
+    aConstrIter = myConstraintMap.begin();
+  for ( ; aConstrIter != myConstraintMap.end(); aConstrIter++)
+  {
+    std::list< boost::shared_ptr<ModelAPI_Attribute> > anAttributes = 
+      aConstrIter->first->data()->attributes(std::string());
+
+    std::list< boost::shared_ptr<ModelAPI_Attribute> >::iterator
+      anAttrIter = anAttributes.begin();
+    for ( ; anAttrIter != anAttributes.end(); anAttrIter++)
+    {
+      boost::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr = 
+        boost::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttrIter);
+      if (aRefAttr && aRefAttr->isObject() && aRefAttr->object() == theFeature)
+      {
+        static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
+        ModelAPI_EventCreator::get()->sendUpdated(aConstrIter->first, anEvent);
+        break;
+      }
+    }
+  }
+}
+
 
 
 // ========================================================
@@ -1100,7 +1196,7 @@ int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities)
   int aVecSize = theEntities.size();
   while (aResIndex >= 0 && theEntities[aResIndex].h > theEntityID)
     aResIndex--;
-  while (aResIndex < aVecSize && theEntities[aResIndex].h < theEntityID)
+  while (aResIndex < aVecSize && aResIndex >= 0 && theEntities[aResIndex].h < theEntityID)
     aResIndex++;
   if (aResIndex == -1)
     aResIndex = aVecSize;