]> SALOME platform Git repositories - modules/shaper.git/blobdiff - src/SketchPlugin/SketchPlugin_Circle.cpp
Salome HOME
Merge remote-tracking branch 'remotes/origin/HighLevelDump'
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_Circle.cpp
index 858c2e7efaf1fd77540610d742acb797bece4351..babdd6f14e01dcff3da73c1b76c1f4f01ac1a09f 100644 (file)
@@ -16,6 +16,8 @@
 
 #include <GeomAPI_Pnt2d.h>
 #include <GeomAPI_Circ.h>
+#include <GeomAPI_Circ2d.h>
+#include <GeomAPI_Vertex.h>
 #include <GeomAPI_XY.h>
 #include <GeomDataAPI_Point2D.h>
 #include <GeomDataAPI_Dir.h>
 #include <GeomAlgoAPI_EdgeBuilder.h>
 #include <GeomAlgoAPI_CompoundBuilder.h>
 
-namespace {
-  static const std::string& CIRCLE_TYPE()
-  {
-    static const std::string TYPE("CircleType");
-    return TYPE;
-  }
-  static const std::string CIRCLE_TYPE_CENTER_AND_RADIUS()
-  {
-    static const std::string TYPE("CenterRadius");
-    return TYPE;
-  }
-  static const std::string CIRCLE_TYPE_THREE_POINTS()
-  {
-    static const std::string TYPE("ThreePoints");
-    return TYPE;
-  }
+#include <cmath>
 
-  static const std::string& FIRST_POINT_ID()
-  {
-    static const std::string FIRST_PNT("FirstPoint");
-    return FIRST_PNT;
-  }
-  static const std::string& SECOND_POINT_ID()
-  {
-    static const std::string SECOND_PNT("SecondPoint");
-    return SECOND_PNT;
-  }
-  static const std::string& THIRD_POINT_ID()
-  {
-    static const std::string THIRD_PNT("ThirdPoint");
-    return THIRD_PNT;
-  }
+const double tolerance = 1e-7;
+
+namespace {
   static const std::string& POINT_ID(int theIndex)
   {
     switch (theIndex) {
-    case 1: return FIRST_POINT_ID();
-    case 2: return SECOND_POINT_ID();
-    case 3: return THIRD_POINT_ID();
+    case 1: return SketchPlugin_Circle::FIRST_POINT_ID();
+    case 2: return SketchPlugin_Circle::SECOND_POINT_ID();
+    case 3: return SketchPlugin_Circle::THIRD_POINT_ID();
     }
 
     static const std::string DUMMY;
@@ -68,12 +43,6 @@ namespace {
   }
 }
 
-static void calculateCircleOnThreePoints(const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPnt,
-                                         const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPnt,
-                                         const std::shared_ptr<GeomAPI_Pnt2d>& theThirdPnt,
-                                               std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
-                                               double&                         theRadius);
-
 
 SketchPlugin_Circle::SketchPlugin_Circle()
     : SketchPlugin_SketchEntity()
@@ -134,7 +103,7 @@ void SketchPlugin_Circle::execute()
 AISObjectPtr SketchPlugin_Circle::getAISObject(AISObjectPtr thePrevious)
 {
   SketchPlugin_Sketch* aSketch = sketch();
-  if (aSketch) {
+  if (aSketch && !isFeatureValid()) {
     // compute a circle point in 3D view
     std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr = std::dynamic_pointer_cast<
         GeomDataAPI_Point2D>(data()->attribute(CENTER_ID()));
@@ -154,7 +123,7 @@ AISObjectPtr SketchPlugin_Circle::getAISObject(AISObjectPtr thePrevious)
         if (aCircleShape && aRadius != 0) {
           std::list<std::shared_ptr<GeomAPI_Shape> > aShapes;
           // make a visible point
-          std::shared_ptr<GeomAPI_Shape> aCenterPointShape = GeomAlgoAPI_PointBuilder::point(aCenter);
+          std::shared_ptr<GeomAPI_Shape> aCenterPointShape = GeomAlgoAPI_PointBuilder::vertex(aCenter);
           aShapes.push_back(aCenterPointShape);
           aShapes.push_back(aCircleShape);
 
@@ -171,15 +140,45 @@ AISObjectPtr SketchPlugin_Circle::getAISObject(AISObjectPtr thePrevious)
   return AISObjectPtr();
 }
 
+bool SketchPlugin_Circle::isFeatureValid()
+{
+  std::shared_ptr<GeomDataAPI_Point2D> aCenter = 
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(CENTER_ID()));
+  bool aValid = aCenter->isInitialized();
+
+  std::string aType = std::dynamic_pointer_cast<ModelAPI_AttributeString>(
+                                         data()->attribute(CIRCLE_TYPE()))->value();
+  if (aType == CIRCLE_TYPE_THREE_POINTS()) {
+    std::shared_ptr<GeomDataAPI_Point2D> aFirstPnt =
+        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(FIRST_POINT_ID()));
+    std::shared_ptr<GeomDataAPI_Point2D> aSecondPnt =
+        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(SECOND_POINT_ID()));
+    std::shared_ptr<GeomDataAPI_Point2D> aThirdPnt =
+        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(THIRD_POINT_ID()));
+    aValid = aValid &&
+             aFirstPnt->isInitialized() &&
+             aSecondPnt->isInitialized() &&
+             aThirdPnt->isInitialized();
+  }
+  return aValid;
+}
+
 void SketchPlugin_Circle::move(double theDeltaX, double theDeltaY)
 {
   std::shared_ptr<ModelAPI_Data> aData = data();
   if (!aData->isValid())
     return;
 
-  std::shared_ptr<GeomDataAPI_Point2D> aPoint1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+  std::shared_ptr<GeomDataAPI_Point2D> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
       aData->attribute(CENTER_ID()));
-  aPoint1->move(theDeltaX, theDeltaY);
+  aPoint->move(theDeltaX, theDeltaY);
+
+  aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aData->attribute(FIRST_POINT_ID()));
+  aPoint->move(theDeltaX, theDeltaY);
+  aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aData->attribute(SECOND_POINT_ID()));
+  aPoint->move(theDeltaX, theDeltaY);
+  aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aData->attribute(THIRD_POINT_ID()));
+  aPoint->move(theDeltaX, theDeltaY);
 }
 
 bool SketchPlugin_Circle::isFixed() {
@@ -190,6 +189,12 @@ void SketchPlugin_Circle::attributeChanged(const std::string& theID) {
   // the second condition for unability to move external segments anywhere
   if (theID == EXTERNAL_ID() || isFixed()) {
     std::shared_ptr<GeomAPI_Shape> aSelection = data()->selection(EXTERNAL_ID())->value();
+    if (!aSelection) {
+      // empty shape in selection shows that the shape is equal to context
+      ResultPtr anExtRes = selection(EXTERNAL_ID())->context();
+      if (anExtRes)
+        aSelection = anExtRes->shape();
+    }
     // update arguments due to the selection value
     if (aSelection && !aSelection->isNull() && aSelection->isEdge()) {
       std::shared_ptr<GeomAPI_Edge> anEdge( new GeomAPI_Edge(aSelection));
@@ -203,43 +208,15 @@ void SketchPlugin_Circle::attributeChanged(const std::string& theID) {
   else if (theID == CENTER_ID() || theID == RADIUS_ID()) {
     std::string aType = std::dynamic_pointer_cast<ModelAPI_AttributeString>(
       data()->attribute(CIRCLE_TYPE()))->value();
-    if (aType == CIRCLE_TYPE_THREE_POINTS())
-      return;
-
-    std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr =
-        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(CENTER_ID()));
-    if (!aCenterAttr->isInitialized())
-      return;
-    AttributeDoublePtr aRadiusAttr = 
-      std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(attribute(RADIUS_ID()));
-    if (!aRadiusAttr->isInitialized())
-      return;
-
-    // check the execute() was called and the shape was built
-    if (!lastResult())
-      return;
-
-    data()->blockSendAttributeUpdated(true);
-    std::shared_ptr<GeomDataAPI_Point2D> aFirstPnt =
-        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(FIRST_POINT_ID()));
-    std::shared_ptr<GeomDataAPI_Point2D> aSecondPnt =
-        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(SECOND_POINT_ID()));
-    std::shared_ptr<GeomDataAPI_Point2D> aThirdPnt =
-        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(THIRD_POINT_ID()));
-    double aRadius = aRadiusAttr->value();
-    aFirstPnt->setValue(aCenterAttr->x() + aRadius, aCenterAttr->y());
-    aSecondPnt->setValue(aCenterAttr->x(), aCenterAttr->y() + aRadius);
-    aThirdPnt->setValue(aCenterAttr->x() - aRadius, aCenterAttr->y());
-    data()->blockSendAttributeUpdated(false);
-  }
-  else if (theID == FIRST_POINT_ID() || theID == SECOND_POINT_ID() || theID == THIRD_POINT_ID()) {
+    if (aType == CIRCLE_TYPE_THREE_POINTS() && lastResult())  // adjust data from the solver
+      adjustThreePoints();
+  } else if (theID == FIRST_POINT_ID() || theID == SECOND_POINT_ID() || theID == THIRD_POINT_ID()) {
+    // support the center and radius attributes enev in other mode: solver uses them
     std::string aType = std::dynamic_pointer_cast<ModelAPI_AttributeString>(
       data()->attribute(CIRCLE_TYPE()))->value();
     if (aType == CIRCLE_TYPE_CENTER_AND_RADIUS())
       return;
-
-    data()->blockSendAttributeUpdated(true);
-
+    data()->blockSendAttributeUpdated(true); // to modify two attributes at once
     std::shared_ptr<GeomAPI_Pnt2d> aPoints[3];
     int aNbInitialized = 0;
     for (int i = 1; i <= 3; ++i) {
@@ -263,45 +240,53 @@ void SketchPlugin_Circle::attributeChanged(const std::string& theID) {
       aCenterAttr->setValue(aCoord->x(), aCoord->y());
       aRadiusAttr->setValue(aRadius);
     } else {
-      std::shared_ptr<GeomAPI_Pnt2d> aCenter;
-      double aRadius;
-      calculateCircleOnThreePoints(aPoints[0], aPoints[1], aPoints[2], aCenter, aRadius);
+      std::shared_ptr<GeomAPI_Circ2d> aCircle(
+          new GeomAPI_Circ2d(aPoints[0], aPoints[1], aPoints[2]));
+
+      std::shared_ptr<GeomAPI_Pnt2d> aCenter = aCircle->center();
       if (aCenter) {
+        double aRadius = aCircle->radius();
         aCenterAttr->setValue(aCenter->x(), aCenter->y());
         aRadiusAttr->setValue(aRadius);
       }
     }
+    data()->blockSendAttributeUpdated(false, false);
 
-    data()->blockSendAttributeUpdated(false);
+  } else if (theID == CIRCLE_TYPE()) { // if switched to 3 points mode, adjust the needed attributes
+    std::string aType = std::dynamic_pointer_cast<ModelAPI_AttributeString>(
+      data()->attribute(CIRCLE_TYPE()))->value();
+    if (aType == CIRCLE_TYPE_THREE_POINTS()) {
+      adjustThreePoints();
+    }
   }
 }
 
-
-
-
-// ==========   Auxiliary functions   =========================
-void calculateCircleOnThreePoints(const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPnt,
-                                  const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPnt,
-                                  const std::shared_ptr<GeomAPI_Pnt2d>& theThirdPnt,
-                                        std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
-                                        double&                         theRadius)
+void SketchPlugin_Circle::adjustThreePoints()
 {
-  std::shared_ptr<GeomAPI_XY> aVec12 = theSecondPnt->xy()->decreased(theFirstPnt->xy());
-  std::shared_ptr<GeomAPI_XY> aVec23 = theThirdPnt->xy()->decreased(theSecondPnt->xy());
-  std::shared_ptr<GeomAPI_XY> aVec31 = theFirstPnt->xy()->decreased(theThirdPnt->xy());
-  // square of parallelogram
-  double aSquare2 = aVec12->cross(aVec23);
-  aSquare2 *= aSquare2 * 2.0;
-  if (aSquare2 < 1.e-20)
+  std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr =
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(CENTER_ID()));
+  if (!aCenterAttr->isInitialized())
+    return;
+  AttributeDoublePtr aRadiusAttr = 
+    std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(attribute(RADIUS_ID()));
+  if (!aRadiusAttr->isInitialized())
     return;
-  // coefficients to calculate center
-  double aCoeff1 = aVec23->dot(aVec23) / aSquare2 * aVec12->dot(aVec31->multiplied(-1.0));
-  double aCoeff2 = aVec31->dot(aVec31) / aSquare2 * aVec23->dot(aVec12->multiplied(-1.0));
-  double aCoeff3 = aVec12->dot(aVec12) / aSquare2 * aVec31->dot(aVec23->multiplied(-1.0));
-  // center
-  std::shared_ptr<GeomAPI_XY> aCenter = theFirstPnt->xy()->multiplied(aCoeff1)->added(
-      theSecondPnt->xy()->multiplied(aCoeff2))->added(theThirdPnt->xy()->multiplied(aCoeff3));
-  theCenter = std::shared_ptr<GeomAPI_Pnt2d>(new GeomAPI_Pnt2d(aCenter));
-  // radius
-  theRadius = theFirstPnt->distance(theCenter);
+
+  data()->blockSendAttributeUpdated(true);
+  std::shared_ptr<GeomDataAPI_Point2D> aFirstPnt =
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(FIRST_POINT_ID()));
+  std::shared_ptr<GeomDataAPI_Point2D> aSecondPnt =
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(SECOND_POINT_ID()));
+  std::shared_ptr<GeomDataAPI_Point2D> aThirdPnt =
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(THIRD_POINT_ID()));
+  double aRadius = aRadiusAttr->value();
+
+  if (fabs(aFirstPnt->pnt()->distance(aCenterAttr->pnt()) - aRadius) > tolerance ||
+      fabs(aSecondPnt->pnt()->distance(aCenterAttr->pnt()) - aRadius) > tolerance ||
+      fabs(aThirdPnt->pnt()->distance(aCenterAttr->pnt()) - aRadius) > tolerance) {
+    aFirstPnt->setValue(aCenterAttr->x() + aRadius, aCenterAttr->y());
+    aSecondPnt->setValue(aCenterAttr->x(), aCenterAttr->y() + aRadius);
+    aThirdPnt->setValue(aCenterAttr->x() - aRadius, aCenterAttr->y());
+  }
+  data()->blockSendAttributeUpdated(false, false);
 }