-// Copyright (C) 2017-2019 CEA/DEN, EDF R&D
+// Copyright (C) 2017-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
#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)
{
}
}
// 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()
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;
}
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);