Salome HOME
updated copyright message
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_Arc.cpp
index 9ebf16eb34205e343f114a511be0a5eb0e9ba60f..0eb84450c4e5dbbbf75634280721b4d011754fde 100644 (file)
@@ -1,8 +1,21 @@
-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
-
-// File:        SketchPlugin_Arc.cpp
-// Created:     26 Apr 2014
-// Author:      Artem ZHIDKOV
+// Copyright (C) 2014-2023  CEA, EDF
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
 
 #include "SketchPlugin_Arc.h"
 #include "SketchPlugin_Sketch.h"
 #include <GeomAlgoAPI_EdgeBuilder.h>
 #include <GeomAlgoAPI_CompoundBuilder.h>
 // for sqrt on Linux
-#include <math.h>
+#include <cmath>
 
-const double tolerance = 1e-7;
-const double paramTolerance = 1.e-4;
-const double PI = 3.141592653589793238463;
+static const double tolerance = 1e-7;
+static const double paramTolerance = 1.e-4;
+static const double PI = 3.141592653589793238463;
 
 
 SketchPlugin_Arc::SketchPlugin_Arc()
@@ -99,44 +112,47 @@ void SketchPlugin_Arc::execute()
       aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
   std::shared_ptr<GeomAPI_Dir> aNormal(new GeomAPI_Dir(aNDir->x(), aNDir->y(), aNDir->z()));
 
-  GeomShapePtr anArcShape = boolean(REVERSED_ID())->value() ?
-      GeomAlgoAPI_EdgeBuilder::lineCircleArc(aCenter, anEnd, aStart, aNormal)
-    : GeomAlgoAPI_EdgeBuilder::lineCircleArc(aCenter, aStart, anEnd, aNormal);
-
-  std::shared_ptr<ModelAPI_ResultConstruction> aResult = document()->createConstruction(data(), 1);
-  aResult->setShape(anArcShape);
-  aResult->setIsInHistory(false);
-  setResult(aResult, 1);
-}
-
-void SketchPlugin_Arc::move(double theDeltaX, double theDeltaY)
-{
-  std::shared_ptr<ModelAPI_Data> aData = data();
-  if(!aData->isValid()) {
-    return;
+  if (myParamBefore == 0) { // parameter has not been calculate yet
+    std::shared_ptr<GeomAPI_Circ2d> aCircleForArc(
+        new GeomAPI_Circ2d(aCenterAttr->pnt(), aStartAttr->pnt()));
+    aCircleForArc->parameter(anEndAttr->pnt(), paramTolerance, myParamBefore);
   }
 
-  bool aWasBlocked = aData->blockSendAttributeUpdated(true);
-
-  std::shared_ptr<GeomDataAPI_Point2D> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      attribute(CENTER_ID()));
-  if(aCenter->isInitialized()) {
-    aCenter->move(theDeltaX, theDeltaY);
-  }
+  bool isReversed = boolean(REVERSED_ID())->value();
 
-  std::shared_ptr<GeomDataAPI_Point2D> aStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      attribute(START_ID()));
-  if(aStart->isInitialized()) {
-    aStart->move(theDeltaX, theDeltaY);
+  GeomEdgePtr anArcShape;
+  if (fabs(myParamBefore - 2.0 * PI) < paramTolerance) {
+    anArcShape = GeomAlgoAPI_EdgeBuilder::lineCircle(aCenter, aNormal, aStart->distance(aCenter));
+    myParamBefore = 0;
+  } else {
+    anArcShape = isReversed ?
+      GeomAlgoAPI_EdgeBuilder::lineCircleArc(aCenter, anEnd, aStart, aNormal)
+    : GeomAlgoAPI_EdgeBuilder::lineCircleArc(aCenter, aStart, anEnd, aNormal);
   }
 
-  std::shared_ptr<GeomDataAPI_Point2D> anEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      attribute(END_ID()));
-  if(anEnd->isInitialized()) {
-    anEnd->move(theDeltaX, theDeltaY);
+  // calculate tolerances for start and end points of the arc and set them to the result shape
+  // (this is done to fix gaps which appear because of inaccurate computation of arcs in PlaneGCS,
+  // which leads to difference in SketchPlugin_Arc attributes and boundary points of result shape)
+  if (anArcShape) {
+    for (int ind = 0; ind < 2; ++ind) {
+      bool isFirst = ind == 0;
+      GeomPointPtr anArcBndPoint = isFirst == isReversed ? anEnd : aStart;
+      GeomPointPtr aShapePoint = isFirst ? anArcShape->firstPoint() : anArcShape->lastPoint();
+      double aDistance = anArcBndPoint->distance(aShapePoint);
+      // avoid setting too high tolerance because it may be caused by incomplete update of an arc
+      if (aDistance > tolerance && aDistance < 100. * tolerance) {
+        if (isFirst)
+          anArcShape->setFirstPointTolerance(aDistance);
+        else
+          anArcShape->setLastPointTolerance(aDistance);
+      }
+    }
   }
 
-  aData->blockSendAttributeUpdated(aWasBlocked);
+  std::shared_ptr<ModelAPI_ResultConstruction> aResult = document()->createConstruction(data(), 1);
+  aResult->setShape(anArcShape);
+  aResult->setIsInHistory(false);
+  setResult(aResult, 1);
 }
 
 bool SketchPlugin_Arc::isFixed()
@@ -190,8 +206,17 @@ void SketchPlugin_Arc::attributeChanged(const std::string& theID)
         aCirc->parameter(anEdge->firstPoint(), paramTolerance, aStartParam);
         aCirc->parameter(aMinPnt, paramTolerance, aMidParam);
         aCirc->parameter(anEdge->lastPoint(), paramTolerance, anEndParam);
+
+        // adjust period
+        anEndParam -= aStartParam;
+        aMidParam -= aStartParam;
+        if (anEndParam < 0.0)
+          anEndParam += 2.0 * PI;
+        if (aMidParam < 0.0)
+          aMidParam += 2.0 * PI;
+
         aWasBlocked = data()->blockSendAttributeUpdated(true);
-        if(aStartParam < aMidParam && aMidParam < anEndParam) {
+        if(aMidParam < anEndParam) {
           setReversed(false);
         } else {
           setReversed(true);
@@ -213,31 +238,28 @@ void SketchPlugin_Arc::attributeChanged(const std::string& theID)
       return;
     std::shared_ptr<GeomAPI_Circ2d> aCircleForArc(new GeomAPI_Circ2d(aCenter, aStart));
 
-    bool aWasBlocked = data()->blockSendAttributeUpdated(true);
-    // The Arc end point is projected
-    // on the circle formed by center and start points
+    // Do not recalculate REVERSED flag if the arc is not consistent
     std::shared_ptr<GeomAPI_Pnt2d> aProjection = aCircleForArc->project(anEnd);
-    if (aProjection && anEnd->distance(aProjection) > tolerance) {
-      anEndAttr->setValue(aProjection);
-      anEnd = aProjection;
-    }
-    data()->blockSendAttributeUpdated(aWasBlocked, false);
-
-    double aParameterNew = 0.0;
-    if(aCircleForArc->parameter(anEnd, paramTolerance, aParameterNew)) {
-      bool aWasBlocked = data()->blockSendAttributeUpdated(true);
-      if(myParamBefore <= PI / 2.0 && aParameterNew >= PI * 1.5) {
-        if(!boolean(REVERSED_ID())->value()) {
-          boolean(REVERSED_ID())->setValue(true);
-        }
-      } else if(myParamBefore >= PI * 1.5 && aParameterNew <= PI / 2.0) {
-        if(boolean(REVERSED_ID())->value()) {
-          boolean(REVERSED_ID())->setValue(false);
+    if (aProjection && anEnd->distance(aProjection) <= tolerance) {
+      double aParameterNew = 0.0;
+      if(aCircleForArc->parameter(anEnd, paramTolerance, aParameterNew)) {
+        bool aWasBlocked = data()->blockSendAttributeUpdated(true);
+        if(myParamBefore <= PI / 2.0 && aParameterNew >= PI * 1.5) {
+          if(!boolean(REVERSED_ID())->value()) {
+            boolean(REVERSED_ID())->setValue(true);
+          }
+        } else if(myParamBefore >= PI * 1.5 && aParameterNew <= PI / 2.0) {
+          if(boolean(REVERSED_ID())->value()) {
+            boolean(REVERSED_ID())->setValue(false);
+          }
         }
+        data()->blockSendAttributeUpdated(aWasBlocked, false);
       }
-      data()->blockSendAttributeUpdated(aWasBlocked, false);
+      if (fabs(aParameterNew) < paramTolerance ||
+          fabs(aParameterNew - 2.0 * PI) < paramTolerance)
+        aParameterNew = 2.0 * PI;
+      myParamBefore = aParameterNew;
     }
-    myParamBefore = aParameterNew;
   }
 
   double aRadius = 0;