Salome HOME
Issue #591 - Highlight of the first argument of constraints
[modules/shaper.git] / src / SketchSolver / SketchSolver_ConstraintMultiRotation.cpp
index 9dc080f16727553a377175da0d600c7d61ac6f17..0ceaee69066ce7e0f2c335518a61398c8b8fbafa 100644 (file)
@@ -6,6 +6,7 @@
 #include <SketchPlugin_MultiRotation.h>
 
 #include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeInteger.h>
 #include <ModelAPI_AttributeRefAttr.h>
 #include <ModelAPI_AttributeRefList.h>
 #include <ModelAPI_ResultConstruction.h>
 
 #include <math.h>
 
-#define PI 3.1415926535897932
+static double squareDistance(
+    StoragePtr theStorage, const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2)
+{
+  Slvs_Entity aPoint1 = theStorage->getEntity(thePoint1);
+  Slvs_Entity aPoint2 = theStorage->getEntity(thePoint2);
+  double x1 = theStorage->getParameter(aPoint1.param[0]).val;
+  double y1 = theStorage->getParameter(aPoint1.param[1]).val;
+  double x2 = theStorage->getParameter(aPoint2.param[0]).val;
+  double y2 = theStorage->getParameter(aPoint2.param[1]).val;
+  return (x1-x2) * (x1-x2) + (y1-y2) * (y1-y2);
+}
 
 void SketchSolver_ConstraintMultiRotation::getAttributes(
     Slvs_hEntity& theCenter, double& theAngle,
@@ -41,8 +52,7 @@ void SketchSolver_ConstraintMultiRotation::getAttributes(
   AttributeRefListPtr anInitialRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
       aData->attribute(SketchPlugin_Constraint::ENTITY_A()));
   myNumberOfObjects = anInitialRefList->size();
-  myNumberOfCopies = (size_t)std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
-      aData->attribute(SketchPlugin_MultiRotation::NUMBER_OF_COPIES_ID()))->value();
+  myNumberOfCopies = (size_t) aData->integer(SketchPlugin_MultiRotation::NUMBER_OF_COPIES_ID())->value();
   AttributeRefListPtr aRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
       myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
   if (!aRefList) {
@@ -120,6 +130,8 @@ void SketchSolver_ConstraintMultiRotation::process()
   if (!myErrorMsg.empty())
     return;
 
+  myAuxLines.clear();
+
   // Create lines between neighbor rotated points and make angle between them equal to anAngle.
   // Also these lines should have equal lengths.
   Slvs_Constraint aConstraint;
@@ -133,6 +145,7 @@ void SketchSolver_ConstraintMultiRotation::process()
     aPrevLine = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, myGroup->getId(),
           myGroup->getWorkplaneId(), aCenter, (*aCopyIter)[0]);
     aPrevLine.h = myStorage->addEntity(aPrevLine);
+    std::vector<Slvs_hEntity> anEqualLines(1, aPrevLine.h);
     for (size_t i = 1; i < aSize; i++) {
       Slvs_Entity aLine = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, myGroup->getId(),
           myGroup->getWorkplaneId(), aCenter, (*aCopyIter)[i]);
@@ -153,7 +166,10 @@ void SketchSolver_ConstraintMultiRotation::process()
       mySlvsConstraints.push_back(aConstraint.h);
 
       aPrevLine = aLine;
+      anEqualLines.push_back(aPrevLine.h);
     }
+
+    myAuxLines.push_back(anEqualLines);
   }
   // Equal radii constraints
   for (aCopyIter = aCircsAndCopies.begin(); aCopyIter != aCircsAndCopies.end(); aCopyIter++) {
@@ -185,7 +201,8 @@ void SketchSolver_ConstraintMultiRotation::update(ConstraintPtr theConstraint)
   if (!theConstraint || theConstraint == myBaseConstraint) {
     AttributeRefListPtr anInitialRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
         myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
-    if (anInitialRefList->size() != myNumberOfObjects) {
+    AttributeIntegerPtr aNbCopies = myBaseConstraint->integer(SketchPlugin_MultiRotation::NUMBER_OF_COPIES_ID());
+    if (anInitialRefList->size() != myNumberOfObjects || aNbCopies->value() != myNumberOfCopies) {
       remove(myBaseConstraint);
       process();
       return;
@@ -213,6 +230,9 @@ bool SketchSolver_ConstraintMultiRotation::remove(ConstraintPtr theConstraint)
   std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIt = myFeatureMap.begin();
   for (; aFeatIt != myFeatureMap.end(); aFeatIt++)
     myStorage->removeEntity(aFeatIt->second);
+  myStorage->removeUnusedEntities();
+
+  std::map<FeaturePtr, Slvs_hEntity> aFeatureMapCopy = myFeatureMap;
 
   if (isFullyRemoved) {
     myFeatureMap.clear();
@@ -220,6 +240,18 @@ bool SketchSolver_ConstraintMultiRotation::remove(ConstraintPtr theConstraint)
     myValueMap.clear();
   } else
     cleanRemovedEntities();
+
+  // Restore initial features
+  std::map<FeaturePtr, Slvs_hEntity>::iterator aFIter = aFeatureMapCopy.begin();
+  for (; aFIter != aFeatureMapCopy.end(); ++aFIter)
+  {
+    if (myFeatureMap.find(aFIter->first) != myFeatureMap.end())
+      continue; // the feature was not removed
+    Slvs_hEntity anEntity = myGroup->getFeatureId(aFIter->first);
+    if (anEntity != SLVS_E_UNKNOWN)
+      myFeatureMap[aFIter->first] = anEntity;
+  }
+
   return true;
 }
 
@@ -230,6 +262,65 @@ void SketchSolver_ConstraintMultiRotation::adjustConstraint()
     return;
   }
 
+  // Check the lengths of auxiliary lines are zero.
+  // If they become zero, remove corresponding Angle constraints.
+  // It they become non-zero (but were zero recently), add Angle constraint.
+  std::vector<Slvs_hConstraint>::iterator aConstr = mySlvsConstraints.begin();
+  std::map<Slvs_hEntity, Slvs_hEntity> anEqualLines;
+  bool isFirstRemoved = false;
+  for (; aConstr != mySlvsConstraints.end();
+       isFirstRemoved ? aConstr = mySlvsConstraints.begin() : ++aConstr) {
+    isFirstRemoved = false;
+    Slvs_Constraint aConstraint = myStorage->getConstraint(*aConstr);
+    if (aConstraint.type == SLVS_C_ANGLE || aConstraint.type == SLVS_C_EQUAL_LENGTH_LINES) {
+      Slvs_Entity aLine = myStorage->getEntity(aConstraint.entityA);
+      // Line length became zero => remove constraint
+      if (squareDistance(myStorage, aLine.point[0], aLine.point[1]) < tolerance * tolerance) {
+        myStorage->removeConstraint(aConstraint.h);
+        isFirstRemoved = aConstr == mySlvsConstraints.begin();
+        std::vector<Slvs_hConstraint>::iterator aTmpIter = aConstr;
+        if (!isFirstRemoved)
+          --aConstr;
+        mySlvsConstraints.erase(aTmpIter);
+      }
+      // Store the lines into the map
+      anEqualLines[aConstraint.entityB] = aConstraint.entityA;
+    }
+  }
+  // Create Angle and Equal constraints for non-degenerated lines
+  AuxLinesList::iterator anIt = myAuxLines.begin();
+  for (; anIt != myAuxLines.end(); ++anIt) {
+    if (anEqualLines.find(anIt->back()) != anEqualLines.end())
+      continue;
+
+    std::vector<Slvs_hEntity>::iterator anEqLinesIt = anIt->begin();
+    Slvs_hEntity aPrevLine = (*anEqLinesIt);
+    // Check the length of the line
+    Slvs_Entity aLine = myStorage->getEntity(aPrevLine);
+    if (squareDistance(myStorage, aLine.point[0], aLine.point[1]) < tolerance * tolerance)
+      continue;
+
+    for (++anEqLinesIt; anEqLinesIt != anIt->end(); ++anEqLinesIt) {
+      Slvs_hEntity aLine = (*anEqLinesIt);
+      // Equal length constraint
+      Slvs_Constraint aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(),
+          SLVS_C_EQUAL_LENGTH_LINES, myGroup->getWorkplaneId(), 0.0,
+          SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aPrevLine, aLine);
+      aConstraint.h = myStorage->addConstraint(aConstraint);
+      mySlvsConstraints.push_back(aConstraint.h);
+      // Angle constraint
+      aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(),
+          SLVS_C_ANGLE, myGroup->getWorkplaneId(), fabs(myAngle), SLVS_E_UNKNOWN, SLVS_E_UNKNOWN,
+          aPrevLine, aLine);
+      if (myAngle < 0.0) // clockwise rotation
+        aConstraint.other = true;
+      aConstraint.h = myStorage->addConstraint(aConstraint);
+      mySlvsConstraints.push_back(aConstraint.h);
+
+      aPrevLine = aLine;
+    }
+  }
+
   // Obtain coordinates of rotation center
   Slvs_Entity aRotCenter = myStorage->getEntity(myRotationCenter);
   double aCenterXY[2];