From d2026409659dfa0a142d1b018b3cec5d94932a7a Mon Sep 17 00:00:00 2001 From: azv Date: Tue, 24 Sep 2019 14:37:55 +0300 Subject: [PATCH] Task 2.12. New entities: ellipses and arcs of ellipses (issue #3003) Implementation of elliptical arc and processing its modification in 3D viewer. --- src/GeomAPI/GeomAPI_Ellipse.cpp | 10 + src/GeomAPI/GeomAPI_Ellipse.h | 13 + src/GeomAPI/GeomAPI_Ellipse2d.cpp | 31 ++ src/GeomAPI/GeomAPI_Ellipse2d.h | 17 + src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.cpp | 30 ++ src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.h | 11 + src/SketchPlugin/CMakeLists.txt | 4 + src/SketchPlugin/SketchPlugin_EllipticArc.cpp | 223 ++++++++++ src/SketchPlugin/SketchPlugin_EllipticArc.h | 149 +++++++ .../SketchPlugin_MacroEllipse.cpp | 85 +--- src/SketchPlugin/SketchPlugin_MacroEllipse.h | 8 - .../SketchPlugin_MacroEllipticArc.cpp | 413 ++++++++++++++++++ .../SketchPlugin_MacroEllipticArc.h | 176 ++++++++ src/SketchPlugin/SketchPlugin_Plugin.cpp | 8 + src/SketchPlugin/SketchPlugin_Tools.cpp | 64 +++ src/SketchPlugin/SketchPlugin_Tools.h | 15 + src/SketchPlugin/SketchPlugin_Validators.cpp | 2 +- src/SketchPlugin/plugin-Sketch.xml | 204 +++++++-- .../PlaneGCSSolver_EdgeWrapper.cpp | 76 +++- .../PlaneGCSSolver_FeatureBuilder.cpp | 87 +++- .../PlaneGCSSolver/PlaneGCSSolver_Storage.cpp | 109 +++-- .../PlaneGCSSolver/PlaneGCSSolver_Tools.cpp | 84 +++- .../PlaneGCSSolver/PlaneGCSSolver_Tools.h | 5 + .../SketchSolver_ConstraintFixed.cpp | 12 + .../SketchSolver_ConstraintMovement.cpp | 20 +- 25 files changed, 1646 insertions(+), 210 deletions(-) create mode 100644 src/SketchPlugin/SketchPlugin_EllipticArc.cpp create mode 100644 src/SketchPlugin/SketchPlugin_EllipticArc.h create mode 100644 src/SketchPlugin/SketchPlugin_MacroEllipticArc.cpp create mode 100644 src/SketchPlugin/SketchPlugin_MacroEllipticArc.h diff --git a/src/GeomAPI/GeomAPI_Ellipse.cpp b/src/GeomAPI/GeomAPI_Ellipse.cpp index 243be630e..86a0391cb 100644 --- a/src/GeomAPI/GeomAPI_Ellipse.cpp +++ b/src/GeomAPI/GeomAPI_Ellipse.cpp @@ -28,6 +28,7 @@ #include #include +#include #include #define MY_ELIPS implPtr() @@ -101,3 +102,12 @@ const std::shared_ptr GeomAPI_Ellipse::project( } return aResult; } + +const bool GeomAPI_Ellipse::parameter(const std::shared_ptr thePoint, + const double theTolerance, + double& theParameter) const +{ + Handle(Geom_Ellipse) aCurve = new Geom_Ellipse(*MY_ELIPS); + return GeomLib_Tool::Parameter(aCurve, thePoint->impl(), + theTolerance, theParameter) == Standard_True; +} diff --git a/src/GeomAPI/GeomAPI_Ellipse.h b/src/GeomAPI/GeomAPI_Ellipse.h index dc41993a0..9f1be781a 100644 --- a/src/GeomAPI/GeomAPI_Ellipse.h +++ b/src/GeomAPI/GeomAPI_Ellipse.h @@ -77,6 +77,19 @@ public: /// Project point on ellipse GEOMAPI_EXPORT const std::shared_ptr project( const std::shared_ptr& thePoint) const; + + /** \brief Computes the parameter of a given point on an ellipse. The point must be + * located either on the circle itself or relatively to the latter + * at a distance less than the tolerance value. Return FALSE if the point + * is beyond the tolerance limit or if computation fails. + * Max Tolerance value is currently limited to 1.e-4 + * \param[in] thePoint point of origin. + * \param[in] theTolerance tolerance of computation. + * \param[out] theParameter resulting parameter. + */ + GEOMAPI_EXPORT const bool parameter(const std::shared_ptr thePoint, + const double theTolerance, + double& theParameter) const; }; //! Pointer on the object diff --git a/src/GeomAPI/GeomAPI_Ellipse2d.cpp b/src/GeomAPI/GeomAPI_Ellipse2d.cpp index 4a4c9950d..7db3ef8a4 100644 --- a/src/GeomAPI/GeomAPI_Ellipse2d.cpp +++ b/src/GeomAPI/GeomAPI_Ellipse2d.cpp @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include #include #include @@ -169,3 +171,32 @@ double GeomAPI_Ellipse2d::distance(const std::shared_ptr& the delete anExtema; return aDistance; } + +const std::shared_ptr GeomAPI_Ellipse2d::project( + const std::shared_ptr& thePoint) const +{ + std::shared_ptr aResult; + if (!MY_ELLIPSE) + return aResult; + + Handle(Geom2d_Ellipse) aEllipse = new Geom2d_Ellipse(*MY_ELLIPSE); + + const gp_Pnt2d& aPoint = thePoint->impl(); + + Geom2dAPI_ProjectPointOnCurve aProj(aPoint, aEllipse); + Standard_Integer aNbPoint = aProj.NbPoints(); + if (aNbPoint > 0) { + gp_Pnt2d aNearest = aProj.NearestPoint(); + aResult.reset(new GeomAPI_Pnt2d(aNearest.X(), aNearest.Y())); + } + return aResult; +} + +const bool GeomAPI_Ellipse2d::parameter(const std::shared_ptr thePoint, + const double theTolerance, + double& theParameter) const +{ + Handle(Geom2d_Ellipse) aCurve = new Geom2d_Ellipse(*MY_ELLIPSE); + return GeomLib_Tool::Parameter(aCurve, thePoint->impl(), + theTolerance, theParameter) == Standard_True; +} diff --git a/src/GeomAPI/GeomAPI_Ellipse2d.h b/src/GeomAPI/GeomAPI_Ellipse2d.h index bda3221e1..7772abbf1 100644 --- a/src/GeomAPI/GeomAPI_Ellipse2d.h +++ b/src/GeomAPI/GeomAPI_Ellipse2d.h @@ -66,6 +66,23 @@ public: /// Returns major radius of the ellipse GEOMAPI_EXPORT double majorRadius() const; + /// Project point on ellipse + GEOMAPI_EXPORT const std::shared_ptr project( + const std::shared_ptr& thePoint) const; + + /** \brief Computes the parameter of a given point on an ellipse. The point must be + * located either on the circle itself or relatively to the latter + * at a distance less than the tolerance value. Return FALSE if the point + * is beyond the tolerance limit or if computation fails. + * Max Tolerance value is currently limited to 1.e-4 + * \param[in] thePoint point of origin. + * \param[in] theTolerance tolerance of computation. + * \param[out] theParameter resulting parameter. + */ + GEOMAPI_EXPORT const bool parameter(const std::shared_ptr thePoint, + const double theTolerance, + double& theParameter) const; + /// Calculate minimal distance between the ellipse and a line. /// Return corresponding points on the ellipse and on the line. GEOMAPI_EXPORT double distance(const std::shared_ptr& theLine, diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.cpp index 85828425c..9bfc1a50a 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.cpp +++ b/src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.cpp @@ -18,6 +18,10 @@ // #include + +#include +#include + #include #include #include @@ -236,3 +240,29 @@ std::shared_ptr GeomAlgoAPI_EdgeBuilder::ellipse( aRes->setImpl(new TopoDS_Shape(anEdge)); return aRes; } + +std::shared_ptr GeomAlgoAPI_EdgeBuilder::ellipticArc( + const std::shared_ptr& theCenter, + const std::shared_ptr& theNormal, + const std::shared_ptr& theMajorAxis, + const double theMajorRadius, + const double theMinorRadius, + const std::shared_ptr& theStart, + const std::shared_ptr& theEnd) +{ + std::shared_ptr anAx2(new GeomAPI_Ax2(theCenter, theNormal, theMajorAxis)); + GeomAPI_Ellipse anEllipse(anAx2, theMajorRadius, theMinorRadius); + + GeomPointPtr aStartPnt = anEllipse.project(theStart); + GeomPointPtr aEndPnt = anEllipse.project(theEnd); + + double aStartParam, aEndParam; + anEllipse.parameter(aStartPnt, Precision::Confusion(), aStartParam); + anEllipse.parameter(aEndPnt, Precision::Confusion(), aEndParam); + + BRepBuilderAPI_MakeEdge anEdgeBuilder(anEllipse.impl(), aStartParam, aEndParam); + GeomEdgePtr aRes(new GeomAPI_Edge); + TopoDS_Edge anEdge = anEdgeBuilder.Edge(); + aRes->setImpl(new TopoDS_Shape(anEdge)); + return aRes; +} diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.h b/src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.h index 259800972..245e97f05 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.h +++ b/src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.h @@ -78,6 +78,17 @@ class GEOMALGOAPI_EXPORT GeomAlgoAPI_EdgeBuilder const std::shared_ptr& theMajorAxis, const double theMajorRadius, const double theMinorRadius); + + + /// Creates elliptic edge + static std::shared_ptr ellipticArc( + const std::shared_ptr& theCenter, + const std::shared_ptr& theNormal, + const std::shared_ptr& theMajorAxis, + const double theMajorRadius, + const double theMinorRadius, + const std::shared_ptr& theStart, + const std::shared_ptr& theEnd); }; #endif diff --git a/src/SketchPlugin/CMakeLists.txt b/src/SketchPlugin/CMakeLists.txt index d7274a96a..47508117c 100644 --- a/src/SketchPlugin/CMakeLists.txt +++ b/src/SketchPlugin/CMakeLists.txt @@ -47,6 +47,7 @@ SET(PROJECT_HEADERS SketchPlugin_ConstraintTangent.h SketchPlugin_ConstraintVertical.h SketchPlugin_Ellipse.h + SketchPlugin_EllipticArc.h SketchPlugin_ExternalValidator.h SketchPlugin_Feature.h SketchPlugin_IntersectionPoint.h @@ -55,6 +56,7 @@ SET(PROJECT_HEADERS SketchPlugin_MacroArcReentrantMessage.h SketchPlugin_MacroCircle.h SketchPlugin_MacroEllipse.h + SketchPlugin_MacroEllipticArc.h SketchPlugin_MultiRotation.h SketchPlugin_MultiTranslation.h SketchPlugin_Plugin.h @@ -94,6 +96,7 @@ SET(PROJECT_SOURCES SketchPlugin_ConstraintTangent.cpp SketchPlugin_ConstraintVertical.cpp SketchPlugin_Ellipse.cpp + SketchPlugin_EllipticArc.cpp SketchPlugin_ExternalValidator.cpp SketchPlugin_Feature.cpp SketchPlugin_IntersectionPoint.cpp @@ -101,6 +104,7 @@ SET(PROJECT_SOURCES SketchPlugin_MacroArc.cpp SketchPlugin_MacroCircle.cpp SketchPlugin_MacroEllipse.cpp + SketchPlugin_MacroEllipticArc.cpp SketchPlugin_MultiRotation.cpp SketchPlugin_MultiTranslation.cpp SketchPlugin_Plugin.cpp diff --git a/src/SketchPlugin/SketchPlugin_EllipticArc.cpp b/src/SketchPlugin/SketchPlugin_EllipticArc.cpp new file mode 100644 index 000000000..3bc24f1cc --- /dev/null +++ b/src/SketchPlugin/SketchPlugin_EllipticArc.cpp @@ -0,0 +1,223 @@ +// Copyright (C) 2017-2019 CEA/DEN, EDF R&D +// +// 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 +#include + +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + +static const double tolerance = 1e-7; + + +SketchPlugin_EllipticArc::SketchPlugin_EllipticArc() +: SketchPlugin_SketchEntity() +{ +} + +void SketchPlugin_EllipticArc::initDerivedClassAttributes() +{ + data()->addAttribute(CENTER_ID(), GeomDataAPI_Point2D::typeId()); + data()->addAttribute(FIRST_FOCUS_ID(), GeomDataAPI_Point2D::typeId()); + data()->addAttribute(SECOND_FOCUS_ID(), GeomDataAPI_Point2D::typeId()); + data()->addAttribute(MAJOR_AXIS_START_ID(), GeomDataAPI_Point2D::typeId()); + data()->addAttribute(MAJOR_AXIS_END_ID(), GeomDataAPI_Point2D::typeId()); + data()->addAttribute(MINOR_AXIS_START_ID(), GeomDataAPI_Point2D::typeId()); + data()->addAttribute(MINOR_AXIS_END_ID(), GeomDataAPI_Point2D::typeId()); + data()->addAttribute(MAJOR_RADIUS_ID(), ModelAPI_AttributeDouble::typeId()); + data()->addAttribute(MINOR_RADIUS_ID(), ModelAPI_AttributeDouble::typeId()); + data()->addAttribute(START_POINT_ID(), GeomDataAPI_Point2D::typeId()); + data()->addAttribute(END_POINT_ID(), GeomDataAPI_Point2D::typeId()); + + data()->addAttribute(REVERSED_ID(), ModelAPI_AttributeBoolean::typeId()); + + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), SECOND_FOCUS_ID()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), MAJOR_AXIS_START_ID()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), MAJOR_AXIS_END_ID()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), MINOR_AXIS_START_ID()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), MINOR_AXIS_END_ID()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), MAJOR_RADIUS_ID()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), MINOR_RADIUS_ID()); + + data()->addAttribute(EXTERNAL_ID(), ModelAPI_AttributeSelection::typeId()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EXTERNAL_ID()); +} + +void SketchPlugin_EllipticArc::execute() +{ + SketchPlugin_Sketch* aSketch = sketch(); + if(!aSketch) { + return; + } + + // Calculate all characteristics of the ellipse. + fillCharacteristicPoints(); + + // Make a visible ellipse. + createEllipticArc(aSketch); +} + +bool SketchPlugin_EllipticArc::isFixed() { + return data()->selection(EXTERNAL_ID())->context().get() != NULL; +} + +void SketchPlugin_EllipticArc::attributeChanged(const std::string& theID) { + // the second condition for unability to move external segments anywhere + if (theID == EXTERNAL_ID() || isFixed()) { + std::shared_ptr aSelection = data()->selection(EXTERNAL_ID())->value(); + if (!aSelection) { + // empty shape in selection shows that the shape is equal to context + ResultPtr anExtRes = selection(EXTERNAL_ID())->context(); + if (anExtRes) + aSelection = anExtRes->shape(); + } + // update arguments due to the selection value + if (aSelection && !aSelection->isNull() && aSelection->isEdge()) { + std::shared_ptr anEdge( new GeomAPI_Edge(aSelection)); + std::shared_ptr anEllipse = anEdge->ellipse(); + + std::shared_ptr aCenterAttr = + std::dynamic_pointer_cast(attribute(CENTER_ID())); + aCenterAttr->setValue(sketch()->to2D(anEllipse->center())); + + std::shared_ptr aFocusAttr = + std::dynamic_pointer_cast(attribute(FIRST_FOCUS_ID())); + aFocusAttr->setValue(sketch()->to2D(anEllipse->firstFocus())); + + std::shared_ptr aStartAttr = + std::dynamic_pointer_cast(attribute(START_POINT_ID())); + aStartAttr->setValue(sketch()->to2D(anEdge->firstPoint())); + + std::shared_ptr aEndAttr = + std::dynamic_pointer_cast(attribute(END_POINT_ID())); + aEndAttr->setValue(sketch()->to2D(anEdge->lastPoint())); + + real(MAJOR_RADIUS_ID())->setValue(anEllipse->majorRadius()); + real(MINOR_RADIUS_ID())->setValue(anEllipse->minorRadius()); + } + } +} + +bool SketchPlugin_EllipticArc::fillCharacteristicPoints() +{ + std::shared_ptr aCenterAttr = + std::dynamic_pointer_cast(data()->attribute(CENTER_ID())); + std::shared_ptr aFocusAttr = + std::dynamic_pointer_cast(data()->attribute(FIRST_FOCUS_ID())); + + AttributeDoublePtr aMinorRadiusAttr = real(MINOR_RADIUS_ID()); + + if (!aCenterAttr->isInitialized() || + !aFocusAttr->isInitialized() || + !aMinorRadiusAttr->isInitialized()) { + return false; + } + + double aMinorRadius = aMinorRadiusAttr->value(); + if (aMinorRadius < tolerance) { + return false; + } + + data()->blockSendAttributeUpdated(true); + GeomPnt2dPtr aCenter2d = aCenterAttr->pnt(); + GeomPnt2dPtr aFocus2d = aFocusAttr->pnt(); + GeomDir2dPtr aMajorDir2d(new GeomAPI_Dir2d(aFocus2d->x() - aCenter2d->x(), + 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(attribute(SECOND_FOCUS_ID())) + ->setValue(2.0 * aCenter2d->x() - aFocus2d->x(), 2.0 * aCenter2d->y() - aFocus2d->y()); + std::dynamic_pointer_cast(attribute(MAJOR_AXIS_START_ID())) + ->setValue(aCenter2d->x() - aMajorDir2d->x() * aMajorRadius, + aCenter2d->y() - aMajorDir2d->y() * aMajorRadius); + std::dynamic_pointer_cast(attribute(MAJOR_AXIS_END_ID())) + ->setValue(aCenter2d->x() + aMajorDir2d->x() * aMajorRadius, + aCenter2d->y() + aMajorDir2d->y() * aMajorRadius); + std::dynamic_pointer_cast(attribute(MINOR_AXIS_START_ID())) + ->setValue(aCenter2d->x() - aMinorDir2d->x() * aMinorRadius, + aCenter2d->y() - aMinorDir2d->y() * aMinorRadius); + std::dynamic_pointer_cast(attribute(MINOR_AXIS_END_ID())) + ->setValue(aCenter2d->x() + aMinorDir2d->x() * aMinorRadius, + aCenter2d->y() + aMinorDir2d->y() * aMinorRadius); + data()->blockSendAttributeUpdated(false); + + return true; +} + +void SketchPlugin_EllipticArc::createEllipticArc(SketchPlugin_Sketch* theSketch) +{ + // Compute a ellipse in 3D view. + std::shared_ptr aCenterAttr = + std::dynamic_pointer_cast(data()->attribute(CENTER_ID())); + std::shared_ptr aFocusAttr = + std::dynamic_pointer_cast(data()->attribute(FIRST_FOCUS_ID())); + + double aMajorRadius = real(MAJOR_RADIUS_ID())->value(); + double aMinorRadius = real(MINOR_RADIUS_ID())->value(); + + std::shared_ptr aNDir = std::dynamic_pointer_cast( + theSketch->attribute(SketchPlugin_Sketch::NORM_ID())); + + GeomPointPtr aCenter(theSketch->to3D(aCenterAttr->x(), aCenterAttr->y())); + GeomPointPtr aFocus(theSketch->to3D(aFocusAttr->x(), aFocusAttr->y())); + GeomDirPtr aNormal = aNDir->dir(); + std::shared_ptr anEllipseShape; + if (aFocus->distance(aCenter) > tolerance) { + GeomDirPtr aMajorAxis(new GeomAPI_Dir(aFocus->x() - aCenter->x(), + aFocus->y() - aCenter->y(), aFocus->z() - aCenter->z())); + + std::shared_ptr aStartAttr = + std::dynamic_pointer_cast(data()->attribute(START_POINT_ID())); + std::shared_ptr aEndAttr = + std::dynamic_pointer_cast(data()->attribute(END_POINT_ID())); + + GeomPointPtr aStartPnt(theSketch->to3D(aStartAttr->x(), aStartAttr->y())); + GeomPointPtr aEndPnt(theSketch->to3D(aEndAttr->x(), aEndAttr->y())); + + anEllipseShape = GeomAlgoAPI_EdgeBuilder::ellipticArc(aCenter, aNormal, aMajorAxis, + aMajorRadius, aMinorRadius, aStartPnt, aEndPnt); + } + else { + // build circle instead of ellipse + anEllipseShape = GeomAlgoAPI_EdgeBuilder::lineCircle(aCenter, aNormal, aMajorRadius); + } + + ResultConstructionPtr aResult = document()->createConstruction(data()); + aResult->setShape(anEllipseShape); + aResult->setIsInHistory(false); + setResult(aResult); +} diff --git a/src/SketchPlugin/SketchPlugin_EllipticArc.h b/src/SketchPlugin/SketchPlugin_EllipticArc.h new file mode 100644 index 000000000..4b84d3bcf --- /dev/null +++ b/src/SketchPlugin/SketchPlugin_EllipticArc.h @@ -0,0 +1,149 @@ +// Copyright (C) 2017-2019 CEA/DEN, EDF R&D +// +// 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 +// + +#ifndef SketchPlugin_EllipticArc_H_ +#define SketchPlugin_EllipticArc_H_ + +#include +#include + +/**\class SketchPlugin_EllipticArc + * \ingroup Plugins + * \brief Feature for creation of the new elliptical arc in Sketch. + */ +class SketchPlugin_EllipticArc: public SketchPlugin_SketchEntity +{ + public: + /// Ellipse feature kind + inline static const std::string& ID() + { + static const std::string ID("SketchEllipticArc"); + return ID; + } + + /// 2D point - center of the ellipse + inline static const std::string& CENTER_ID() + { + static const std::string ID("ellipse_center"); + return ID; + } + + /// 2D point - start point of elliptic arc + inline static const std::string& START_POINT_ID() + { + static const std::string ID("start_point"); + return ID; + } + /// 2D point - end point of elliptic arc + inline static const std::string& END_POINT_ID() + { + static const std::string ID("end_point"); + return ID; + } + + /// 2D point - focus of the ellipse + inline static const std::string& FIRST_FOCUS_ID() + { + static const std::string ID("ellipse_first_focus"); + return ID; + } + /// 2D point - second focus of the ellipse + inline static const std::string& SECOND_FOCUS_ID() + { + static const std::string ID("ellipse_second_focus"); + return ID; + } + + /// 2D point - start point of major axis + inline static const std::string& MAJOR_AXIS_START_ID() + { + static const std::string ID("ellipse_major_axis_start_point"); + return ID; + } + /// 2D point - end point of major axis + inline static const std::string& MAJOR_AXIS_END_ID() + { + static const std::string ID("ellipse_major_axis_end_point"); + return ID; + } + + /// 2D point - start point of minor axis + inline static const std::string& MINOR_AXIS_START_ID() + { + static const std::string ID("ellipse_minor_axis_start_point"); + return ID; + } + /// 2D point - end point of minor axis + inline static const std::string& MINOR_AXIS_END_ID() + { + static const std::string ID("ellipse_minor_axis_end_point"); + return ID; + } + + /// Major radius of the ellipse + inline static const std::string& MAJOR_RADIUS_ID() + { + static const std::string ID("ellipse_major_radius"); + return ID; + } + + /// Minor radius of the ellipse + inline static const std::string& MINOR_RADIUS_ID() + { + static const std::string ID("ellipse_minor_radius"); + return ID; + } + + /// Flag the arc is reversed + inline static const std::string& REVERSED_ID() + { + static const std::string ID("reversed"); + return ID; + } + + /// Returns the kind of a feature + SKETCHPLUGIN_EXPORT virtual const std::string& getKind() + { + static std::string MY_KIND = SketchPlugin_EllipticArc::ID(); + return MY_KIND; + } + + /// Returns true is sketch element is under the rigid constraint + SKETCHPLUGIN_EXPORT virtual bool isFixed(); + + /// Called on change of any argument-attribute of this object + SKETCHPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID); + + /// Creates a new part document if needed + SKETCHPLUGIN_EXPORT virtual void execute(); + + /// Use plugin manager for features creation + SketchPlugin_EllipticArc(); + +protected: + /// \brief Initializes attributes of derived class. + virtual void initDerivedClassAttributes(); + +private: + bool fillCharacteristicPoints(); + + void createEllipticArc(SketchPlugin_Sketch* theSketch); +}; + +#endif diff --git a/src/SketchPlugin/SketchPlugin_MacroEllipse.cpp b/src/SketchPlugin/SketchPlugin_MacroEllipse.cpp index 99910ceba..a4abe7b7d 100644 --- a/src/SketchPlugin/SketchPlugin_MacroEllipse.cpp +++ b/src/SketchPlugin/SketchPlugin_MacroEllipse.cpp @@ -295,84 +295,31 @@ FeaturePtr SketchPlugin_MacroEllipse::createEllipseFeature() aEllipseFeature->execute(); // create auxiliary points - createAuxiliaryPoint(aEllipseFeature, SketchPlugin_Ellipse::CENTER_ID()); - createAuxiliaryPoint(aEllipseFeature, SketchPlugin_Ellipse::FIRST_FOCUS_ID()); - createAuxiliaryPoint(aEllipseFeature, SketchPlugin_Ellipse::SECOND_FOCUS_ID()); - createAuxiliaryPoint(aEllipseFeature, SketchPlugin_Ellipse::MAJOR_AXIS_START_ID()); - createAuxiliaryPoint(aEllipseFeature, SketchPlugin_Ellipse::MAJOR_AXIS_END_ID()); - createAuxiliaryPoint(aEllipseFeature, SketchPlugin_Ellipse::MINOR_AXIS_START_ID()); - createAuxiliaryPoint(aEllipseFeature, SketchPlugin_Ellipse::MINOR_AXIS_END_ID()); + SketchPlugin_Tools::createAuxiliaryPointOnEllipse( + aEllipseFeature, SketchPlugin_Ellipse::CENTER_ID()); + SketchPlugin_Tools::createAuxiliaryPointOnEllipse( + aEllipseFeature, SketchPlugin_Ellipse::FIRST_FOCUS_ID()); + SketchPlugin_Tools::createAuxiliaryPointOnEllipse( + aEllipseFeature, SketchPlugin_Ellipse::SECOND_FOCUS_ID()); + SketchPlugin_Tools::createAuxiliaryPointOnEllipse( + aEllipseFeature, SketchPlugin_Ellipse::MAJOR_AXIS_START_ID()); + SketchPlugin_Tools::createAuxiliaryPointOnEllipse( + aEllipseFeature, SketchPlugin_Ellipse::MAJOR_AXIS_END_ID()); + SketchPlugin_Tools::createAuxiliaryPointOnEllipse( + aEllipseFeature, SketchPlugin_Ellipse::MINOR_AXIS_START_ID()); + SketchPlugin_Tools::createAuxiliaryPointOnEllipse( + aEllipseFeature, SketchPlugin_Ellipse::MINOR_AXIS_END_ID()); // create auxiliary axes - createAuxiliaryAxis(aEllipseFeature, + SketchPlugin_Tools::createAuxiliaryAxisOfEllipse(aEllipseFeature, SketchPlugin_Ellipse::MAJOR_AXIS_START_ID(), SketchPlugin_Ellipse::MAJOR_AXIS_END_ID()); - createAuxiliaryAxis(aEllipseFeature, + SketchPlugin_Tools::createAuxiliaryAxisOfEllipse(aEllipseFeature, SketchPlugin_Ellipse::MINOR_AXIS_START_ID(), SketchPlugin_Ellipse::MINOR_AXIS_END_ID()); return aEllipseFeature; } -void SketchPlugin_MacroEllipse::createAuxiliaryPoint(const FeaturePtr& theEllipseFeature, - const std::string& theEllipsePoint) -{ - FeaturePtr aPointFeature = sketch()->addFeature(SketchPlugin_Point::ID()); - aPointFeature->boolean(SketchPlugin_Point::AUXILIARY_ID())->setValue(true); - aPointFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(theEllipseFeature); - - AttributePoint2DPtr anElPoint = std::dynamic_pointer_cast( - theEllipseFeature->attribute(theEllipsePoint)); - - AttributePoint2DPtr aCoord = std::dynamic_pointer_cast( - aPointFeature->attribute(SketchPlugin_Point::COORD_ID())); - aCoord->setValue(anElPoint->x(), anElPoint->y()); - - aPointFeature->execute(); - std::string aName = theEllipseFeature->name() + "_" + theEllipsePoint; - aPointFeature->data()->setName(aName); - aPointFeature->lastResult()->data()->setName(aName); - - createInternalConstraint(anElPoint, aCoord); -} - -void SketchPlugin_MacroEllipse::createAuxiliaryAxis(const FeaturePtr& theEllipseFeature, - const std::string& theStartPoint, - const std::string& theEndPoint) -{ - FeaturePtr aLineFeature = sketch()->addFeature(SketchPlugin_Line::ID()); - aLineFeature->boolean(SketchPlugin_Point::AUXILIARY_ID())->setValue(true); - aLineFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(theEllipseFeature); - - AttributePoint2DPtr aStartPoint = std::dynamic_pointer_cast( - theEllipseFeature->attribute(theStartPoint)); - AttributePoint2DPtr aEndPoint = std::dynamic_pointer_cast( - theEllipseFeature->attribute(theEndPoint)); - - AttributePoint2DPtr aLineStart = std::dynamic_pointer_cast( - aLineFeature->attribute(SketchPlugin_Line::START_ID())); - aLineStart->setValue(aStartPoint->x(), aStartPoint->y()); - - AttributePoint2DPtr aLineEnd = std::dynamic_pointer_cast( - aLineFeature->attribute(SketchPlugin_Line::END_ID())); - aLineEnd->setValue(aEndPoint->x(), aEndPoint->y()); - - aLineFeature->execute(); - std::string aName = theEllipseFeature->name() + "_" + - (theStartPoint == SketchPlugin_Ellipse::MAJOR_AXIS_START_ID() ? "major_axis" : "minor_axis"); - aLineFeature->data()->setName(aName); - aLineFeature->lastResult()->data()->setName(aName); - - createInternalConstraint(aStartPoint, aLineStart); - createInternalConstraint(aEndPoint, aLineEnd); -} - -void SketchPlugin_MacroEllipse::createInternalConstraint(const AttributePtr& thePoint1, - const AttributePtr& thePoint2) -{ - SketchPlugin_Tools::createConstraintAttrAttr( - sketch(), SketchPlugin_ConstraintCoincidenceInternal::ID(), thePoint1, thePoint2); -} - AISObjectPtr SketchPlugin_MacroEllipse::getAISObject(AISObjectPtr thePrevious) { SketchPlugin_Sketch* aSketch = sketch(); diff --git a/src/SketchPlugin/SketchPlugin_MacroEllipse.h b/src/SketchPlugin/SketchPlugin_MacroEllipse.h index 4bea22221..609d96bf6 100644 --- a/src/SketchPlugin/SketchPlugin_MacroEllipse.h +++ b/src/SketchPlugin/SketchPlugin_MacroEllipse.h @@ -162,14 +162,6 @@ private: FeaturePtr createEllipseFeature(); - void createAuxiliaryPoint(const FeaturePtr& theEllipseFeature, - const std::string& theEllipsePoint); - void createAuxiliaryAxis(const FeaturePtr& theEllipseFeature, - const std::string& theStartPoint, - const std::string& theEndPoint); - - void createInternalConstraint(const AttributePtr& thePoint1, const AttributePtr& thePoint2); - private: std::shared_ptr myCenter; std::shared_ptr myFocus; diff --git a/src/SketchPlugin/SketchPlugin_MacroEllipticArc.cpp b/src/SketchPlugin/SketchPlugin_MacroEllipticArc.cpp new file mode 100644 index 000000000..768e82713 --- /dev/null +++ b/src/SketchPlugin/SketchPlugin_MacroEllipticArc.cpp @@ -0,0 +1,413 @@ +// Copyright (C) 2017-2019 CEA/DEN, EDF R&D +// +// 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 + +////#include +#include +////#include +#include +////#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include + + +const double paramTolerance = 1.e-4; +const double PI = 3.141592653589793238463; + + +SketchPlugin_MacroEllipticArc::SketchPlugin_MacroEllipticArc() + : SketchPlugin_SketchEntity(), + myMajorRadius(0.0), + myMinorRadius(0.0), + myParamDelta(0.0) +{ +} + +void SketchPlugin_MacroEllipticArc::initAttributes() +{ + data()->addAttribute(CENTER_ID(), GeomDataAPI_Point2D::typeId()); + data()->addAttribute(CENTER_REF_ID(), ModelAPI_AttributeRefAttr::typeId()); + data()->addAttribute(MAJOR_AXIS_POINT_ID(), GeomDataAPI_Point2D::typeId()); + data()->addAttribute(MAJOR_AXIS_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId()); + data()->addAttribute(START_POINT_ID(), GeomDataAPI_Point2D::typeId()); + data()->addAttribute(START_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId()); + data()->addAttribute(END_POINT_ID(), GeomDataAPI_Point2D::typeId()); + data()->addAttribute(END_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId()); + + data()->addAttribute(MAJOR_RADIUS_ID(), ModelAPI_AttributeDouble::typeId()); + data()->addAttribute(MINOR_RADIUS_ID(), ModelAPI_AttributeDouble::typeId()); + + data()->addAttribute(REVERSED_ID(), ModelAPI_AttributeBoolean::typeId()); + data()->addAttribute(AUXILIARY_ID(), ModelAPI_AttributeBoolean::typeId()); + + boolean(REVERSED_ID())->setValue(false); + + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), CENTER_REF_ID()); + ModelAPI_Session::get()->validators() + ->registerNotObligatory(getKind(), MAJOR_AXIS_POINT_REF_ID()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), START_POINT_REF_ID()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), END_POINT_REF_ID()); +} + +void SketchPlugin_MacroEllipticArc::execute() +{ + FeaturePtr anEllipse = createEllipticArcFeature(); + + // message to init reentrant operation + static Events_ID anId = SketchPlugin_MacroArcReentrantMessage::eventId(); + std::shared_ptr aMessage = std::shared_ptr + (new SketchPlugin_MacroArcReentrantMessage(anId, this)); + aMessage->setCreatedFeature(anEllipse); + Events_Loop::loop()->send(aMessage); +} + +void SketchPlugin_MacroEllipticArc::attributeChanged(const std::string& theID) +{ + static const int NB_POINTS = 4; + std::string aPointAttrName[NB_POINTS] = { CENTER_ID(), + MAJOR_AXIS_POINT_ID(), + START_POINT_ID(), + END_POINT_ID() }; + std::string aPointRefName[NB_POINTS] = { CENTER_REF_ID(), + MAJOR_AXIS_POINT_REF_ID(), + START_POINT_REF_ID(), + END_POINT_REF_ID() }; + + int aNbInitialized = 0; + GeomPnt2dPtr anEllipsePoints[NB_POINTS]; + + for (int aPntIndex = 0; aPntIndex < NB_POINTS; ++aPntIndex) { + AttributePtr aPointAttr = attribute(aPointAttrName[aPntIndex]); + if (!aPointAttr->isInitialized()) + continue; + + AttributeRefAttrPtr aPointRef = refattr(aPointRefName[aPntIndex]); + // calculate ellipse parameters + GeomPnt2dPtr aPassedPoint = + std::dynamic_pointer_cast(aPointAttr)->pnt(); + GeomShapePtr aTangentCurve; + SketchPlugin_Tools::convertRefAttrToPointOrTangentCurve( + aPointRef, aPointAttr, aTangentCurve, aPassedPoint); + + anEllipsePoints[aNbInitialized++] = aPassedPoint; + } + + if (aNbInitialized <= 1) + return; // too few points for the ellipse + + myCenter = anEllipsePoints[0]; + myMajorAxis = anEllipsePoints[1]; + myStartPnt = anEllipsePoints[2]; + myEndPnt = anEllipsePoints[3]; + + std::shared_ptr anEllipse; + if (aNbInitialized == 2) { + GeomDir2dPtr aXDir(new GeomAPI_Dir2d(anEllipsePoints[1]->x() - anEllipsePoints[0]->x(), + anEllipsePoints[1]->y() - anEllipsePoints[0]->y())); + double aMajorRad = anEllipsePoints[1]->distance(anEllipsePoints[0]); + anEllipse = std::shared_ptr( + new GeomAPI_Ellipse2d(anEllipsePoints[0], aXDir, aMajorRad, 0.5 * aMajorRad)); + } + else if (aNbInitialized >= 3) { + anEllipse = std::shared_ptr( + new GeomAPI_Ellipse2d(anEllipsePoints[0], anEllipsePoints[1], anEllipsePoints[2])); + } + + if (!anEllipse || anEllipse->implPtr() == 0) + return; + + myMajorRadius = anEllipse->majorRadius(); + myMinorRadius = anEllipse->minorRadius(); + + bool aWasBlocked = data()->blockSendAttributeUpdated(true); + real(MAJOR_RADIUS_ID())->setValue(myMajorRadius); + real(MINOR_RADIUS_ID())->setValue(myMinorRadius); + data()->blockSendAttributeUpdated(aWasBlocked, false); + + // update the REVERSED flag + if (myEndPnt) { + double aParameterEnd = 0.0; + GeomPnt2dPtr aEnd = anEllipse->project(myEndPnt); + if (anEllipse->parameter(aEnd, paramTolerance, aParameterEnd)) { + double aParamStart = 0.0; + anEllipse->parameter(myStartPnt, paramTolerance, aParamStart); + aParameterEnd -= aParamStart; + + if (myParamDelta > 0.0 && myParamDelta <= PI * 0.5 && + aParameterEnd < 0 && aParameterEnd >= -PI * 0.5) { + boolean(REVERSED_ID())->setValue(true); + } + else if (myParamDelta < 0.0 && myParamDelta >= -PI * 0.5 && + aParameterEnd > 0.0 && aParameterEnd <= PI * 0.5) { + boolean(REVERSED_ID())->setValue(false); + } + } + myParamDelta = aParameterEnd; + } +} + +// LCOV_EXCL_START +std::string SketchPlugin_MacroEllipticArc::processEvent( + const std::shared_ptr& theMessage) +{ + std::string aFilledAttributeName; + + std::shared_ptr aReentrantMessage = + std::dynamic_pointer_cast(theMessage); + if (aReentrantMessage) { + FeaturePtr aCreatedFeature = aReentrantMessage->createdFeature(); + + ObjectPtr anObject = aReentrantMessage->selectedObject(); + AttributePtr anAttribute = aReentrantMessage->selectedAttribute(); + std::shared_ptr aClickedPoint = aReentrantMessage->clickedPoint(); + + if (aClickedPoint && (anObject || anAttribute)) { + aFilledAttributeName = CENTER_ID(); + std::string aReferenceAttributeName = CENTER_REF_ID(); + + // fill 2d point attribute + AttributePoint2DPtr aPointAttr = + std::dynamic_pointer_cast(attribute(aFilledAttributeName)); + aPointAttr->setValue(aClickedPoint); + + // fill reference attribute + AttributeRefAttrPtr aRefAttr = + std::dynamic_pointer_cast(attribute(aReferenceAttributeName)); + if (anAttribute) { + if (!anAttribute->owner() || !anAttribute->owner()->data()->isValid()) { + if (aCreatedFeature && anAttribute->id() == CENTER_ID()) + anAttribute = aCreatedFeature->attribute(SketchPlugin_EllipticArc::CENTER_ID()); + } + aRefAttr->setAttr(anAttribute); + } + else if (anObject.get()) { + // if attribute is NULL, only object is defined, it should be processed outside + // the feature because it might be an external feature, that will be + // removed/created again after restart operation + // #2468 - Crash when sketching circles successively on a repetition + aFilledAttributeName = ""; + } + } + Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED)); + } + return aFilledAttributeName; +} +// LCOV_EXCL_STOP + +////void SketchPlugin_MacroEllipticArc::constraintsForEllipseByCenterAxisAndPassed( +//// FeaturePtr theEllipseFeature) +////{ +//// // tangency on-the-fly is not applicable for ellipses +//// static const bool isTangencyApplicable = false; +//// // Create constraints. +//// SketchPlugin_Tools::createCoincidenceOrTangency( +//// this, FIRST_POINT_REF_ID(), +//// theEllipseFeature->attribute(SketchPlugin_Ellipse::CENTER_ID()), +//// ObjectPtr(), isTangencyApplicable); +//// SketchPlugin_Tools::createCoincidenceOrTangency( +//// this, SECOND_POINT_REF_ID(), +//// theEllipseFeature->attribute(SketchPlugin_Ellipse::MAJOR_AXIS_END_ID()), +//// ObjectPtr(), isTangencyApplicable); +//// // make coincidence only if PASSED_POINT_REF_ID() refers a point but not an object +//// if (!refattr(PASSED_POINT_REF_ID())->isObject()) { +//// SketchPlugin_Tools::createCoincidenceOrTangency( +//// this, PASSED_POINT_REF_ID(), AttributePtr(), +//// theEllipseFeature->lastResult(), isTangencyApplicable); +//// } +////} +//// +////void SketchPlugin_MacroEllipticArc::constraintsForEllipseByMajoxAxisAndPassed( +//// FeaturePtr theEllipseFeature) +////{ +//// // tangency on-the-fly is not applicable for ellipses +//// static const bool isTangencyApplicable = false; +//// // Create constraints. +//// SketchPlugin_Tools::createCoincidenceOrTangency( +//// this, FIRST_POINT_REF_ID(), +//// theEllipseFeature->attribute(SketchPlugin_Ellipse::MAJOR_AXIS_START_ID()), +//// ObjectPtr(), isTangencyApplicable); +//// SketchPlugin_Tools::createCoincidenceOrTangency( +//// this, SECOND_POINT_REF_ID(), +//// theEllipseFeature->attribute(SketchPlugin_Ellipse::MAJOR_AXIS_END_ID()), +//// ObjectPtr(), isTangencyApplicable); +//// // make coincidence only if PASSED_POINT_REF_ID() refers a point but not an object +//// if (!refattr(PASSED_POINT_REF_ID())->isObject()) { +//// SketchPlugin_Tools::createCoincidenceOrTangency( +//// this, PASSED_POINT_REF_ID(), AttributePtr(), +//// theEllipseFeature->lastResult(), isTangencyApplicable); +//// } +////} + +FeaturePtr SketchPlugin_MacroEllipticArc::createEllipticArcFeature() +{ + GeomShapePtr anArc = getArcShape(); + GeomEllipsePtr anEllipse; + GeomPointPtr aStartPoint, aEndPoint; + if (anArc->isEdge()) { + GeomEdgePtr anArcEdge = anArc->edge(); + aStartPoint = anArcEdge->firstPoint(); + aEndPoint = anArcEdge->lastPoint(); + + if (anArcEdge->isEllipse()) + anEllipse = anArcEdge->ellipse(); + } + + if (!anEllipse) + return FeaturePtr(); + + // Create and fill new EllipticArc feature + SketchPlugin_Sketch* aSketch = sketch(); + FeaturePtr aEllipseFeature = aSketch->addFeature(SketchPlugin_EllipticArc::ID()); + + AttributePoint2DPtr aCenterAttr = std::dynamic_pointer_cast( + aEllipseFeature->attribute(SketchPlugin_EllipticArc::CENTER_ID())); + aCenterAttr->setValue(aSketch->to2D(anEllipse->center())); + + AttributePoint2DPtr aFocusAttr = std::dynamic_pointer_cast( + aEllipseFeature->attribute(SketchPlugin_EllipticArc::FIRST_FOCUS_ID())); + aFocusAttr->setValue(aSketch->to2D(anEllipse->firstFocus())); + + AttributePoint2DPtr aStartAttr = std::dynamic_pointer_cast( + aEllipseFeature->attribute(SketchPlugin_EllipticArc::START_POINT_ID())); + aStartAttr->setValue(aSketch->to2D(aStartPoint)); + + AttributePoint2DPtr aEndAttr = std::dynamic_pointer_cast( + aEllipseFeature->attribute(SketchPlugin_EllipticArc::END_POINT_ID())); + aEndAttr->setValue(aSketch->to2D(aEndPoint)); + + aEllipseFeature->real(SketchPlugin_EllipticArc::MAJOR_RADIUS_ID())->setValue(myMajorRadius); + aEllipseFeature->real(SketchPlugin_EllipticArc::MINOR_RADIUS_ID())->setValue(myMinorRadius); + + aEllipseFeature->boolean(SketchPlugin_EllipticArc::REVERSED_ID())->setValue( + boolean(REVERSED_ID())->value()); + + aEllipseFeature->boolean(SketchPlugin_EllipticArc::AUXILIARY_ID())->setValue( + boolean(AUXILIARY_ID())->value()); + + aEllipseFeature->execute(); + + // create auxiliary points + SketchPlugin_Tools::createAuxiliaryPointOnEllipse( + aEllipseFeature, SketchPlugin_EllipticArc::CENTER_ID()); + SketchPlugin_Tools::createAuxiliaryPointOnEllipse( + aEllipseFeature, SketchPlugin_EllipticArc::FIRST_FOCUS_ID()); + SketchPlugin_Tools::createAuxiliaryPointOnEllipse( + aEllipseFeature, SketchPlugin_EllipticArc::SECOND_FOCUS_ID()); + SketchPlugin_Tools::createAuxiliaryPointOnEllipse( + aEllipseFeature, SketchPlugin_EllipticArc::MAJOR_AXIS_START_ID()); + SketchPlugin_Tools::createAuxiliaryPointOnEllipse( + aEllipseFeature, SketchPlugin_EllipticArc::MAJOR_AXIS_END_ID()); + SketchPlugin_Tools::createAuxiliaryPointOnEllipse( + aEllipseFeature, SketchPlugin_EllipticArc::MINOR_AXIS_START_ID()); + SketchPlugin_Tools::createAuxiliaryPointOnEllipse( + aEllipseFeature, SketchPlugin_EllipticArc::MINOR_AXIS_END_ID()); + // create auxiliary axes + SketchPlugin_Tools::createAuxiliaryAxisOfEllipse(aEllipseFeature, + SketchPlugin_EllipticArc::MAJOR_AXIS_START_ID(), + SketchPlugin_EllipticArc::MAJOR_AXIS_END_ID()); + SketchPlugin_Tools::createAuxiliaryAxisOfEllipse(aEllipseFeature, + SketchPlugin_EllipticArc::MINOR_AXIS_START_ID(), + SketchPlugin_EllipticArc::MINOR_AXIS_END_ID()); + + return aEllipseFeature; +} + +AISObjectPtr SketchPlugin_MacroEllipticArc::getAISObject(AISObjectPtr thePrevious) +{ + SketchPlugin_Sketch* aSketch = sketch(); + if (!aSketch || !myCenter || !myMajorAxis) + return AISObjectPtr(); + + // Compute a elliptic arc in 3D view. + GeomPointPtr aCenter(aSketch->to3D(myCenter->x(), myCenter->y())); + GeomShapePtr aCenterPointShape = GeomAlgoAPI_PointBuilder::vertex(aCenter); + GeomShapePtr anArcShape = getArcShape(); + if (!anArcShape.get() || !aCenterPointShape.get()) + return AISObjectPtr(); + + std::list > aShapes; + aShapes.push_back(anArcShape); + aShapes.push_back(aCenterPointShape); + + std::shared_ptr aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes); + AISObjectPtr anAIS = thePrevious; + if (!anAIS) + anAIS.reset(new GeomAPI_AISObject()); + anAIS->createShape(aCompound); + return anAIS; +} + +GeomShapePtr SketchPlugin_MacroEllipticArc::getArcShape() +{ + if (!myCenter.get() || !myMajorAxis.get()) + return GeomShapePtr(); + + SketchPlugin_Sketch* aSketch = sketch(); + if (!aSketch) + return GeomShapePtr(); + + GeomPointPtr aCenter(aSketch->to3D(myCenter->x(), myCenter->y())); + GeomPointPtr aMajorAxisPnt(aSketch->to3D(myMajorAxis->x(), myMajorAxis->y())); + GeomDirPtr aMajorAxisDir(new GeomAPI_Dir(aMajorAxisPnt->x() - aCenter->x(), + aMajorAxisPnt->y() - aCenter->y(), + aMajorAxisPnt->z() - aCenter->z())); + + std::shared_ptr aNDir = std::dynamic_pointer_cast( + aSketch->attribute(SketchPlugin_Sketch::NORM_ID())); + GeomDirPtr aNormal(new GeomAPI_Dir(aNDir->x(), aNDir->y(), aNDir->z())); + + GeomPointPtr aStart, anEnd; + if (myStartPnt) + aStart = aSketch->to3D(myStartPnt->x(), myStartPnt->y()); + if (myEndPnt) + anEnd = aSketch->to3D(myEndPnt->x(), myEndPnt->y()); + + GeomShapePtr anArcShape; + if (anEnd) { + if (boolean(REVERSED_ID())->value()) + std::swap(aStart, anEnd); + + anArcShape = GeomAlgoAPI_EdgeBuilder::ellipticArc(aCenter, aNormal, aMajorAxisDir, + myMajorRadius, myMinorRadius, aStart, anEnd); + } + else { + anArcShape = GeomAlgoAPI_EdgeBuilder::ellipse(aCenter, aNormal, aMajorAxisDir, + myMajorRadius, myMinorRadius); + } + + return anArcShape; +} diff --git a/src/SketchPlugin/SketchPlugin_MacroEllipticArc.h b/src/SketchPlugin/SketchPlugin_MacroEllipticArc.h new file mode 100644 index 000000000..1d6db5ffc --- /dev/null +++ b/src/SketchPlugin/SketchPlugin_MacroEllipticArc.h @@ -0,0 +1,176 @@ +// Copyright (C) 2017-2019 CEA/DEN, EDF R&D +// +// 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 +// + +#ifndef SketchPlugin_MacroEllipticArc_H_ +#define SketchPlugin_MacroEllipticArc_H_ + +#include +#include +#include +#include + +class GeomAPI_Pnt2d; +class GeomAPI_Shape; + +/**\class SketchPlugin_MacroEllipticArc + * \ingroup Plugins + * \brief Feature for creation of the new elliptical arc in Sketch. + */ +class SketchPlugin_MacroEllipticArc: public SketchPlugin_SketchEntity, + public GeomAPI_IPresentable, + public ModelAPI_IReentrant +{ + public: + /// Elliptical arc feature kind + inline static const std::string& ID() + { + static const std::string ID("SketchMacroEllipticArc"); + return ID; + } + + /// Attribute for the central point selected during elliptic arc creation. + inline static const std::string& CENTER_ID() + { + static const std::string ID("center"); + return ID; + } + + /// Reference to the first selected point (center of ellipse). + inline static const std::string& CENTER_REF_ID() + { + static const std::string ID("center_ref"); + return ID; + } + + /// Attribute for the point on major semi-axis selected during elliptic arc creation. + inline static const std::string& MAJOR_AXIS_POINT_ID() + { + static const std::string ID("major_axis_point"); + return ID; + } + + /// Reference to the second selected point (major semi-axis of the ellipse). + inline static const std::string& MAJOR_AXIS_POINT_REF_ID() + { + static const std::string ID("major_axis_point_ref"); + return ID; + } + + /// Attribute for the start point of the elliptic arc selected during creation. + inline static const std::string& START_POINT_ID() + { + static const std::string ID("start_point"); + return ID; + } + + /// Reference for the start point selection. + inline static const std::string& START_POINT_REF_ID() + { + static const std::string ID("start_point_ref"); + return ID; + } + + /// Attribute for the end point of the elliptic arc selected during creation. + inline static const std::string& END_POINT_ID() + { + static const std::string ID("end_point"); + return ID; + } + + /// Reference for the end point selection. + inline static const std::string& END_POINT_REF_ID() + { + static const std::string ID("end_point_ref"); + return ID; + } + + /// Major radius of the ellipse + inline static const std::string& MAJOR_RADIUS_ID() + { + static const std::string ID("major_radius"); + return ID; + } + + /// Minor radius of the ellipse + inline static const std::string& MINOR_RADIUS_ID() + { + static const std::string ID("minor_radius"); + return ID; + } + + /// Flag the arc is reversed + inline static const std::string& REVERSED_ID() + { + static const std::string ID("reversed"); + return ID; + } + + /// Returns the kind of a feature + SKETCHPLUGIN_EXPORT virtual const std::string& getKind() + { + static std::string MY_KIND = SketchPlugin_MacroEllipticArc::ID(); + return MY_KIND; + } + + /// \brief Request for initialization of data model of the feature: adding all attributes. + SKETCHPLUGIN_EXPORT virtual void initAttributes(); + + /// Called on change of any argument-attribute of this object + SKETCHPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID); + + /// Returns the AIS preview + virtual AISObjectPtr getAISObject(AISObjectPtr thePrevious); + + /// Creates a new part document if needed + SKETCHPLUGIN_EXPORT virtual void execute(); + + /// Reimplemented from ModelAPI_Feature::isMacro(). + /// \returns true + SKETCHPLUGIN_EXPORT virtual bool isMacro() const + {return true;} + + SKETCHPLUGIN_EXPORT virtual bool isPreviewNeeded() const + {return false;} + + /// Apply information of the message to current object. It fills reference object, + /// tangent type and tangent point refence in case of tangent arc + virtual std::string processEvent(const std::shared_ptr& theMessage); + + /// Use plugin manager for features creation + SketchPlugin_MacroEllipticArc(); + +private: + std::shared_ptr getArcShape(); + +//// void constraintsForEllipseByCenterAxisAndPassed(FeaturePtr theEllipseFeature); +//// void constraintsForEllipseByMajoxAxisAndPassed(FeaturePtr theEllipseFeature); + + FeaturePtr createEllipticArcFeature(); + +private: + std::shared_ptr myCenter; + std::shared_ptr myMajorAxis; + std::shared_ptr myStartPnt; + std::shared_ptr myEndPnt; + double myMajorRadius; + double myMinorRadius; + double myParamDelta; +}; + +#endif diff --git a/src/SketchPlugin/SketchPlugin_Plugin.cpp b/src/SketchPlugin/SketchPlugin_Plugin.cpp index 38852d714..d9e967e60 100644 --- a/src/SketchPlugin/SketchPlugin_Plugin.cpp +++ b/src/SketchPlugin/SketchPlugin_Plugin.cpp @@ -54,6 +54,8 @@ #include #include #include +#include +#include #include #include @@ -251,6 +253,10 @@ FeaturePtr SketchPlugin_Plugin::createFeature(std::string theFeatureID) return FeaturePtr(new SketchPlugin_Ellipse); } else if (theFeatureID == SketchPlugin_MacroEllipse::ID()) { return FeaturePtr(new SketchPlugin_MacroEllipse); + } else if (theFeatureID == SketchPlugin_EllipticArc::ID()) { + return FeaturePtr(new SketchPlugin_EllipticArc); + } else if (theFeatureID == SketchPlugin_MacroEllipticArc::ID()) { + return FeaturePtr(new SketchPlugin_MacroEllipticArc); } else if (theFeatureID == SketchPlugin_SketchDrawer::ID()) { return FeaturePtr(new SketchPlugin_SketchDrawer); } @@ -297,6 +303,7 @@ std::shared_ptr SketchPlugin_Plugin aMsg->setState(SketchPlugin_Circle::ID(), aHasSketchPlane); aMsg->setState(SketchPlugin_Arc::ID(), aHasSketchPlane); aMsg->setState(SketchPlugin_Ellipse::ID(), aHasSketchPlane); + aMsg->setState(SketchPlugin_EllipticArc::ID(), aHasSketchPlane); aMsg->setState(SketchPlugin_Projection::ID(), aHasSketchPlane); aMsg->setState(SketchPlugin_ConstraintCoincidence::ID(), aHasSketchPlane); aMsg->setState(SketchPlugin_ConstraintCoincidenceInternal::ID(), aHasSketchPlane); @@ -322,6 +329,7 @@ std::shared_ptr SketchPlugin_Plugin aMsg->setState(SketchPlugin_MacroArc::ID(), aHasSketchPlane); aMsg->setState(SketchPlugin_MacroCircle::ID(), aHasSketchPlane); aMsg->setState(SketchPlugin_MacroEllipse::ID(), aHasSketchPlane); + aMsg->setState(SketchPlugin_MacroEllipticArc::ID(), aHasSketchPlane); aMsg->setState(SketchPlugin_ConstraintDistanceHorizontal::ID(), aHasSketchPlane); aMsg->setState(SketchPlugin_ConstraintDistanceVertical::ID(), aHasSketchPlane); // SketchRectangle is a python feature, so its ID is passed just as a string diff --git a/src/SketchPlugin/SketchPlugin_Tools.cpp b/src/SketchPlugin/SketchPlugin_Tools.cpp index 4f55be24d..472078f18 100644 --- a/src/SketchPlugin/SketchPlugin_Tools.cpp +++ b/src/SketchPlugin/SketchPlugin_Tools.cpp @@ -20,8 +20,10 @@ #include "SketchPlugin_Tools.h" #include "SketchPlugin_ConstraintCoincidence.h" +#include "SketchPlugin_ConstraintCoincidenceInternal.h" #include "SketchPlugin_ConstraintLength.h" #include "SketchPlugin_ConstraintTangent.h" +#include "SketchPlugin_Ellipse.h" #include "SketchPlugin_Line.h" #include "SketchPlugin_Point.h" #include "SketchPlugin_SketchEntity.h" @@ -429,6 +431,68 @@ FeaturePtr createConstraintObjectObject(SketchPlugin_Sketch* theSketch, return aConstraint; } +void createAuxiliaryPointOnEllipse(const FeaturePtr& theEllipseFeature, + const std::string& theEllipsePoint) +{ + SketchPlugin_Sketch* aSketch = + std::dynamic_pointer_cast(theEllipseFeature)->sketch(); + + FeaturePtr aPointFeature = aSketch->addFeature(SketchPlugin_Point::ID()); + aPointFeature->boolean(SketchPlugin_Point::AUXILIARY_ID())->setValue(true); + aPointFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(theEllipseFeature); + + AttributePoint2DPtr anElPoint = std::dynamic_pointer_cast( + theEllipseFeature->attribute(theEllipsePoint)); + + AttributePoint2DPtr aCoord = std::dynamic_pointer_cast( + aPointFeature->attribute(SketchPlugin_Point::COORD_ID())); + aCoord->setValue(anElPoint->x(), anElPoint->y()); + + aPointFeature->execute(); + std::string aName = theEllipseFeature->name() + "_" + theEllipsePoint; + aPointFeature->data()->setName(aName); + aPointFeature->lastResult()->data()->setName(aName); + + createConstraintAttrAttr(aSketch, + SketchPlugin_ConstraintCoincidenceInternal::ID(), anElPoint, aCoord); +} + +void createAuxiliaryAxisOfEllipse(const FeaturePtr& theEllipseFeature, + const std::string& theStartPoint, + const std::string& theEndPoint) +{ + SketchPlugin_Sketch* aSketch = + std::dynamic_pointer_cast(theEllipseFeature)->sketch(); + + FeaturePtr aLineFeature = aSketch->addFeature(SketchPlugin_Line::ID()); + aLineFeature->boolean(SketchPlugin_Point::AUXILIARY_ID())->setValue(true); + aLineFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(theEllipseFeature); + + AttributePoint2DPtr aStartPoint = std::dynamic_pointer_cast( + theEllipseFeature->attribute(theStartPoint)); + AttributePoint2DPtr aEndPoint = std::dynamic_pointer_cast( + theEllipseFeature->attribute(theEndPoint)); + + AttributePoint2DPtr aLineStart = std::dynamic_pointer_cast( + aLineFeature->attribute(SketchPlugin_Line::START_ID())); + aLineStart->setValue(aStartPoint->x(), aStartPoint->y()); + + AttributePoint2DPtr aLineEnd = std::dynamic_pointer_cast( + aLineFeature->attribute(SketchPlugin_Line::END_ID())); + aLineEnd->setValue(aEndPoint->x(), aEndPoint->y()); + + aLineFeature->execute(); + std::string aName = theEllipseFeature->name() + "_" + + (theStartPoint == SketchPlugin_Ellipse::MAJOR_AXIS_START_ID() ? "major_axis" : "minor_axis"); + aLineFeature->data()->setName(aName); + aLineFeature->lastResult()->data()->setName(aName); + + createConstraintAttrAttr(aSketch, + SketchPlugin_ConstraintCoincidenceInternal::ID(), aStartPoint, aLineStart); + createConstraintAttrAttr(aSketch, + SketchPlugin_ConstraintCoincidenceInternal::ID(), aEndPoint, aLineEnd); +} + GeomPnt2dPtr flyoutPointCoordinates(const ConstraintPtr& theConstraint) { // currently process Length constraints only diff --git a/src/SketchPlugin/SketchPlugin_Tools.h b/src/SketchPlugin/SketchPlugin_Tools.h index 730d865b9..31162f91d 100644 --- a/src/SketchPlugin/SketchPlugin_Tools.h +++ b/src/SketchPlugin/SketchPlugin_Tools.h @@ -103,6 +103,21 @@ void createCoincidenceOrTangency(SketchPlugin_Feature* theFeature, const ObjectPtr theObject, const bool theIsCanBeTangent); +/// Creates auxiliary point for ellipse and corresponding internal constraint. +/// \param[in] theEllipse base ellipse feature +/// \param[in] theAttrName name of the attribute of the ellipse, +/// the new point should be constrained +void createAuxiliaryPointOnEllipse(const FeaturePtr& theEllipseFeature, + const std::string& theAttrName); + +/// Creates auxiliary axis for ellipse and corresponding internal constraints. +/// \param[in] theEllipse base ellipse feature +/// \param[in] theStartAttr name of the attribute of the ellipse, the line is started +/// \param[in] theEndAttr name of the attribute of the ellipse, the line is ended +void createAuxiliaryAxisOfEllipse(const FeaturePtr& theEllipseFeature, + const std::string& theStartAttr, + const std::string& theEndAttr); + /// Creates passing point or tangent curve basing on the given attributes are initialized. /// \param[in] theRefAttr prefered attribute to be converted /// \param[in] theDefaultAttr default attribute if theRefAttr is not initialized diff --git a/src/SketchPlugin/SketchPlugin_Validators.cpp b/src/SketchPlugin/SketchPlugin_Validators.cpp index 63ab98c89..a889f1068 100644 --- a/src/SketchPlugin/SketchPlugin_Validators.cpp +++ b/src/SketchPlugin/SketchPlugin_Validators.cpp @@ -1150,7 +1150,7 @@ bool SketchPlugin_ProjectionValidator::isValid(const AttributePtr& theAttribute, return aValid; } - theError = "Error: Selected object is not line, circle or arc."; + theError = "Error: Selected object is not supported for projection."; return false; } diff --git a/src/SketchPlugin/plugin-Sketch.xml b/src/SketchPlugin/plugin-Sketch.xml index 8b1c3db31..fe1f4e2a1 100644 --- a/src/SketchPlugin/plugin-Sketch.xml +++ b/src/SketchPlugin/plugin-Sketch.xml @@ -5,7 +5,7 @@ id="Sketch" nested="SketchPoint SketchIntersectionPoint SketchLine SketchCircle SketchMacroCircle SketchArc SketchMacroArc - SketchEllipse SketchMacroEllipse + SketchEllipse SketchMacroEllipse SketchEllipticArc SketchMacroEllipticArc SketchRectangle SketchProjection SketchConstraintLength SketchConstraintRadius SketchConstraintDistance SketchConstraintDistanceHorizontal SketchConstraintDistanceVertical @@ -51,7 +51,7 @@ - + - - - - - - - - - - - - - - - - - - + enable_value="enable_by_preferences"/> - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EdgeWrapper.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EdgeWrapper.cpp index bb8af7873..3a7aa0cb4 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EdgeWrapper.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EdgeWrapper.cpp @@ -20,24 +20,45 @@ #include #include +static bool isLine(const GCSCurvePtr& theEntity) +{ + return std::dynamic_pointer_cast(theEntity).get(); +} + +static bool isCircle(const GCSCurvePtr& theEntity) +{ + return std::dynamic_pointer_cast(theEntity).get(); +} + +static bool isArc(const GCSCurvePtr& theEntity) +{ + return std::dynamic_pointer_cast(theEntity).get(); +} + +static bool isEllipse(const GCSCurvePtr& theEntity) +{ + return std::dynamic_pointer_cast(theEntity).get(); +} + +static bool isEllipticArc(const GCSCurvePtr& theEntity) +{ + return std::dynamic_pointer_cast(theEntity).get(); +} + + PlaneGCSSolver_EdgeWrapper::PlaneGCSSolver_EdgeWrapper(const GCSCurvePtr theEntity) : myEntity(theEntity) { - std::shared_ptr aLine = std::dynamic_pointer_cast(myEntity); - if (aLine) myType = ENTITY_LINE; - else { - std::shared_ptr anArc = std::dynamic_pointer_cast(myEntity); - if (anArc) myType = ENTITY_ARC; - else { - std::shared_ptr aCircle = std::dynamic_pointer_cast(myEntity); - if (aCircle) myType = ENTITY_CIRCLE; - else { - std::shared_ptr anEllipse = - std::dynamic_pointer_cast(myEntity); - if (anEllipse) myType = ENTITY_ELLIPSE; - } - } - } + if (isLine(myEntity)) + myType = ENTITY_LINE; + else if (isArc(myEntity)) + myType = ENTITY_ARC; + else if (isCircle(myEntity)) + myType = ENTITY_CIRCLE; + else if (isEllipticArc(myEntity)) + myType = ENTITY_ELLIPTICAL_ARC; + else if (isEllipse(myEntity)) + myType = ENTITY_ELLIPSE; } static double squareDistance(const GCS::Point& theP1, const GCS::Point& theP2) @@ -49,27 +70,36 @@ static double squareDistance(const GCS::Point& theP1, const GCS::Point& theP2) bool PlaneGCSSolver_EdgeWrapper::isDegenerated() const { - static const double aSqTol = tolerance * 1e-2; - static const double aMaxRadius = 1e8; + static const double THE_SQ_TOL = tolerance * 1e-2; + static const double THE_ANGLE_TOL = 1.e-5; + static const double THE_MAX_RADIUS = 1e8; + static const double THE_SQ_MAX_RADIUS = THE_MAX_RADIUS * THE_MAX_RADIUS; + if (myType == ENTITY_LINE) { std::shared_ptr aLine = std::dynamic_pointer_cast(myEntity); - return squareDistance(aLine->p1, aLine->p2) < aSqTol; + return squareDistance(aLine->p1, aLine->p2) < THE_SQ_TOL; } else if (myType == ENTITY_CIRCLE) { std::shared_ptr aCircle = std::dynamic_pointer_cast(myEntity); - return *aCircle->rad < tolerance || *aCircle->rad > aMaxRadius; + return *aCircle->rad < tolerance || *aCircle->rad > THE_MAX_RADIUS; } else if (myType == ENTITY_ARC) { - static const double anAngleTol = 1.e-5; std::shared_ptr anArc = std::dynamic_pointer_cast(myEntity); double anAngleDiff = fabs(*anArc->startAngle - *anArc->endAngle); double aSqRadius = squareDistance(anArc->center, anArc->start); - return aSqRadius < aSqTol || aSqRadius > aMaxRadius * aMaxRadius || // <- arc radius - anAngleDiff < anAngleTol || fabs(anAngleDiff - 2*PI) < anAngleTol; // <- arc angle + return aSqRadius < THE_SQ_TOL || aSqRadius > THE_SQ_MAX_RADIUS || // <- arc radius + anAngleDiff < THE_ANGLE_TOL || fabs(anAngleDiff - 2*PI) < THE_ANGLE_TOL; // <- arc angle } else if (myType == ENTITY_ELLIPSE) { std::shared_ptr anEllipse = std::dynamic_pointer_cast(myEntity); - return *anEllipse->radmin < tolerance; + return *anEllipse->radmin < tolerance || anEllipse->getRadMaj() > THE_MAX_RADIUS; + } + else if (myType == ENTITY_ELLIPTICAL_ARC) { + std::shared_ptr anArc = + std::dynamic_pointer_cast(myEntity); + double anAngleDiff = fabs(*anArc->startAngle - *anArc->endAngle); + return *anArc->radmin < THE_SQ_TOL || anArc->getRadMaj() > THE_SQ_MAX_RADIUS || // <- arc radius + anAngleDiff < THE_ANGLE_TOL || fabs(anAngleDiff - 2*PI) < THE_ANGLE_TOL; // <- arc angle } return false; } diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_FeatureBuilder.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_FeatureBuilder.cpp index 4755eb6bf..400319aed 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_FeatureBuilder.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_FeatureBuilder.cpp @@ -22,10 +22,12 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -42,6 +44,8 @@ static EntityWrapperPtr createCircle(const AttributeEntityMap& theAttributes); static EntityWrapperPtr createArc(const AttributeEntityMap& theAttributes, PlaneGCSSolver_Storage* theStorage); static EntityWrapperPtr createEllipse(const AttributeEntityMap& theAttributes); +static EntityWrapperPtr createEllipticArc(const AttributeEntityMap& theAttributes, + PlaneGCSSolver_Storage* theStorage); PlaneGCSSolver_FeatureBuilder::PlaneGCSSolver_FeatureBuilder( @@ -95,6 +99,9 @@ EntityWrapperPtr PlaneGCSSolver_FeatureBuilder::createFeature(FeaturePtr theFeat // Ellipse else if (aFeatureKind == SketchPlugin_Ellipse::ID()) aResult = createEllipse(myAttributes); + // Arc of ellipse + else if (aFeatureKind == SketchPlugin_EllipticArc::ID()) + aResult = createEllipticArc(myAttributes, myStorage); // Point (it has low probability to be an attribute of constraint, so it is checked at the end) else if (aFeatureKind == SketchPlugin_Point::ID() || aFeatureKind == SketchPlugin_IntersectionPoint::ID()) { @@ -189,29 +196,16 @@ EntityWrapperPtr createArc(const AttributeEntityMap& theAttributes, } } - // Additional atrtributes of arc necessary for PlaneGCS solver + // Additional attributes of arc necessary for PlaneGCS solver // (start and end angles, radius) aNewArc->startAngle = createParameter(theStorage); aNewArc->endAngle = createParameter(theStorage); aNewArc->rad = createParameter(theStorage); - static std::shared_ptr OX(new GeomAPI_Dir2d(1.0, 0.0)); - std::shared_ptr aCenter( - new GeomAPI_Pnt2d(*aNewArc->center.x, *aNewArc->center.y)); - std::shared_ptr aStart( - new GeomAPI_Pnt2d(*aNewArc->start.x, *aNewArc->start.y)); - - *aNewArc->rad = aStart->distance(aCenter); - - std::shared_ptr aDir(new GeomAPI_Dir2d(aStart->xy()->decreased(aCenter->xy()))); - *aNewArc->startAngle = OX->angle(aDir); - - aDir = std::shared_ptr( - new GeomAPI_Dir2d((*aNewArc->end.x) - aCenter->x(), (*aNewArc->end.y) - aCenter->y())); - *aNewArc->endAngle = OX->angle(aDir); - EdgeWrapperPtr anArcWrapper(new PlaneGCSSolver_EdgeWrapper(aNewArc)); anArcWrapper->setReversed(isReversed); + PlaneGCSSolver_Tools::recalculateArcParameters(anArcWrapper); + return anArcWrapper; } @@ -247,6 +241,53 @@ EntityWrapperPtr createEllipse(const AttributeEntityMap& theAttributes) return anEllipseWrapper; } +EntityWrapperPtr createEllipticArc(const AttributeEntityMap& theAttributes, + PlaneGCSSolver_Storage* theStorage) +{ + std::shared_ptr aNewArc(new GCS::ArcOfEllipse); + + BooleanWrapperPtr isReversed; + std::map anAdditionalAttributes; + + AttributeEntityMap::const_iterator anIt = theAttributes.begin(); + for (; anIt != theAttributes.end(); ++anIt) { + std::shared_ptr aPoint = + std::dynamic_pointer_cast(anIt->second); + if (aPoint) { + if (anIt->first->id() == SketchPlugin_EllipticArc::CENTER_ID()) + aNewArc->center = *(aPoint->point()); + else if (anIt->first->id() == SketchPlugin_EllipticArc::FIRST_FOCUS_ID()) + aNewArc->focus1 = *(aPoint->point()); + else if (anIt->first->id() == SketchPlugin_EllipticArc::START_POINT_ID()) + aNewArc->start = *(aPoint->point()); + else if (anIt->first->id() == SketchPlugin_EllipticArc::END_POINT_ID()) + aNewArc->end = *(aPoint->point()); + else + anAdditionalAttributes[anIt->first->id()] = anIt->second; + } + else if (anIt->first->id() == SketchPlugin_EllipticArc::MINOR_RADIUS_ID()) { + ScalarWrapperPtr aScalar = + std::dynamic_pointer_cast(anIt->second); + aNewArc->radmin = aScalar->scalar(); + } + else if (anIt->first->id() == SketchPlugin_EllipticArc::REVERSED_ID()) + isReversed = std::dynamic_pointer_cast(anIt->second); + else + anAdditionalAttributes[anIt->first->id()] = anIt->second; + } + + // Additional attributes of elliptic arc necessary for PlaneGCS solver (start and end angles) + aNewArc->startAngle = createParameter(theStorage); + aNewArc->endAngle = createParameter(theStorage); + + EdgeWrapperPtr anEllipseWrapper(new PlaneGCSSolver_EdgeWrapper(aNewArc)); + anEllipseWrapper->setReversed(isReversed); + anEllipseWrapper->setAdditionalAttributes(anAdditionalAttributes); + PlaneGCSSolver_Tools::recalculateArcParameters(anEllipseWrapper); + + return anEllipseWrapper; +} + bool isAttributeApplicable(const std::string& theAttrName, const std::string& theOwnerName) { if (theOwnerName == SketchPlugin_Arc::ID()) { @@ -274,6 +315,20 @@ bool isAttributeApplicable(const std::string& theAttrName, const std::string& th theAttrName == SketchPlugin_Ellipse::MAJOR_RADIUS_ID() || theAttrName == SketchPlugin_Ellipse::MINOR_RADIUS_ID(); } + else if (theOwnerName == SketchPlugin_EllipticArc::ID()) { + return theAttrName == SketchPlugin_EllipticArc::CENTER_ID() || + theAttrName == SketchPlugin_EllipticArc::FIRST_FOCUS_ID() || + theAttrName == SketchPlugin_EllipticArc::SECOND_FOCUS_ID() || + theAttrName == SketchPlugin_EllipticArc::MAJOR_AXIS_START_ID() || + theAttrName == SketchPlugin_EllipticArc::MAJOR_AXIS_END_ID() || + theAttrName == SketchPlugin_EllipticArc::MINOR_AXIS_START_ID() || + theAttrName == SketchPlugin_EllipticArc::MINOR_AXIS_END_ID() || + theAttrName == SketchPlugin_EllipticArc::MAJOR_RADIUS_ID() || + theAttrName == SketchPlugin_EllipticArc::MINOR_RADIUS_ID() || + theAttrName == SketchPlugin_EllipticArc::START_POINT_ID() || + theAttrName == SketchPlugin_EllipticArc::END_POINT_ID() || + theAttrName == SketchPlugin_EllipticArc::REVERSED_ID(); + } // suppose that all remaining features are points return theAttrName == SketchPlugin_Point::COORD_ID(); diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp index 6a41efc0d..2aff74fb4 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp @@ -224,28 +224,8 @@ bool PlaneGCSSolver_Storage::update(FeaturePtr theFeature, bool theForce) notify(theFeature); // update arc - if (aRelated && aRelated->type() == ENTITY_ARC) { - /// TODO: this code should be shared with FeatureBuilder somehow - - std::shared_ptr anEntity = - std::dynamic_pointer_cast(aRelated); - std::shared_ptr anArc = std::dynamic_pointer_cast(anEntity->entity()); - - static std::shared_ptr OX(new GeomAPI_Dir2d(1.0, 0.0)); - std::shared_ptr aCenter( - new GeomAPI_Pnt2d(*anArc->center.x, *anArc->center.y)); - std::shared_ptr aStart( - new GeomAPI_Pnt2d(*anArc->start.x, *anArc->start.y)); - - *anArc->rad = aStart->distance(aCenter); - - std::shared_ptr aDir(new GeomAPI_Dir2d(aStart->xy()->decreased(aCenter->xy()))); - *anArc->startAngle = OX->angle(aDir); - - aDir = std::shared_ptr( - new GeomAPI_Dir2d((*anArc->end.x) - aCenter->x(), (*anArc->end.y) - aCenter->y())); - *anArc->endAngle = OX->angle(aDir); - } + if (aRelated) + PlaneGCSSolver_Tools::recalculateArcParameters(aRelated); return isUpdated; } @@ -397,11 +377,42 @@ static void createEllipseConstraints( ConstraintWrapperPtr aWrapper( new PlaneGCSSolver_ConstraintWrapper(anEllipseConstraints, CONSTRAINT_UNKNOWN)); aWrapper->setId(theConstraintID); - constraintsToSolver(aWrapper, theSolver); + if (theSolver) + constraintsToSolver(aWrapper, theSolver); theConstraints[theEllipse] = aWrapper; } +static void createEllipticArcConstraints( + const EntityWrapperPtr& theEllipticArc, + const SolverPtr& theSolver, + const ConstraintID theConstraintID, + std::map& theConstraints) +{ + // create base constraints for the ellipse without adding them to solver + createEllipseConstraints(theEllipticArc, SolverPtr(), theConstraintID, theConstraints); + + ConstraintWrapperPtr& aConstraint = theConstraints[theEllipticArc]; + std::list anEllArcConstraints = aConstraint->constraints(); + + // constrain extremities of the elliptic arc + EdgeWrapperPtr anEdge = std::dynamic_pointer_cast(theEllipticArc); + std::shared_ptr anArc = + std::dynamic_pointer_cast(anEdge->entity()); + + anEllArcConstraints.push_back(GCSConstraintPtr( + new GCS::ConstraintCurveValue(anArc->start, anArc->start.x, *anArc, anArc->startAngle))); + anEllArcConstraints.push_back(GCSConstraintPtr( + new GCS::ConstraintCurveValue(anArc->start, anArc->start.y, *anArc, anArc->startAngle))); + anEllArcConstraints.push_back(GCSConstraintPtr( + new GCS::ConstraintCurveValue(anArc->end, anArc->end.x, *anArc, anArc->endAngle))); + anEllArcConstraints.push_back(GCSConstraintPtr( + new GCS::ConstraintCurveValue(anArc->end, anArc->end.y, *anArc, anArc->endAngle))); + + aConstraint->setConstraints(anEllArcConstraints); + constraintsToSolver(aConstraint, theSolver); +} + void PlaneGCSSolver_Storage::createAuxiliaryConstraints(const EntityWrapperPtr& theEntity) { if (!theEntity || theEntity->isExternal()) @@ -411,6 +422,10 @@ void PlaneGCSSolver_Storage::createAuxiliaryConstraints(const EntityWrapperPtr& createArcConstraints(theEntity, mySketchSolver, ++myConstraintLastID, myAuxConstraintMap); else if (theEntity->type() == ENTITY_ELLIPSE) createEllipseConstraints(theEntity, mySketchSolver, ++myConstraintLastID, myAuxConstraintMap); + else if (theEntity->type() == ENTITY_ELLIPTICAL_ARC) { + createEllipticArcConstraints(theEntity, mySketchSolver, + ++myConstraintLastID, myAuxConstraintMap); + } } void PlaneGCSSolver_Storage::removeAuxiliaryConstraints(const EntityWrapperPtr& theEntity) @@ -423,30 +438,42 @@ void PlaneGCSSolver_Storage::removeAuxiliaryConstraints(const EntityWrapperPtr& } } +template +void adjustArcParametrization(ARCTYPE& theArc, bool theReversed) +{ + // tune start angle of the arc to be in [0, 2PI] + while (*theArc.startAngle < -PI) + *theArc.startAngle += 2.0 * PI; + while (*theArc.startAngle >= PI) + *theArc.startAngle -= 2.0 * PI; + // adjust end angle of the arc + if (theReversed) { + while (*theArc.endAngle > *theArc.startAngle) + *theArc.endAngle -= 2.0 * PI; + while (*theArc.endAngle + 2 * PI < *theArc.startAngle) + *theArc.endAngle += 2.0 * PI; + } + else { + while (*theArc.endAngle < *theArc.startAngle) + *theArc.endAngle += 2.0 * PI; + while (*theArc.endAngle > *theArc.startAngle + 2 * PI) + *theArc.endAngle -= 2.0 * PI; + } +} + void PlaneGCSSolver_Storage::adjustParametrizationOfArcs() { std::map::iterator anIt = myAuxConstraintMap.begin(); for (; anIt != myAuxConstraintMap.end(); ++anIt) { EdgeWrapperPtr anEdge = std::dynamic_pointer_cast(anIt->first); std::shared_ptr anArc = std::dynamic_pointer_cast(anEdge->entity()); - if (!anArc) - continue; - // tune start angle of the arc to be in [0, 2PI] - while (*anArc->startAngle < -PI) - *anArc->startAngle += 2.0 * PI; - while (*anArc->startAngle >= PI) - *anArc->startAngle -= 2.0 * PI; - // adjust end angle of the arc - if (anEdge->isReversed()) { - while (*anArc->endAngle > *anArc->startAngle) - *anArc->endAngle -= 2.0 * PI; - while (*anArc->endAngle + 2 * PI < *anArc->startAngle) - *anArc->endAngle += 2.0 * PI; - } else { - while (*anArc->endAngle < *anArc->startAngle) - *anArc->endAngle += 2.0 * PI; - while (*anArc->endAngle > *anArc->startAngle + 2 * PI) - *anArc->endAngle -= 2.0 * PI; + if (anArc) + adjustArcParametrization(*anArc, anEdge->isReversed()); + else { +//// std::shared_ptr aEllArc = +//// std::dynamic_pointer_cast(anEdge->entity()); +//// if (aEllArc) +//// adjustArcParametrization(*aEllArc, anEdge->isReversed()); } } diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.cpp index 11c265dd0..461ae6885 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.cpp @@ -122,6 +122,9 @@ static GCS::SET_pD lineParameters(const EdgeWrapperPtr& theLine); static GCS::SET_pD circleParameters(const EdgeWrapperPtr& theCircle); static GCS::SET_pD arcParameters(const EdgeWrapperPtr& theArc); static GCS::SET_pD ellipseParameters(const EdgeWrapperPtr& theEllipse); +static GCS::SET_pD ellipticArcParameters(const EdgeWrapperPtr& theEllipticArc); + +static double distance(const GCS::Point& thePnt1, const GCS::Point& thePnt2); @@ -321,6 +324,54 @@ std::shared_ptr PlaneGCSSolver_Tools::ellipse(EntityWrapperPt new GeomAPI_Ellipse2d(aCenter, anAxis, anEllipse->getRadMaj(), *anEllipse->radmin)); } +void PlaneGCSSolver_Tools::recalculateArcParameters(EntityWrapperPtr theArc) +{ + std::shared_ptr anEdge = + std::dynamic_pointer_cast(theArc); + if (!anEdge) + return; + + GCS::Point aCenter, aStartPnt, aEndPnt; + double *aStartAngle, *aEndAngle; + GeomDir2dPtr OX; + + if (anEdge->type() == ENTITY_ARC) { + std::shared_ptr anArc = std::dynamic_pointer_cast(anEdge->entity()); + + aCenter = anArc->center; + aStartPnt = anArc->start; + aEndPnt = anArc->end; + + *anArc->rad = distance(aCenter, aStartPnt); + + aStartAngle = anArc->startAngle; + aEndAngle = anArc->endAngle; + + OX.reset(new GeomAPI_Dir2d(1.0, 0.0)); + } + else if (anEdge->type() == ENTITY_ELLIPTICAL_ARC) { + std::shared_ptr aEllArc = + std::dynamic_pointer_cast(anEdge->entity()); + + aCenter = aEllArc->center; + aStartPnt = aEllArc->start; + aEndPnt = aEllArc->end; + + aStartAngle = aEllArc->startAngle; + aEndAngle = aEllArc->endAngle; + + OX.reset(new GeomAPI_Dir2d(*aEllArc->focus1.x - *aCenter.x, *aEllArc->focus1.y - *aCenter.y)); + } + else // skip other type of entities + return; + + GeomDir2dPtr aDir(new GeomAPI_Dir2d(*aStartPnt.x - *aCenter.x, *aStartPnt.y - *aCenter.y)); + *aStartAngle = OX->angle(aDir); + + aDir.reset(new GeomAPI_Dir2d(*aEndPnt.x - *aCenter.x, *aEndPnt.y - *aCenter.y)); + *aEndAngle = OX->angle(aDir); +} + GCS::SET_pD PlaneGCSSolver_Tools::parameters(const EntityWrapperPtr& theEntity) @@ -339,6 +390,8 @@ GCS::SET_pD PlaneGCSSolver_Tools::parameters(const EntityWrapperPtr& theEntity) return arcParameters(GCS_EDGE_WRAPPER(theEntity)); case ENTITY_ELLIPSE: return ellipseParameters(GCS_EDGE_WRAPPER(theEntity)); + case ENTITY_ELLIPTICAL_ARC: + return ellipticArcParameters(GCS_EDGE_WRAPPER(theEntity)); default: break; } return GCS::SET_pD(); @@ -608,10 +661,7 @@ ConstraintWrapperPtr createConstraintEqual( aConstrList.push_back(GCSConstraintPtr( new GCS::ConstraintP2PDistance(aLine2->p1, aLine2->p2, theIntermed->scalar()))); // update value of intermediate parameter - double x = *aLine1->p1.x - *aLine1->p2.x; - double y = *aLine1->p1.y - *aLine1->p2.y; - double aLen = sqrt(x*x + y*y); - theIntermed->setValue(aLen); + theIntermed->setValue(distance(aLine1->p1, aLine1->p2)); } else { std::shared_ptr aCirc1 = std::dynamic_pointer_cast(theEntity1->entity()); @@ -678,17 +728,14 @@ GCS::SET_pD circleParameters(const EdgeWrapperPtr& theCircle) GCS::SET_pD arcParameters(const EdgeWrapperPtr& theArc) { - GCS::SET_pD aParams; + GCS::SET_pD aParams = circleParameters(theArc); std::shared_ptr anArc = std::dynamic_pointer_cast(theArc->entity()); - aParams.insert(anArc->center.x); - aParams.insert(anArc->center.y); aParams.insert(anArc->start.x); aParams.insert(anArc->start.y); aParams.insert(anArc->end.x); aParams.insert(anArc->end.y); aParams.insert(anArc->startAngle); aParams.insert(anArc->endAngle); - aParams.insert(anArc->rad); return aParams; } @@ -704,3 +751,24 @@ GCS::SET_pD ellipseParameters(const EdgeWrapperPtr& theEllipse) aParams.insert(anEllipse->radmin); return aParams; } + +GCS::SET_pD ellipticArcParameters(const EdgeWrapperPtr& theEllipticArc) +{ + GCS::SET_pD aParams = ellipseParameters(theEllipticArc); + std::shared_ptr anArc = + std::dynamic_pointer_cast(theEllipticArc->entity()); + aParams.insert(anArc->start.x); + aParams.insert(anArc->start.y); + aParams.insert(anArc->end.x); + aParams.insert(anArc->end.y); + aParams.insert(anArc->startAngle); + aParams.insert(anArc->endAngle); + return aParams; +} + +double distance(const GCS::Point& thePnt1, const GCS::Point& thePnt2) +{ + double x = *thePnt1.x - *thePnt2.x; + double y = *thePnt1.y - *thePnt2.y; + return sqrt(x*x + y*y); +} diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.h index 1eb95be4f..a02a9948c 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.h +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.h @@ -81,6 +81,11 @@ namespace PlaneGCSSolver_Tools /// \return empty pointer if the entity is not a line std::shared_ptr line(FeaturePtr theFeature); + /// \brief Update start and end parameters of circular and elliptic arcs + /// respectively to start and end points on the arc. + /// For the circular arc, the radius is calculated too. + void recalculateArcParameters(EntityWrapperPtr theArc); + /// brief Return list of parameters for the given entity GCS::SET_pD parameters(const EntityWrapperPtr& theEntity); }; diff --git a/src/SketchSolver/SketchSolver_ConstraintFixed.cpp b/src/SketchSolver/SketchSolver_ConstraintFixed.cpp index 2cb632522..7e7c6aab1 100644 --- a/src/SketchSolver/SketchSolver_ConstraintFixed.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintFixed.cpp @@ -151,6 +151,18 @@ GCS::VEC_pD toParameters(const EntityWrapperPtr& theEntity) aParameters.push_back(anEllipse->radmin); break; } + case ENTITY_ELLIPTICAL_ARC: { + std::shared_ptr anEllArc = + std::dynamic_pointer_cast(anEntity->entity()); + aParameters.push_back(anEllArc->center.x); + aParameters.push_back(anEllArc->center.y); + aParameters.push_back(anEllArc->focus1.x); + aParameters.push_back(anEllArc->focus1.y); + aParameters.push_back(anEllArc->radmin); + aParameters.push_back(anEllArc->startAngle); + aParameters.push_back(anEllArc->endAngle); + break; + } default: break; } diff --git a/src/SketchSolver/SketchSolver_ConstraintMovement.cpp b/src/SketchSolver/SketchSolver_ConstraintMovement.cpp index 1c752f47d..e4a59127b 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMovement.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintMovement.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -92,9 +93,11 @@ static bool isSimpleMove(FeaturePtr theMovedFeature, AttributePtr theDraggedPoin if (theMovedFeature->getKind() == SketchPlugin_Circle::ID() || theMovedFeature->getKind() == SketchPlugin_Ellipse::ID()) isSimple = (theDraggedPoint.get() != 0); - else if (theMovedFeature->getKind() == SketchPlugin_Arc::ID()) { + else if (theMovedFeature->getKind() == SketchPlugin_Arc::ID() || + theMovedFeature->getKind() == SketchPlugin_EllipticArc::ID()) { isSimple = (theDraggedPoint.get() != 0 && - theDraggedPoint->id() == SketchPlugin_Arc::CENTER_ID()); + (theDraggedPoint->id() == SketchPlugin_Arc::CENTER_ID() || + theDraggedPoint->id() == SketchPlugin_EllipticArc::CENTER_ID())); } #endif return isSimple; @@ -152,12 +155,21 @@ ConstraintWrapperPtr SketchSolver_ConstraintMovement::fixArcExtremity( myStorage->entity(myMovedFeature)); std::shared_ptr anArc = std::dynamic_pointer_cast(aCircularEntity->entity()); + std::shared_ptr anEllArc = + std::dynamic_pointer_cast(aCircularEntity->entity()); PointWrapperPtr aPoint = std::dynamic_pointer_cast(theArcExtremity); - double* aParams[nbParams] = { aPoint->point()->x, aPoint->point()->y, - anArc->center.x, anArc->center.y }; + double* aParams[nbParams] = { aPoint->point()->x, aPoint->point()->y, 0, 0 }; + if (anArc) { + aParams[2] = anArc->center.x; + aParams[3] = anArc->center.y; + } + else if (anEllArc) { + aParams[2] = anEllArc->center.x; + aParams[3] = anEllArc->center.y; + } std::list aConstraints; for (int i = 0; i < nbParams; ++i) { -- 2.39.2