Salome HOME
Renamed SHAPER_CONFIG_FILE to PLUGINS_CONFIG_FILE
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_Arc.cpp
index ac9981b002ce4684a3a5921d617f1d7c321bec49..6060698560e9d993f662a5e053b92c5ee3fad3f8 100644 (file)
@@ -42,11 +42,6 @@ const double paramTolerance = 1.e-4;
 const double PI =3.141592653589793238463;
 
 namespace {
-  /*static const std::string& ARC_TYPE()
-  {
-    static const std::string TYPE("ArcType");
-    return TYPE;
-  }*/
   static const std::string& ARC_TYPE_CENTER_START_END()
   {
     static const std::string TYPE("CenterStartEnd");
@@ -57,22 +52,12 @@ namespace {
     static const std::string TYPE("ThreePoints");
     return TYPE;
   }
-  /*static const std::string& ARC_TYPE_TANGENT()
-  {
-    static const std::string TYPE("Tangent");
-    return TYPE;
-  }*/
 
   static const std::string& PASSED_POINT_ID()
   {
     static const std::string PASSED_PNT("ArcPassedPoint");
     return PASSED_PNT;
   }
-  static const std::string& TANGENT_POINT_ID()
-  {
-    static const std::string TANGENT_PNT("ArcTangentPoint");
-    return TANGENT_PNT;
-  }
   static const std::string& RADIUS_ID()
   {
     static const std::string RADIUS("ArcRadius");
@@ -381,6 +366,10 @@ static inline void calculatePassedPoint(
     bool theArcReversed,
     std::shared_ptr<GeomDataAPI_Point2D> thePassedPoint)
 {
+  if (theCenter->distance(theStartPoint) < tolerance ||
+      theCenter->distance(theEndPoint) < tolerance)
+    return;
+
   std::shared_ptr<GeomAPI_Dir2d> aStartDir(new GeomAPI_Dir2d(
       theStartPoint->xy()->decreased(theCenter->xy())));
   std::shared_ptr<GeomAPI_Dir2d> aEndDir(new GeomAPI_Dir2d(
@@ -425,8 +414,9 @@ void SketchPlugin_Arc::updateDependentAttributes()
   if (aRadiusAttr && anAngleAttr) {
     std::shared_ptr<GeomAPI_Circ2d> aCircle(
         new GeomAPI_Circ2d(aStartAttr->pnt(), anEndAttr->pnt(), aPassedPoint->pnt()));
-    calculateArcAngleRadius(aCircle, aStartAttr->pnt(), anEndAttr->pnt(), aPassedPoint->pnt(),
-                            anAngleAttr, aRadiusAttr);
+    if (aCircle->implPtr<void*>())
+      calculateArcAngleRadius(aCircle, aStartAttr->pnt(), anEndAttr->pnt(), aPassedPoint->pnt(),
+                              anAngleAttr, aRadiusAttr);
   }
   data()->blockSendAttributeUpdated(false);
 }
@@ -465,14 +455,14 @@ void SketchPlugin_Arc::attributeChanged(const std::string& theID)
     if (!aStartAttr->isInitialized() || !anEndAttr->isInitialized())
       return;
     // move center and passed point
-    std::shared_ptr<GeomAPI_Pnt2d> aStartPnt = aStartAttr->pnt();
-    std::shared_ptr<GeomAPI_Pnt2d> aEndPnt = anEndAttr->pnt();
+    std::shared_ptr<GeomAPI_XY> aStartPnt = aStartAttr->pnt()->xy();
+    std::shared_ptr<GeomAPI_XY> aEndPnt = anEndAttr->pnt()->xy();
     double aDist = aStartPnt->distance(aEndPnt);
     if (fabs(aDist) < tolerance)
       return;
-    std::shared_ptr<GeomAPI_XY> aDir = aEndPnt->xy()->decreased(aStartPnt->xy());
+    std::shared_ptr<GeomAPI_Dir2d> aDir(new GeomAPI_Dir2d(aEndPnt->decreased(aStartPnt)));
     std::shared_ptr<GeomAPI_Dir2d> aMidPerpDir(new GeomAPI_Dir2d(-aDir->y(), aDir->x()));
-    std::shared_ptr<GeomAPI_XY> aMidPnt = aStartPnt->xy()->added(aEndPnt->xy())->multiplied(0.5);
+    std::shared_ptr<GeomAPI_XY> aMidPnt = aStartPnt->added(aEndPnt)->multiplied(0.5);
 
     double anAngle = anAngleAttr->value() * PI / 180.0;
     adjustPeriod(anAngle);
@@ -480,12 +470,21 @@ void SketchPlugin_Arc::attributeChanged(const std::string& theID)
       aMidPerpDir->reverse();
 
     double aRadius = aRadiusAttr->value();
-    aDist = sqrt(aRadius * aRadius - aDist * aDist / 4.0);
+    // The center is placed on a perpendicular bisector of a start-end points segment.
+    // If the radius is smaller that necessary, start and end points are moved too.
+    double aDist2 = aRadius * aRadius - aDist * aDist / 4.0;
+    aDist = aDist2 > 0.0 ? sqrt(aDist2) : 0.0;
+    // distance between middle point and start point (does not changed if the arc diameter is greater than start-end distance)
+    aDist2 = sqrt(aRadius * aRadius - aDist * aDist);
 
     std::shared_ptr<GeomAPI_XY> aCenter = aMidPnt->added(aMidPerpDir->xy()->multiplied(aDist));
+    aStartPnt = aMidPnt->added(aDir->xy()->multiplied(-aDist2));
+    aEndPnt = aMidPnt->added(aDir->xy()->multiplied(aDist2));
 
     data()->blockSendAttributeUpdated(true);
     aCenterAttr->setValue(aCenter->x(), aCenter->y());
+    aStartAttr->setValue(aStartPnt->x(), aStartPnt->y());
+    anEndAttr->setValue(aEndPnt->x(), aEndPnt->y());
     updateDependentAttributes();
     data()->blockSendAttributeUpdated(false);
     return;
@@ -524,19 +523,8 @@ void SketchPlugin_Arc::attributeChanged(const std::string& theID)
   }
 
   if (theID == CENTER_ID()) {
-    if (!isFeatureValid())
-      return;
-    if (aCenterAttr->pnt()->distance(aStartAttr->pnt()) < tolerance)
-      return;
-    data()->blockSendAttributeUpdated(true);
-    // compute and change the arc end point
-    std::shared_ptr<GeomAPI_Circ2d> aCircleForArc(
-        new GeomAPI_Circ2d(aCenterAttr->pnt(), aStartAttr->pnt()));
-    std::shared_ptr<GeomAPI_Pnt2d> aProjection = aCircleForArc->project(anEndAttr->pnt());
-    if (aProjection && anEndAttr->pnt()->distance(aProjection) > tolerance)
-      anEndAttr->setValue(aProjection);
-    updateDependentAttributes();
-    data()->blockSendAttributeUpdated(false);
+    if (isFeatureValid())
+      projectEndPoint();
     return;
   }
 
@@ -550,6 +538,11 @@ void SketchPlugin_Arc::attributeChanged(const std::string& theID)
   if (anArcType == ARC_TYPE_CENTER_START_END()) {
     if (!isFeatureValid())
       return;
+    if (theID == END_ID() && isStable()) {
+      // The arc is under construction, so its end point projected
+      // on the circle formed by center and start points
+      projectEndPoint();
+    }
     updateDependentAttributes();
   }
   else if (anArcType == ARC_TYPE_THREE_POINTS() &&
@@ -807,3 +800,25 @@ void SketchPlugin_Arc::tangencyArcConstraints()
       Events_Loop::loop()->setFlushed(anUpdateEvent, true);
   }
 }
+
+void SketchPlugin_Arc::projectEndPoint()
+{
+  std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr = std::dynamic_pointer_cast<
+      GeomDataAPI_Point2D>(data()->attribute(CENTER_ID()));
+  std::shared_ptr<GeomDataAPI_Point2D> aStartAttr = std::dynamic_pointer_cast<
+      GeomDataAPI_Point2D>(data()->attribute(START_ID()));
+  std::shared_ptr<GeomDataAPI_Point2D> anEndAttr = std::dynamic_pointer_cast<
+      GeomDataAPI_Point2D>(data()->attribute(END_ID()));
+
+  if (aCenterAttr->pnt()->distance(aStartAttr->pnt()) < tolerance)
+    return;
+  data()->blockSendAttributeUpdated(true);
+  // compute and change the arc end point
+  std::shared_ptr<GeomAPI_Circ2d> aCircleForArc(
+      new GeomAPI_Circ2d(aCenterAttr->pnt(), aStartAttr->pnt()));
+  std::shared_ptr<GeomAPI_Pnt2d> aProjection = aCircleForArc->project(anEndAttr->pnt());
+  if (aProjection && anEndAttr->pnt()->distance(aProjection) > tolerance)
+    anEndAttr->setValue(aProjection);
+  updateDependentAttributes();
+  data()->blockSendAttributeUpdated(false);
+}