]> SALOME platform Git repositories - modules/shaper.git/blobdiff - src/SketchSolver/SketchSolver_Constraint.cpp
Salome HOME
SketchSolver library refactoring
[modules/shaper.git] / src / SketchSolver / SketchSolver_Constraint.cpp
index c382cdeb30e86ec4d051643104d75e95ec23aeec..012c45c6ec172d20e99fee1afca8d7671eac4cc3 100644 (file)
@@ -169,6 +169,7 @@ bool SketchSolver_Constraint::remove(ConstraintPtr theConstraint)
     myValueMap.clear();
   } else
     cleanRemovedEntities();
+  mySlvsConstraints.clear();
   return true;
 }
 
@@ -278,7 +279,7 @@ 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())
+  if (!isInitialized(theEntity))
     return SLVS_E_UNKNOWN;
 
   // If the entity is already in the group, try to find it
@@ -373,7 +374,7 @@ Slvs_hEntity SketchSolver_Constraint::changeEntity(AttributePtr theEntity, int&
 Slvs_hEntity SketchSolver_Constraint::changeEntity(FeaturePtr theEntity, int& theType)
 {
   Slvs_hEntity aResult = SLVS_E_UNKNOWN;
-  if (!theEntity->data()->isValid())
+  if (!theEntity->data() || !theEntity->data()->isValid())
     return SLVS_E_UNKNOWN;
   // If the entity is already in the group, try to find it
   std::map<FeaturePtr, Slvs_hEntity>::const_iterator anEntIter = myFeatureMap.find(theEntity);
@@ -392,85 +393,82 @@ Slvs_hEntity SketchSolver_Constraint::changeEntity(FeaturePtr theEntity, int& th
 
   Slvs_hGroup aGroupID = myGroup->getId();
   Slvs_hEntity aWorkplaneID = myGroup->getWorkplaneId();
+  DataPtr aData = theEntity->data();
+
   // SketchPlugin features
-  std::shared_ptr<SketchPlugin_Feature> aFeature = std::dynamic_pointer_cast<
-      SketchPlugin_Feature>(theEntity);
-  if (aFeature) {  // Verify the feature by its kind
-    const std::string& aFeatureKind = aFeature->getKind();
-    AttributePtr anAttribute;
-    int anAttrType;
-
-    // Line
-    if (aFeatureKind == SketchPlugin_Line::ID()) {
-      anAttribute = aFeature->data()->attribute(SketchPlugin_Line::START_ID());
-      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
-      Slvs_hEntity aStart = changeEntity(anAttribute, anAttrType);
-
-      anAttribute = aFeature->data()->attribute(SketchPlugin_Line::END_ID());
-      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
-      Slvs_hEntity aEnd = changeEntity(anAttribute, anAttrType);
+  const std::string& aFeatureKind = theEntity->getKind();
+  AttributePtr anAttribute;
+  int anAttrType;
+  // Line
+  if (aFeatureKind == SketchPlugin_Line::ID()) {
+    anAttribute = aData->attribute(SketchPlugin_Line::START_ID());
+    if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
+    Slvs_hEntity aStart = changeEntity(anAttribute, anAttrType);
+
+    anAttribute = aData->attribute(SketchPlugin_Line::END_ID());
+    if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
+    Slvs_hEntity aEnd = changeEntity(anAttribute, anAttrType);
 
-      if (aCurrentEntity.h == SLVS_E_UNKNOWN) // New entity
-        aCurrentEntity = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID, aStart, aEnd);
-      else {
-        aCurrentEntity.point[0] = aStart;
-        aCurrentEntity.point[1] = aEnd;
-      }
-      aResult = myStorage->addEntity(aCurrentEntity);
-    }
-    // Circle
-    else if (aFeatureKind == SketchPlugin_Circle::ID()) {
-      anAttribute = aFeature->data()->attribute(SketchPlugin_Circle::CENTER_ID());
-      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
-      Slvs_hEntity aCenter = changeEntity(anAttribute, anAttrType);
-
-      anAttribute = aFeature->data()->attribute(SketchPlugin_Circle::RADIUS_ID());
-      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
-      Slvs_hEntity aRadius = changeEntity(anAttribute, anAttrType);
-
-      if (aCurrentEntity.h == SLVS_E_UNKNOWN) { // New entity
-        Slvs_Entity aWorkplane = myStorage->getEntity(aWorkplaneID);
-        aCurrentEntity = Slvs_MakeCircle(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID,
-                                         aCenter, aWorkplane.normal, aRadius);
-      } else {
-        aCurrentEntity.point[0] = aCenter;
-        aCurrentEntity.distance = aRadius;
-      }
-      aResult = myStorage->addEntity(aCurrentEntity);
+    if (aCurrentEntity.h == SLVS_E_UNKNOWN) // New entity
+      aCurrentEntity = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID, aStart, aEnd);
+    else {
+      aCurrentEntity.point[0] = aStart;
+      aCurrentEntity.point[1] = aEnd;
     }
-    // Arc
-    else if (aFeatureKind == SketchPlugin_Arc::ID()) {
-      anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::CENTER_ID());
-      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
-      Slvs_hEntity aCenter = changeEntity(anAttribute, anAttrType);
-
-      anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::START_ID());
-      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
-      Slvs_hEntity aStart = changeEntity(anAttribute, anAttrType);
-
-      anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::END_ID());
-      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
-      Slvs_hEntity aEnd = changeEntity(anAttribute, anAttrType);
-
-      if (aCurrentEntity.h == SLVS_E_UNKNOWN) { // New entity
-        Slvs_Entity aWorkplane = myStorage->getEntity(aWorkplaneID);
-        aCurrentEntity = Slvs_MakeArcOfCircle(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID,
-                                              aWorkplane.normal, aCenter, aStart, aEnd);
-      } else {
-        aCurrentEntity.point[0] = aCenter;
-        aCurrentEntity.point[1] = aStart;
-        aCurrentEntity.point[2] = aEnd;
-      }
-      aResult = myStorage->addEntity(aCurrentEntity);
+    aResult = myStorage->addEntity(aCurrentEntity);
+  }
+  // Circle
+  else if (aFeatureKind == SketchPlugin_Circle::ID()) {
+    anAttribute = aData->attribute(SketchPlugin_Circle::CENTER_ID());
+    if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
+    Slvs_hEntity aCenter = changeEntity(anAttribute, anAttrType);
+
+    anAttribute = aData->attribute(SketchPlugin_Circle::RADIUS_ID());
+    if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
+    Slvs_hEntity aRadius = changeEntity(anAttribute, anAttrType);
+
+    if (aCurrentEntity.h == SLVS_E_UNKNOWN) { // New entity
+      Slvs_Entity aWorkplane = myStorage->getEntity(aWorkplaneID);
+      aCurrentEntity = Slvs_MakeCircle(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID,
+                                        aCenter, aWorkplane.normal, aRadius);
+    } else {
+      aCurrentEntity.point[0] = aCenter;
+      aCurrentEntity.distance = aRadius;
     }
-    // Point (it has low probability to be an attribute of constraint, so it is checked at the end)
-    else if (aFeatureKind == SketchPlugin_Point::ID()) {
-      anAttribute = aFeature->data()->attribute(SketchPlugin_Point::COORD_ID());
-      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
-      // Both the sketch point and its attribute (coordinates) link to the same SolveSpace point identifier
-      aResult = changeEntity(anAttribute, anAttrType);
-      aCurrentEntity.type = SLVS_E_POINT_IN_3D;
+    aResult = myStorage->addEntity(aCurrentEntity);
+  }
+  // Arc
+  else if (aFeatureKind == SketchPlugin_Arc::ID()) {
+    anAttribute = aData->attribute(SketchPlugin_Arc::CENTER_ID());
+    if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
+    Slvs_hEntity aCenter = changeEntity(anAttribute, anAttrType);
+
+    anAttribute = aData->attribute(SketchPlugin_Arc::START_ID());
+    if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
+    Slvs_hEntity aStart = changeEntity(anAttribute, anAttrType);
+
+    anAttribute = aData->attribute(SketchPlugin_Arc::END_ID());
+    if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
+    Slvs_hEntity aEnd = changeEntity(anAttribute, anAttrType);
+
+    if (aCurrentEntity.h == SLVS_E_UNKNOWN) { // New entity
+      Slvs_Entity aWorkplane = myStorage->getEntity(aWorkplaneID);
+      aCurrentEntity = Slvs_MakeArcOfCircle(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID,
+                                            aWorkplane.normal, aCenter, aStart, aEnd);
+    } else {
+      aCurrentEntity.point[0] = aCenter;
+      aCurrentEntity.point[1] = aStart;
+      aCurrentEntity.point[2] = aEnd;
     }
+    aResult = myStorage->addEntity(aCurrentEntity);
+  }
+  // Point (it has low probability to be an attribute of constraint, so it is checked at the end)
+  else if (aFeatureKind == SketchPlugin_Point::ID()) {
+    anAttribute = aData->attribute(SketchPlugin_Point::COORD_ID());
+    if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
+    // Both the sketch point and its attribute (coordinates) link to the same SolveSpace point identifier
+    aResult = changeEntity(anAttribute, anAttrType);
+    aCurrentEntity.type = SLVS_E_POINT_IN_3D;
   }
 
   if (aResult != SLVS_E_UNKNOWN) {
@@ -501,19 +499,24 @@ void SketchSolver_Constraint::refresh()
         Slvs_Param aPar = myStorage->getParameter(anEntity.param[i]);
         aXYZ[i] = aPar.val;
       }
-      aPoint->setValue(aXYZ[0], aXYZ[1], aXYZ[2]);
+      if (fabs(aPoint->x() - aXYZ[0]) > tolerance ||
+          fabs(aPoint->y() - aXYZ[1]) > tolerance ||
+          fabs(aPoint->z() - aXYZ[2]) > tolerance)
+        aPoint->setValue(aXYZ[0], aXYZ[1], aXYZ[2]);
     } else {
       // Point in 2D
       std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
           std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttrIter->first);
       if (aPoint2D) {
         Slvs_Entity anEntity = myStorage->getEntity(anAttrIter->second);
-        double aXYZ[2];
+        double aXY[2];
         for (int i = 0; i < 2; i++) {
           Slvs_Param aPar = myStorage->getParameter(anEntity.param[i]);
-          aXYZ[i] = aPar.val;
+          aXY[i] = aPar.val;
         }
-        aPoint2D->setValue(aXYZ[0], aXYZ[1]);
+        if (fabs(aPoint2D->x() - aXY[0]) > tolerance ||
+            fabs(aPoint2D->y() - aXY[1]) > tolerance)
+        aPoint2D->setValue(aXY[0], aXY[1]);
       } else {
         // Scalar value (used for the distance entities)
         AttributeDoublePtr aScalar =
@@ -521,7 +524,8 @@ void SketchSolver_Constraint::refresh()
         if (aScalar) {
           Slvs_Entity anEntity = myStorage->getEntity(anAttrIter->second);
           Slvs_Param aPar = myStorage->getParameter(anEntity.param[0]);
-          aScalar->setValue(aPar.val);
+          if (fabs(aScalar->value() - aPar.val) > tolerance)
+            aScalar->setValue(aPar.val);
         }
       }
     }
@@ -554,3 +558,106 @@ Slvs_hEntity SketchSolver_Constraint::getId(AttributePtr theAttribute) const
   return anAttrIter->second;
 }
 
+bool SketchSolver_Constraint::isInitialized(AttributePtr theAttribute)
+{
+  if (theAttribute->isInitialized())
+    return true;
+  myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
+  return false;
+}
+
+
+void SketchSolver_Constraint::calculateMiddlePoint(
+    const Slvs_Entity& theEntity, double theCoeff, double& theX, double& theY) const
+{
+  if (theEntity.type == SLVS_E_LINE_SEGMENT) {
+    double aStartEndXY[2][2];
+    Slvs_Entity aPoint;
+    for (int i = 0; i < 2; i++) {
+      aPoint = myStorage->getEntity(theEntity.point[i]);
+      for (int j = 0; j < 2; j++)
+        aStartEndXY[i][j] = myStorage->getParameter(aPoint.param[j]).val;
+    }
+    theX = (1.0 - theCoeff) * aStartEndXY[0][0] + theCoeff * aStartEndXY[1][0];
+    theY = (1.0 - theCoeff) * aStartEndXY[0][1] + theCoeff * aStartEndXY[1][1];
+  } else if (theEntity.type == SLVS_E_ARC_OF_CIRCLE) {
+    double anArcPoint[3][2];
+    Slvs_Entity aPoint;
+    for (int i = 0; i < 3; i++) {
+      aPoint = myStorage->getEntity(theEntity.point[i]);
+      for (int j = 0; j < 2; j++)
+        anArcPoint[i][j] = myStorage->getParameter(aPoint.param[j]).val;
+    }
+    // project last point of arc on the arc
+    double x = anArcPoint[1][0] - anArcPoint[0][0];
+    double y = anArcPoint[1][1] - anArcPoint[0][1];
+    double aRad = sqrt(x*x + y*y);
+    x = anArcPoint[2][0] - anArcPoint[0][0];
+    y = anArcPoint[2][1] - anArcPoint[0][1];
+    double aNorm = sqrt(x*x + y*y);
+    if (aNorm >= tolerance) {
+      anArcPoint[2][0] = x * aRad / aNorm;
+      anArcPoint[2][1] = y * aRad / aNorm;
+    }
+    anArcPoint[1][0] -= anArcPoint[0][0];
+    anArcPoint[1][1] -= anArcPoint[0][1];
+    if (theCoeff < tolerance) {
+      theX = anArcPoint[0][0] + anArcPoint[1][0];
+      theY = anArcPoint[0][1] + anArcPoint[1][1];
+      return;
+    } else if (1 - theCoeff < tolerance) {
+      theX = anArcPoint[0][0] + anArcPoint[2][0];
+      theY = anArcPoint[0][1] + anArcPoint[2][1];
+      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;
+  }
+}
+