Salome HOME
Fix for the issue #3195 : The groups built by "Group Addtion" are not in ShaperResults
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_EllipticArc.cpp
index 3bc24f1ccee81a5aeaf4f8c2db99d444f84c0ee8..5b8b109e0da138311ee30446dd82cd4d8032abe6 100644 (file)
@@ -25,7 +25,9 @@
 #include <GeomAPI_Dir2d.h>
 #include <GeomAPI_Edge.h>
 #include <GeomAPI_Ellipse.h>
+#include <GeomAPI_Ellipse2d.h>
 #include <GeomAPI_Pnt2d.h>
+#include <GeomAPI_XY.h>
 
 #include <GeomDataAPI_Point2D.h>
 
 #include <cmath>
 
 static const double tolerance = 1e-7;
+static const double paramTolerance = 1.e-4;
+static const double PI = 3.141592653589793238463;
 
 
 SketchPlugin_EllipticArc::SketchPlugin_EllipticArc()
-: SketchPlugin_SketchEntity()
+  : SketchPlugin_SketchEntity(),
+    myParamDelta(0.0)
 {
 }
 
@@ -102,29 +107,63 @@ void SketchPlugin_EllipticArc::attributeChanged(const std::string& theID) {
     }
     // update arguments due to the selection value
     if (aSelection && !aSelection->isNull() && aSelection->isEdge()) {
-      std::shared_ptr<GeomAPI_Edge> anEdge( new GeomAPI_Edge(aSelection));
+      std::shared_ptr<GeomAPI_Edge> anEdge(new GeomAPI_Edge(aSelection));
       std::shared_ptr<GeomAPI_Ellipse> anEllipse = anEdge->ellipse();
 
+      bool aWasBlocked = data()->blockSendAttributeUpdated(true);
       std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr =
-          std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(CENTER_ID()));
+        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(CENTER_ID()));
       aCenterAttr->setValue(sketch()->to2D(anEllipse->center()));
 
       std::shared_ptr<GeomDataAPI_Point2D> aFocusAttr =
-          std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(FIRST_FOCUS_ID()));
+        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(FIRST_FOCUS_ID()));
       aFocusAttr->setValue(sketch()->to2D(anEllipse->firstFocus()));
 
       std::shared_ptr<GeomDataAPI_Point2D> aStartAttr =
-          std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(START_POINT_ID()));
+        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(START_POINT_ID()));
       aStartAttr->setValue(sketch()->to2D(anEdge->firstPoint()));
 
       std::shared_ptr<GeomDataAPI_Point2D> aEndAttr =
-          std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(END_POINT_ID()));
+        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(END_POINT_ID()));
       aEndAttr->setValue(sketch()->to2D(anEdge->lastPoint()));
 
       real(MAJOR_RADIUS_ID())->setValue(anEllipse->majorRadius());
       real(MINOR_RADIUS_ID())->setValue(anEllipse->minorRadius());
+
+      double aStartParam, aMidParam, aEndParam;
+      anEllipse->parameter(anEdge->firstPoint(), tolerance, aStartParam);
+      anEllipse->parameter(anEdge->middlePoint(), tolerance, aMidParam);
+      anEllipse->parameter(anEdge->lastPoint(), tolerance, aEndParam);
+      if (aEndParam < aStartParam)
+        aEndParam += 2.0 * PI;
+      if (aMidParam < aStartParam)
+        aMidParam += 2.0 * PI;
+      boolean(REVERSED_ID())->setValue(aMidParam > aEndParam);
+
+      data()->blockSendAttributeUpdated(aWasBlocked, false);
+
+      fillCharacteristicPoints();
     }
   }
+  else if (theID == CENTER_ID() || theID == FIRST_FOCUS_ID() ||
+           theID == START_POINT_ID() || theID == END_POINT_ID())
+    fillCharacteristicPoints();
+  else if (theID == REVERSED_ID() && myParamDelta == 0.0)
+    myParamDelta = 2.0 * PI;
+}
+
+static void calculateRadii(const GeomPnt2dPtr& theCenter,
+                           const GeomPnt2dPtr& theFocus,
+                           const GeomPnt2dPtr& thePassed,
+                           double& theMajorRadius,
+                           double& theMinorRadius)
+{
+  GeomPnt2dPtr aSecondFocus(new GeomAPI_Pnt2d(
+      theCenter->xy()->multiplied(2.0)->decreased(theFocus->xy())));
+  theMajorRadius = 0.5 * (thePassed->distance(theFocus) + thePassed->distance(aSecondFocus));
+
+  double aFocalDist = theCenter->distance(theFocus);
+  theMinorRadius = sqrt(theMajorRadius * theMajorRadius - aFocalDist * aFocalDist);
 }
 
 bool SketchPlugin_EllipticArc::fillCharacteristicPoints()
@@ -133,47 +172,74 @@ bool SketchPlugin_EllipticArc::fillCharacteristicPoints()
       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(CENTER_ID()));
   std::shared_ptr<GeomDataAPI_Point2D> aFocusAttr =
       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(FIRST_FOCUS_ID()));
-
-  AttributeDoublePtr aMinorRadiusAttr = real(MINOR_RADIUS_ID());
+  std::shared_ptr<GeomDataAPI_Point2D> aStartPointAttr =
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(START_POINT_ID()));
+  std::shared_ptr<GeomDataAPI_Point2D> aEndPointAttr =
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(END_POINT_ID()));
 
   if (!aCenterAttr->isInitialized() ||
       !aFocusAttr->isInitialized() ||
-      !aMinorRadiusAttr->isInitialized()) {
-    return false;
-  }
-
-  double aMinorRadius = aMinorRadiusAttr->value();
-  if (aMinorRadius < tolerance) {
+      !aStartPointAttr->isInitialized()) {
     return false;
   }
 
-  data()->blockSendAttributeUpdated(true);
   GeomPnt2dPtr aCenter2d = aCenterAttr->pnt();
   GeomPnt2dPtr aFocus2d = aFocusAttr->pnt();
+  GeomPnt2dPtr aStart2d = aStartPointAttr->pnt();
+
+  double aMajorRadius = 0.0, aMinorRadius = 0.0;
+  calculateRadii(aCenter2d, aFocus2d, aStart2d, aMajorRadius, aMinorRadius);
+  if (aMinorRadius < tolerance * aMajorRadius)
+    return false;
+
+  bool aWasBlocked = data()->blockSendAttributeUpdated(true);
+  real(MAJOR_RADIUS_ID())->setValue(aMajorRadius);
+  real(MINOR_RADIUS_ID())->setValue(aMinorRadius);
+
   GeomDir2dPtr aMajorDir2d(new GeomAPI_Dir2d(aFocus2d->x() - aCenter2d->x(),
-                                             aFocus2d->y() - aCenter2d->y()));
+    aFocus2d->y() - aCenter2d->y()));
   GeomDir2dPtr aMinorDir2d(new GeomAPI_Dir2d(-aMajorDir2d->y(), aMajorDir2d->x()));
 
-  AttributeDoublePtr aMajorRadiusAttr = real(MAJOR_RADIUS_ID());
-  double aFocalDist = aCenter2d->distance(aFocus2d);
-  double aMajorRadius = sqrt(aFocalDist * aFocalDist + aMinorRadius * aMinorRadius);
-  aMajorRadiusAttr->setValue(aMajorRadius);
-
   std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(SECOND_FOCUS_ID()))
     ->setValue(2.0 * aCenter2d->x() - aFocus2d->x(), 2.0 * aCenter2d->y() - aFocus2d->y());
   std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(MAJOR_AXIS_START_ID()))
-      ->setValue(aCenter2d->x() - aMajorDir2d->x() * aMajorRadius,
-                 aCenter2d->y() - aMajorDir2d->y() * aMajorRadius);
+    ->setValue(aCenter2d->x() - aMajorDir2d->x() * aMajorRadius,
+               aCenter2d->y() - aMajorDir2d->y() * aMajorRadius);
   std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(MAJOR_AXIS_END_ID()))
-      ->setValue(aCenter2d->x() + aMajorDir2d->x() * aMajorRadius,
-                 aCenter2d->y() + aMajorDir2d->y() * aMajorRadius);
+    ->setValue(aCenter2d->x() + aMajorDir2d->x() * aMajorRadius,
+               aCenter2d->y() + aMajorDir2d->y() * aMajorRadius);
   std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(MINOR_AXIS_START_ID()))
-      ->setValue(aCenter2d->x() - aMinorDir2d->x() * aMinorRadius,
-                 aCenter2d->y() - aMinorDir2d->y() * aMinorRadius);
+    ->setValue(aCenter2d->x() - aMinorDir2d->x() * aMinorRadius,
+               aCenter2d->y() - aMinorDir2d->y() * aMinorRadius);
   std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(MINOR_AXIS_END_ID()))
-      ->setValue(aCenter2d->x() + aMinorDir2d->x() * aMinorRadius,
-                 aCenter2d->y() + aMinorDir2d->y() * aMinorRadius);
-  data()->blockSendAttributeUpdated(false);
+    ->setValue(aCenter2d->x() + aMinorDir2d->x() * aMinorRadius,
+               aCenter2d->y() + aMinorDir2d->y() * aMinorRadius);
+
+  if (aEndPointAttr->isInitialized()) {
+    // recalculate REVERSED flag
+    std::shared_ptr<GeomAPI_Ellipse2d> anEllipseForArc(
+        new GeomAPI_Ellipse2d(aCenter2d, aMajorDir2d, aMajorRadius, aMinorRadius));
+    GeomPnt2dPtr anEnd = aEndPointAttr->pnt();
+    std::shared_ptr<GeomAPI_Pnt2d> aProjection = anEllipseForArc->project(anEnd);
+    double aParamStart = 0.0, aParamEnd = 0.0;
+    if (aProjection && anEnd->distance(aProjection) <= tolerance &&
+        anEllipseForArc->parameter(anEnd, paramTolerance, aParamEnd)) {
+      // do not recalculate REVERSED flag if the arc is not consistent
+      anEllipseForArc->parameter(aStart2d, paramTolerance, aParamStart);
+      aParamEnd -= aParamStart;
+
+      if (myParamDelta >= 0.0 && myParamDelta <= PI * 0.5 &&
+          aParamEnd < 0.0 && aParamEnd >= -PI * 0.5) {
+        boolean(REVERSED_ID())->setValue(true);
+      }
+      else if (myParamDelta <= 0.0 && myParamDelta >= -PI * 0.5 &&
+               aParamEnd > 0.0 && aParamEnd <= PI * 0.5) {
+        boolean(REVERSED_ID())->setValue(false);
+      }
+      myParamDelta = aParamEnd;
+    }
+  }
+  data()->blockSendAttributeUpdated(aWasBlocked, false);
 
   return true;
 }
@@ -207,6 +273,8 @@ void SketchPlugin_EllipticArc::createEllipticArc(SketchPlugin_Sketch* theSketch)
 
     GeomPointPtr aStartPnt(theSketch->to3D(aStartAttr->x(), aStartAttr->y()));
     GeomPointPtr aEndPnt(theSketch->to3D(aEndAttr->x(), aEndAttr->y()));
+    if (boolean(REVERSED_ID())->value())
+      std::swap(aStartPnt, aEndPnt);
 
     anEllipseShape = GeomAlgoAPI_EdgeBuilder::ellipticArc(aCenter, aNormal, aMajorAxis,
         aMajorRadius, aMinorRadius, aStartPnt, aEndPnt);