Salome HOME
Fix for a crash: Create sketch, circle, Radius constraint with 0 value.
[modules/shaper.git] / src / SketchSolver / SketchSolver_Constraint.cpp
index b86ce1a28073d4caa0cecf85827bc7e4b4b517b8..c1d0558f4ec08054ba0ccacc19ee227503173e64 100644 (file)
@@ -7,6 +7,7 @@
 #include <SketchPlugin_Line.h>
 #include <SketchPlugin_Point.h>
 
+#include <GeomAPI_Dir2d.h>
 #include <GeomDataAPI_Point.h>
 #include <GeomDataAPI_Point2D.h>
 #include <ModelAPI_AttributeDouble.h>
@@ -33,10 +34,16 @@ SketchSolver_Constraint::~SketchSolver_Constraint()
     myStorage->removeEntity(anIt2->second);
   myAttributeMap.clear();
 
-  std::map<FeaturePtr, Slvs_hEntity>::const_iterator anIt3 =  myFeatureMap.begin();
-  for (; anIt3 != myFeatureMap.end(); anIt3++)
-    myStorage->removeEntity(anIt3->second);
-  myFeatureMap.clear();
+  std::map<FeaturePtr, Slvs_hEntity>::iterator anIt3 =  myFeatureMap.begin();
+  while (!myFeatureMap.empty()) {
+    std::shared_ptr<SketchPlugin_Feature> aFeature =
+        std::dynamic_pointer_cast<SketchPlugin_Feature>(anIt3->first);
+    Slvs_hEntity anEnt = anIt3->second;
+    std::map<FeaturePtr, Slvs_hEntity>::iterator aRemIt = anIt3++;
+    myFeatureMap.erase(aRemIt);
+    if (!myGroup->isInteract(aFeature))
+      myStorage->removeEntity(anEnt);
+  }
 
   std::vector<Slvs_hConstraint>::const_iterator anIt4 = mySlvsConstraints.begin();
   for (; anIt4 != mySlvsConstraints.end(); anIt4++)
@@ -56,6 +63,12 @@ void SketchSolver_Constraint::setGroup(SketchSolver_Group* theGroup)
   process();
 }
 
+void SketchSolver_Constraint::addFeature(FeaturePtr theFeature)
+{
+  int aType;
+  changeEntity(theFeature, aType);
+}
+
 
 void SketchSolver_Constraint::process()
 {
@@ -73,6 +86,8 @@ void SketchSolver_Constraint::process()
   getAttributes(aValue, anAttributes);
   if (!myErrorMsg.empty())
     return;
+  if (aConstrType == SLVS_C_UNKNOWN)
+    aConstrType = getType();
 
   Slvs_hGroup aGroupID = myGroup->getId();
   Slvs_hEntity aWorkplaneID = myGroup->getWorkplaneId();
@@ -101,15 +116,80 @@ void SketchSolver_Constraint::process()
   adjustConstraint();
 }
 
+bool SketchSolver_Constraint::checkAttributesChanged(ConstraintPtr theConstraint)
+{
+  std::set<Slvs_hEntity> aCurAttrs; // list of currently used attributes
+  std::vector<Slvs_hConstraint>::const_iterator aConstrIter = mySlvsConstraints.begin();
+  for (; aConstrIter != mySlvsConstraints.end(); aConstrIter++) {
+    Slvs_Constraint aConstr = myStorage->getConstraint(*aConstrIter);
+    if (aConstr.ptA != SLVS_E_UNKNOWN) aCurAttrs.insert(aConstr.ptA);
+    if (aConstr.ptB != SLVS_E_UNKNOWN) aCurAttrs.insert(aConstr.ptB);
+    if (aConstr.entityA != SLVS_E_UNKNOWN) aCurAttrs.insert(aConstr.entityA);
+    if (aConstr.entityB != SLVS_E_UNKNOWN) aCurAttrs.insert(aConstr.entityB);
+    if (aConstr.entityC != SLVS_E_UNKNOWN) aCurAttrs.insert(aConstr.entityC);
+    if (aConstr.entityD != SLVS_E_UNKNOWN) aCurAttrs.insert(aConstr.entityD);
+  }
+  // Check the attrbutes of constraint are changed
+  ConstraintPtr aConstraint = theConstraint ? theConstraint : myBaseConstraint;
+  std::list<AttributePtr> anAttrList = aConstraint->data()->attributes(std::string());
+  std::list<AttributePtr>::iterator anAttrIter = anAttrList.begin();
+  for (; anAttrIter != anAttrList.end(); anAttrIter++) {
+    AttributeRefAttrPtr aRefAttr =
+        std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttrIter);
+    if (aRefAttr) {
+      if (aRefAttr->isObject()) {
+        FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
+        std::map<FeaturePtr, Slvs_hEntity>::iterator aFIt = myFeatureMap.find(aFeature);
+        if (aFeature) {
+          if (aFIt == myFeatureMap.end())
+            return true;
+          // Additional check the points of entity
+          if (aCurAttrs.find(aFIt->second) == aCurAttrs.end()) {
+            Slvs_Entity anEntity = myStorage->getEntity(aFIt->second);
+            bool isFound = false;
+            for (int i = 0; i < 4 && !isFound; i++)
+              if (anEntity.point[i] != SLVS_E_UNKNOWN && 
+                  aCurAttrs.find(anEntity.point[i]) != aCurAttrs.end())
+                isFound = true;
+            if (!isFound)
+              return true;
+          }
+        }
+      } else if (aRefAttr->attr()) {
+        std::map<AttributePtr, Slvs_hEntity>::iterator anAIt = myAttributeMap.find(aRefAttr->attr());
+        if (anAIt == myAttributeMap.end() || aCurAttrs.find(anAIt->second) == aCurAttrs.end())
+          return true;
+      }
+    }
+    AttributeRefListPtr aRefList =
+        std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anAttrIter);
+    if (aRefList) {
+      std::list<ObjectPtr> anItems = aRefList->list();
+      std::list<ObjectPtr>::iterator anIt = anItems.begin();
+      for (; anIt != anItems.end(); anIt++) {
+        FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
+        if (aFeature && myFeatureMap.find(aFeature) == myFeatureMap.end())
+          return true;
+      }
+    }
+  }
+  return false;
+}
+
 void SketchSolver_Constraint::update(ConstraintPtr theConstraint)
 {
   cleanErrorMsg();
-  if (theConstraint && theConstraint != myBaseConstraint) {
-    if (theConstraint->getKind() != myBaseConstraint->getKind())
+  bool needToRebuild = (theConstraint && theConstraint != myBaseConstraint);
+  if (!needToRebuild)
+    needToRebuild = checkAttributesChanged(theConstraint);
+  if (needToRebuild) {
+    if (theConstraint && theConstraint->getKind() != myBaseConstraint->getKind())
       return;
     remove(myBaseConstraint);
-    myBaseConstraint = theConstraint;
+    if (theConstraint)
+      myBaseConstraint = theConstraint;
     process();
+    return;
   }
 
   // Update all attributes
@@ -141,7 +221,8 @@ void SketchSolver_Constraint::update(ConstraintPtr theConstraint)
   std::vector<Slvs_hConstraint>::iterator aCIter = mySlvsConstraints.begin();
   for (; aCIter != mySlvsConstraints.end(); aCIter++) {
     Slvs_Constraint aConstraint = myStorage->getConstraint(*aCIter);
-    aConstraint.valA = aValue;
+    if (aValueAttr)
+      aConstraint.valA = aValue;
     Slvs_hEntity* aCoeffs[6] = {
         &aConstraint.ptA, &aConstraint.ptB,
         &aConstraint.entityA, &aConstraint.entityB,
@@ -209,6 +290,11 @@ void SketchSolver_Constraint::cleanRemovedEntities()
     std::map<AttributePtr, Slvs_hParam>::iterator aTmpIter = aValIt++;
     myValueMap.erase(aTmpIter);
   }
+  for (size_t i = 0; i < mySlvsConstraints.size(); i++)
+    if (aRemovedConstraints.find(mySlvsConstraints[i]) != aRemovedConstraints.end()) {
+      mySlvsConstraints.erase(mySlvsConstraints.begin() + i);
+      i--;
+    }
 }
 
 void SketchSolver_Constraint::getAttributes(
@@ -282,8 +368,10 @@ Slvs_hEntity SketchSolver_Constraint::changeEntity(AttributeRefAttrPtr theAttrib
 Slvs_hEntity SketchSolver_Constraint::changeEntity(AttributePtr theEntity, int& theType)
 {
   Slvs_hEntity aResult = SLVS_E_UNKNOWN;
-  if (!theEntity || !isInitialized(theEntity))
+  if (!theEntity || !isInitialized(theEntity)) {
+    myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
     return SLVS_E_UNKNOWN;
+  }
 
   // If the entity is already in the group, try to find it
   std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator anEntIter =
@@ -494,11 +582,16 @@ void SketchSolver_Constraint::refresh()
 {
   cleanErrorMsg();
   std::map<AttributePtr, Slvs_hEntity>::iterator anAttrIter = myAttributeMap.begin();
-  for (; anAttrIter != myAttributeMap.end(); anAttrIter++) {
+  while (anAttrIter != myAttributeMap.end()) {
     std::shared_ptr<GeomDataAPI_Point> aPoint =
         std::dynamic_pointer_cast<GeomDataAPI_Point>(anAttrIter->first);
+    Slvs_Entity anEntity = myStorage->getEntity(anAttrIter->second);
+    if (anEntity.h == SLVS_E_UNKNOWN) {
+      std::map<AttributePtr, Slvs_hEntity>::iterator aTmpIter = anAttrIter++;
+      myAttributeMap.erase(aTmpIter);
+      continue;
+    }
     if (aPoint) {
-      Slvs_Entity anEntity = myStorage->getEntity(anAttrIter->second);
       double aXYZ[3];
       for (int i = 0; i < 3; i++) {
         Slvs_Param aPar = myStorage->getParameter(anEntity.param[i]);
@@ -513,7 +606,6 @@ void SketchSolver_Constraint::refresh()
       std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
           std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttrIter->first);
       if (aPoint2D) {
-        Slvs_Entity anEntity = myStorage->getEntity(anAttrIter->second);
         double aXY[2];
         for (int i = 0; i < 2; i++) {
           Slvs_Param aPar = myStorage->getParameter(anEntity.param[i]);
@@ -521,19 +613,19 @@ void SketchSolver_Constraint::refresh()
         }
         if (fabs(aPoint2D->x() - aXY[0]) > tolerance ||
             fabs(aPoint2D->y() - aXY[1]) > tolerance)
-        aPoint2D->setValue(aXY[0], aXY[1]);
+          aPoint2D->setValue(aXY[0], aXY[1]);
       } else {
         // Scalar value (used for the distance entities)
         AttributeDoublePtr aScalar =
             std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anAttrIter->first);
         if (aScalar) {
-          Slvs_Entity anEntity = myStorage->getEntity(anAttrIter->second);
           Slvs_Param aPar = myStorage->getParameter(anEntity.param[0]);
           if (fabs(aScalar->value() - aPar.val) > tolerance)
             aScalar->setValue(aPar.val);
         }
       }
     }
+    anAttrIter++;
   }
 
   std::map<AttributePtr, Slvs_hParam>::iterator aValIter = myValueMap.begin();
@@ -552,7 +644,15 @@ Slvs_hEntity SketchSolver_Constraint::getId(FeaturePtr theFeature) const
   std::map<FeaturePtr, Slvs_hEntity>::const_iterator aFIter = myFeatureMap.find(theFeature);
   if (aFIter == myFeatureMap.end())
     return SLVS_E_UNKNOWN;
-  return aFIter->second;
+  // check the Feature is really in the storage
+  Slvs_Entity anEntity = myStorage->getEntity(aFIter->second);
+  if (anEntity.h == SLVS_E_UNKNOWN) {
+    // rebuild feature
+    int aType;
+    anEntity.h = const_cast<SketchSolver_Constraint*>(this)->changeEntity(aFIter->first, aType);
+    const_cast<SketchSolver_Constraint*>(this)->myFeatureMap[theFeature] = anEntity.h;
+  }
+  return anEntity.h;
 }
 
 Slvs_hEntity SketchSolver_Constraint::getId(AttributePtr theAttribute) const
@@ -616,53 +716,23 @@ void SketchSolver_Constraint::calculateMiddlePoint(
       return;
     }
 
-    double xStart = anArcPoint[1][0] / aRad, xEnd = anArcPoint[2][0] / aRad;
-    double yStart = anArcPoint[1][1] / aRad, yEnd = anArcPoint[2][1] / aRad;
-    if (anArcPoint[1][0] * anArcPoint[2][0] < 0.0) {
-      if (anArcPoint[1][0] > 0.0)
-        yEnd = 2.0 - yEnd;
-      else
-        yStart = -2.0 - yStart;
-    } else {
-      if (yStart > yEnd) {
-        yStart = 2.0 - yStart;
-        yEnd = -2.0 - yEnd;
-      } else {
-        yStart = -2.0 - yStart;
-        yEnd = 2.0 - yEnd;
-      }
-    }
-    if (anArcPoint[1][1] * anArcPoint[2][1] < 0.0) {
-      if (anArcPoint[1][1] > 0.0)
-        xEnd = 2.0 - xEnd;
-      else
-        xStart = -2.0 - xStart;
-    } else {
-      if (xStart > xEnd) {
-        xStart = 2.0 - xStart;
-        xEnd = -2.0 - xEnd;
-      } else {
-        xStart = -2.0 - xStart;
-        xEnd = 2.0 - xEnd;
-      }
-    }
-    x = (1.0 - theCoeff) * xStart + theCoeff * xEnd;
-    y = (1.0 - theCoeff) * yStart + theCoeff * yEnd;
-    if (x > 1.0) x = 2.0 - x;
-    if (x < -1.0) x = -2.0 - x;
-    if (y > 1.0) y = 2.0 - y;
-    if (y < -1.0) y = -2.0 - y;
-
-    aNorm = sqrt(x*x + y*y);
-    if (aNorm >= tolerance) {
-      x *= aRad / aNorm;
-      y *= aRad / aNorm;
-    } else {
-      x = -0.5 * (anArcPoint[2][1] + anArcPoint[1][1]);
-      y = -0.5 * (anArcPoint[2][0] + anArcPoint[1][0]);
-    }
-    theX = anArcPoint[0][0] + x;
-    theY = anArcPoint[0][1] + y;
+    std::shared_ptr<GeomAPI_Dir2d> aStartDir(new GeomAPI_Dir2d(anArcPoint[1][0], anArcPoint[1][1]));
+    std::shared_ptr<GeomAPI_Dir2d> aEndDir(new GeomAPI_Dir2d(anArcPoint[2][0], anArcPoint[2][1]));
+    double anAngle = aStartDir->angle(aEndDir);
+    if (anAngle < 0)
+      anAngle += 2.0 * PI;
+    anAngle *= theCoeff;
+    double aCos = cos(anAngle);
+    double aSin = sin(anAngle);
+    theX = anArcPoint[0][0] + anArcPoint[1][0] * aCos - anArcPoint[1][1] * aSin;
+    theY = anArcPoint[0][1] + anArcPoint[1][0] * aSin + anArcPoint[1][1] * aCos;
   }
 }
 
+void SketchSolver_Constraint::makeTemporary() const
+{
+  std::vector<Slvs_hConstraint>::const_iterator anIt = mySlvsConstraints.begin();
+  for (; anIt != mySlvsConstraints.end(); anIt++)
+    myStorage->addTemporaryConstraint(*anIt);
+}
+