Salome HOME
Issue #3087: Show remaining DoFs highlight not all features
[modules/shaper.git] / src / SketchSolver / PlaneGCSSolver / PlaneGCSSolver_Storage.cpp
index 5c8cebe53ff3a75fc0fa3ac47e2419adc3867411..a5788f23a82f8e37224d769a52f4c91cf07bc89e 100644 (file)
@@ -34,6 +34,7 @@
 #include <GeomAPI_XY.h>
 #include <GeomDataAPI_Point2D.h>
 #include <ModelAPI_AttributeRefAttr.h>
+#include <SketchPlugin_Ellipse.h>
 #include <SketchPlugin_Projection.h>
 
 #include <cmath>
@@ -104,7 +105,7 @@ EntityWrapperPtr PlaneGCSSolver_Storage::createAttribute(
 /// \brief Update value
 static bool updateValue(const double& theSource, double& theDest)
 {
-  static const double aTol = 1000. * tolerance;
+  static const double aTol = 1.e4 * tolerance;
   bool isUpdated = fabs(theSource - theDest) > aTol;
   if (isUpdated)
     theDest = theSource;
@@ -195,7 +196,7 @@ bool PlaneGCSSolver_Storage::update(FeaturePtr theFeature, bool theForce)
     // (do not want to add several copies of it while adding attributes)
     aRelated = createFeature(theFeature, &aBuilder);
     myFeatureMap[theFeature] = aRelated;
-    createArcConstraints(aRelated);
+    createAuxiliaryConstraints(aRelated);
     isUpdated = true;
   }
 
@@ -222,6 +223,10 @@ bool PlaneGCSSolver_Storage::update(FeaturePtr theFeature, bool theForce)
   if (sendNotify && isUpdated)
     notify(theFeature);
 
+  // update arc
+  if (aRelated)
+    PlaneGCSSolver_Tools::recalculateArcParameters(aRelated);
+
   return isUpdated;
 }
 
@@ -265,7 +270,7 @@ void PlaneGCSSolver_Storage::makeExternal(const EntityWrapperPtr& theEntity)
   if (theEntity->isExternal())
     return;
 
-  removeArcConstraints(theEntity);
+  removeAuxiliaryConstraints(theEntity);
 
   GCS::SET_pD aParameters = PlaneGCSSolver_Tools::parameters(theEntity);
   mySketchSolver->removeParameters(aParameters);
@@ -282,73 +287,193 @@ void PlaneGCSSolver_Storage::makeNonExternal(const EntityWrapperPtr& theEntity)
   mySketchSolver->addParameters(aParameters);
   theEntity->setExternal(false);
 
-  createArcConstraints(theEntity);
+  createAuxiliaryConstraints(theEntity);
 
   myNeedToResolve = true;
 }
 
 
-void PlaneGCSSolver_Storage::createArcConstraints(const EntityWrapperPtr& theArc)
+static void createArcConstraints(const EntityWrapperPtr& theArc,
+                                 const SolverPtr& theSolver,
+                                 const ConstraintID theConstraintID,
+                                 std::map<EntityWrapperPtr, ConstraintWrapperPtr>& theConstraints)
 {
-  if (!theArc || theArc->type() != ENTITY_ARC || theArc->isExternal())
-    return;
-
   EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theArc);
   std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(anEdge->entity());
 
   // Additional constaints to fix arc's extra DoF (if the arc is not external):
   std::list<GCSConstraintPtr> anArcConstraints;
-  // constrain the start point on the arc
-  anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintCurveValue(
-      anArc->start, anArc->start.x, *anArc, anArc->startAngle)));
-  anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintCurveValue(
-      anArc->start, anArc->start.y, *anArc, anArc->startAngle)));
-  // constrain the end point on the arc
-  anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintCurveValue(
-      anArc->end, anArc->end.x, *anArc, anArc->endAngle)));
-  anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintCurveValue(
-      anArc->end, anArc->end.y, *anArc, anArc->endAngle)));
+  // 1. distances from center till start and end points are equal to radius
+  anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance(
+      anArc->center, anArc->start, anArc->rad)));
+  anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance(
+      anArc->center, anArc->end, anArc->rad)));
+  // 2. angles of start and end points should be equal to the arc angles
+  anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PAngle(
+      anArc->center, anArc->start, anArc->startAngle)));
+  anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PAngle(
+      anArc->center, anArc->end, anArc->endAngle)));
 
   ConstraintWrapperPtr aWrapper(
-      new PlaneGCSSolver_ConstraintWrapper(anArcConstraints, CONSTRAINT_UNKNOWN));
-  aWrapper->setId(++myConstraintLastID);
-  constraintsToSolver(aWrapper, mySketchSolver);
+    new PlaneGCSSolver_ConstraintWrapper(anArcConstraints, CONSTRAINT_UNKNOWN));
+  aWrapper->setId(theConstraintID);
+  constraintsToSolver(aWrapper, theSolver);
 
-  myArcConstraintMap[theArc] = aWrapper;
+  theConstraints[theArc] = aWrapper;
 }
 
-void PlaneGCSSolver_Storage::removeArcConstraints(const EntityWrapperPtr& theArc)
+static void createEllipseConstraints(
+    const EntityWrapperPtr& theEllipse,
+    const SolverPtr& theSolver,
+    const ConstraintID theConstraintID,
+    std::map<EntityWrapperPtr, ConstraintWrapperPtr>& theConstraints)
+{
+  EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theEllipse);
+  std::shared_ptr<GCS::Ellipse> anEllipse =
+      std::dynamic_pointer_cast<GCS::Ellipse>(anEdge->entity());
+
+  // Additional constaints to fix ellipse's extra points
+  std::list<GCSConstraintPtr> anEllipseConstraints;
+
+  const std::map<std::string, EntityWrapperPtr>& anAttributes = theEllipse->additionalAttributes();
+  for (std::map<std::string, EntityWrapperPtr>::const_iterator anIt = anAttributes.begin();
+       anIt != anAttributes.end(); ++anIt) {
+    std::shared_ptr<PlaneGCSSolver_PointWrapper> aPoint =
+        std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(anIt->second);
+    if (!aPoint)
+      continue;
+
+    GCS::InternalAlignmentType anAlignmentX, anAlignmentY;
+    if (anIt->first == SketchPlugin_Ellipse::SECOND_FOCUS_ID())
+      anAlignmentX = GCS::EllipseFocus2X;
+    else if (anIt->first == SketchPlugin_Ellipse::MAJOR_AXIS_START_ID())
+      anAlignmentX = GCS::EllipseNegativeMajorX;
+    else if (anIt->first == SketchPlugin_Ellipse::MAJOR_AXIS_END_ID())
+      anAlignmentX = GCS::EllipsePositiveMajorX;
+    else if (anIt->first == SketchPlugin_Ellipse::MINOR_AXIS_START_ID())
+      anAlignmentX = GCS::EllipseNegativeMinorX;
+    else if (anIt->first == SketchPlugin_Ellipse::MINOR_AXIS_END_ID())
+      anAlignmentX = GCS::EllipsePositiveMinorX;
+
+    anEllipseConstraints.push_back(GCSConstraintPtr(
+        new GCS::ConstraintInternalAlignmentPoint2Ellipse(
+        *anEllipse, *(aPoint->point()), anAlignmentX)));
+    anAlignmentY = (GCS::InternalAlignmentType)((int)anAlignmentX + 1);
+    anEllipseConstraints.push_back(GCSConstraintPtr(
+        new GCS::ConstraintInternalAlignmentPoint2Ellipse(
+        *anEllipse, *(aPoint->point()), anAlignmentY)));
+  }
+
+  // constraint to bind the major radius value
+  std::shared_ptr<PlaneGCSSolver_PointWrapper> aMajorAxisStart =
+      std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(
+      anAttributes.at(SketchPlugin_Ellipse::MAJOR_AXIS_START_ID()));
+  ScalarWrapperPtr aMajorRadius =
+      std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(
+      anAttributes.at(SketchPlugin_Ellipse::MAJOR_RADIUS_ID()));
+  anEllipseConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance(
+      anEllipse->center, *(aMajorAxisStart->point()), aMajorRadius->scalar())));
+
+  ConstraintWrapperPtr aWrapper(
+    new PlaneGCSSolver_ConstraintWrapper(anEllipseConstraints, CONSTRAINT_UNKNOWN));
+  aWrapper->setId(theConstraintID);
+  if (theSolver)
+    constraintsToSolver(aWrapper, theSolver);
+
+  theConstraints[theEllipse] = aWrapper;
+}
+
+static void createEllipticArcConstraints(
+    const EntityWrapperPtr& theEllipticArc,
+    const SolverPtr& theSolver,
+    const ConstraintID theConstraintID,
+    std::map<EntityWrapperPtr, ConstraintWrapperPtr>& theConstraints)
+{
+  // create base constraints for the ellipse without adding them to solver
+  createEllipseConstraints(theEllipticArc, SolverPtr(), theConstraintID, theConstraints);
+
+  ConstraintWrapperPtr& aConstraint = theConstraints[theEllipticArc];
+  std::list<GCSConstraintPtr> anEllArcConstraints = aConstraint->constraints();
+
+  // constrain extremities of the elliptic arc
+  EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theEllipticArc);
+  std::shared_ptr<GCS::ArcOfEllipse> anArc =
+      std::dynamic_pointer_cast<GCS::ArcOfEllipse>(anEdge->entity());
+
+  anEllArcConstraints.push_back(GCSConstraintPtr(
+      new GCS::ConstraintCurveValue(anArc->start, anArc->start.x, *anArc, anArc->startAngle)));
+  anEllArcConstraints.push_back(GCSConstraintPtr(
+      new GCS::ConstraintCurveValue(anArc->start, anArc->start.y, *anArc, anArc->startAngle)));
+  anEllArcConstraints.push_back(GCSConstraintPtr(
+      new GCS::ConstraintCurveValue(anArc->end, anArc->end.x, *anArc, anArc->endAngle)));
+  anEllArcConstraints.push_back(GCSConstraintPtr(
+      new GCS::ConstraintCurveValue(anArc->end, anArc->end.y, *anArc, anArc->endAngle)));
+
+  aConstraint->setConstraints(anEllArcConstraints);
+  constraintsToSolver(aConstraint, theSolver);
+}
+
+void PlaneGCSSolver_Storage::createAuxiliaryConstraints(const EntityWrapperPtr& theEntity)
+{
+  if (!theEntity || theEntity->isExternal())
+    return;
+
+  if (theEntity->type() == ENTITY_ARC)
+    createArcConstraints(theEntity, mySketchSolver, ++myConstraintLastID, myAuxConstraintMap);
+  else if (theEntity->type() == ENTITY_ELLIPSE)
+    createEllipseConstraints(theEntity, mySketchSolver, ++myConstraintLastID, myAuxConstraintMap);
+  else if (theEntity->type() == ENTITY_ELLIPTIC_ARC) {
+    createEllipticArcConstraints(theEntity, mySketchSolver,
+                                 ++myConstraintLastID, myAuxConstraintMap);
+  }
+}
+
+void PlaneGCSSolver_Storage::removeAuxiliaryConstraints(const EntityWrapperPtr& theEntity)
 {
   std::map<EntityWrapperPtr, ConstraintWrapperPtr>::iterator
-      aFound = myArcConstraintMap.find(theArc);
-  if (aFound != myArcConstraintMap.end()) {
+      aFound = myAuxConstraintMap.find(theEntity);
+  if (aFound != myAuxConstraintMap.end()) {
     mySketchSolver->removeConstraint(aFound->second->id());
-    myArcConstraintMap.erase(aFound);
+    myAuxConstraintMap.erase(aFound);
+  }
+}
+
+template <typename ARCTYPE>
+void adjustArcParametrization(ARCTYPE& theArc, bool theReversed)
+{
+  // tune start angle of the arc to be in [0, 2PI]
+  while (*theArc.startAngle < -PI)
+    *theArc.startAngle += 2.0 * PI;
+  while (*theArc.startAngle >= PI)
+    *theArc.startAngle -= 2.0 * PI;
+  // adjust end angle of the arc
+  if (theReversed) {
+    while (*theArc.endAngle > *theArc.startAngle)
+      *theArc.endAngle -= 2.0 * PI;
+    while (*theArc.endAngle + 2 * PI < *theArc.startAngle)
+      *theArc.endAngle += 2.0 * PI;
+  }
+  else {
+    while (*theArc.endAngle < *theArc.startAngle)
+      *theArc.endAngle += 2.0 * PI;
+    while (*theArc.endAngle > *theArc.startAngle + 2 * PI)
+      *theArc.endAngle -= 2.0 * PI;
   }
 }
 
 void PlaneGCSSolver_Storage::adjustParametrizationOfArcs()
 {
-  std::map<EntityWrapperPtr, ConstraintWrapperPtr>::iterator anIt = myArcConstraintMap.begin();
-  for (; anIt != myArcConstraintMap.end(); ++anIt) {
+  std::map<EntityWrapperPtr, ConstraintWrapperPtr>::iterator anIt = myAuxConstraintMap.begin();
+  for (; anIt != myAuxConstraintMap.end(); ++anIt) {
     EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(anIt->first);
     std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(anEdge->entity());
-    // tune start angle of the arc to be in [0, 2PI]
-    while (*anArc->startAngle < -PI)
-      *anArc->startAngle += 2.0 * PI;
-    while (*anArc->startAngle >= PI)
-      *anArc->startAngle -= 2.0 * PI;
-    // adjust end angle of the arc
-    if (anEdge->isReversed()) {
-      while (*anArc->endAngle > *anArc->startAngle)
-        *anArc->endAngle -= 2.0 * PI;
-      while (*anArc->endAngle + 2 * PI < *anArc->startAngle)
-        *anArc->endAngle += 2.0 * PI;
-    } else {
-      while (*anArc->endAngle < *anArc->startAngle)
-        *anArc->endAngle += 2.0 * PI;
-      while (*anArc->endAngle > *anArc->startAngle + 2 * PI)
-        *anArc->endAngle -= 2.0 * PI;
+    if (anArc)
+      adjustArcParametrization(*anArc, anEdge->isReversed());
+    else {
+      std::shared_ptr<GCS::ArcOfEllipse> aEllArc =
+          std::dynamic_pointer_cast<GCS::ArcOfEllipse>(anEdge->entity());
+      if (aEllArc)
+        adjustArcParametrization(*aEllArc, anEdge->isReversed());
     }
   }
 
@@ -417,7 +542,7 @@ void PlaneGCSSolver_Storage::removeInvalidEntities()
         aDestroyer.remove(aFIter->second);
 
       // remove invalid arc
-      removeArcConstraints(aFIter->second);
+      removeAuxiliaryConstraints(aFIter->second);
     }
   std::list<FeaturePtr>::const_iterator anInvFIt = anInvalidFeatures.begin();
   for (; anInvFIt != anInvalidFeatures.end(); ++anInvFIt)
@@ -529,3 +654,24 @@ PlaneGCSSolver_Solver::SolveStatus PlaneGCSSolver_Storage::checkDegeneratedGeome
   }
   return PlaneGCSSolver_Solver::STATUS_OK;
 }
+
+
+void PlaneGCSSolver_Storage::getUnderconstrainedGeometry(std::set<ObjectPtr>& theFeatures) const
+{
+  std::set<double*> aFreeParams;
+  mySketchSolver->getFreeParameters(aFreeParams);
+  if (aFreeParams.empty())
+    return;
+
+  for (std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIt = myFeatureMap.begin();
+       aFIt != myFeatureMap.end(); ++aFIt) {
+    if (!aFIt->second)
+      continue;
+    GCS::SET_pD aParams = PlaneGCSSolver_Tools::parameters(aFIt->second);
+    for (GCS::SET_pD::iterator aPIt = aParams.begin(); aPIt != aParams.end(); ++aPIt)
+      if (aFreeParams.find(*aPIt) != aFreeParams.end()) {
+        theFeatures.insert(aFIt->first);
+        break;
+      }
+  }
+}