-// 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()
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()
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);
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;