From 9e88f9dfeaf43d1bed488e706ae5d77b6c6ea8bf Mon Sep 17 00:00:00 2001 From: azv Date: Fri, 6 Sep 2019 08:36:27 +0300 Subject: [PATCH] Task 2.12. New entities: ellipses and arcs of ellipses (issue #3003) * Introduce ellipse in SketchPlugin. * Make ellipse processable by the solver. --- lcov_reports.sh | 3 - src/SketchPlugin/SketchPlugin_Ellipse.cpp | 171 +++++++++---- src/SketchPlugin/SketchPlugin_Ellipse.h | 51 +++- src/SketchPlugin/SketchPlugin_Line.cpp | 17 +- .../SketchPlugin_MacroEllipse.cpp | 225 +++++++++++------- src/SketchPlugin/SketchPlugin_MacroEllipse.h | 60 +++-- src/SketchPlugin/SketchPlugin_Plugin.cpp | 1 + src/SketchPlugin/SketchPlugin_Sketch.cpp | 29 +++ src/SketchPlugin/SketchPlugin_Sketch.h | 12 + src/SketchPlugin/SketchPlugin_SketchEntity.h | 7 +- src/SketchPlugin/icons/ellipse.png | Bin 586 -> 743 bytes src/SketchPlugin/icons/ellipse_axes_32x32.png | Bin 0 -> 1295 bytes .../icons/ellipse_cent_rad_32x32.png | Bin 0 -> 1335 bytes src/SketchPlugin/icons/elliptic_arc.png | Bin 0 -> 579 bytes src/SketchPlugin/icons/radius_major.png | Bin 0 -> 387 bytes src/SketchPlugin/icons/radius_minor.png | Bin 0 -> 426 bytes src/SketchPlugin/plugin-Sketch.xml | 112 ++++++--- .../PlaneGCSSolver/CMakeLists.txt | 2 +- .../PlaneGCSSolver/PlaneGCSSolver_Defs.h | 4 +- .../PlaneGCSSolver_EdgeWrapper.cpp | 9 + .../PlaneGCSSolver_EntityWrapper.h | 13 +- .../PlaneGCSSolver_FeatureBuilder.cpp | 48 ++++ .../PlaneGCSSolver/PlaneGCSSolver_Storage.cpp | 116 +++++++-- .../PlaneGCSSolver/PlaneGCSSolver_Storage.h | 13 +- .../PlaneGCSSolver/PlaneGCSSolver_Tools.cpp | 37 ++- .../SketchSolver_ConstraintFixed.cpp | 10 + .../SketchSolver_ConstraintMovement.cpp | 89 ++++++- .../SketchSolver_ConstraintMovement.h | 5 +- 28 files changed, 797 insertions(+), 237 deletions(-) create mode 100644 src/SketchPlugin/icons/ellipse_axes_32x32.png create mode 100644 src/SketchPlugin/icons/ellipse_cent_rad_32x32.png create mode 100644 src/SketchPlugin/icons/elliptic_arc.png create mode 100644 src/SketchPlugin/icons/radius_major.png create mode 100644 src/SketchPlugin/icons/radius_minor.png diff --git a/lcov_reports.sh b/lcov_reports.sh index ebd0c76a1..cd094cf15 100755 --- a/lcov_reports.sh +++ b/lcov_reports.sh @@ -65,9 +65,6 @@ for MASK in $ALL; do mv -f covElse_res covElse fi done -# remove SketchPlugin's Ellipse feature (unsupported yet) -lcov -r covElse SketchPlugin*Ellipse* --output-file covElse_res -q -mv -f covElse_res covElse rm -rf lcov_htmlElse genhtml covElse --output-directory lcov_htmlElse -q diff --git a/src/SketchPlugin/SketchPlugin_Ellipse.cpp b/src/SketchPlugin/SketchPlugin_Ellipse.cpp index df323b167..1c5f5fadd 100644 --- a/src/SketchPlugin/SketchPlugin_Ellipse.cpp +++ b/src/SketchPlugin/SketchPlugin_Ellipse.cpp @@ -17,17 +17,18 @@ // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -// File: SketchPlugin_Ellipse.cpp -// Created: 26 April 2017 -// Author: Artem ZHIDKOV - #include #include #include + +#include #include #include +#include + #include + #include #include #include @@ -44,7 +45,12 @@ SketchPlugin_Ellipse::SketchPlugin_Ellipse() void SketchPlugin_Ellipse::initDerivedClassAttributes() { data()->addAttribute(CENTER_ID(), GeomDataAPI_Point2D::typeId()); - data()->addAttribute(FOCUS_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()); @@ -59,52 +65,45 @@ void SketchPlugin_Ellipse::execute() return; } - // 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(FOCUS_ID())); - AttributeDoublePtr aMajorRadiusAttr = real(MAJOR_RADIUS_ID()); - AttributeDoublePtr aMinorRadiusAttr = real(MINOR_RADIUS_ID()); - if (!aCenterAttr->isInitialized() || - !aFocusAttr->isInitialized() || - !aMajorRadiusAttr->isInitialized() || - !aMinorRadiusAttr->isInitialized()) { - return; - } - - double aMajorRadius = aMajorRadiusAttr->value(); - double aMinorRadius = aMinorRadiusAttr->value(); - if(aMajorRadius < tolerance || aMinorRadius < tolerance) { - return; - } - - // Make a visible point. - SketchPlugin_Sketch::createPoint2DResult(this, aSketch, CENTER_ID(), 0); - - std::shared_ptr aNDir = std::dynamic_pointer_cast( - aSketch->attribute(SketchPlugin_Sketch::NORM_ID())); + // Calculate all characteristics of the ellipse. + fillCharacteristicPoints(); + + // Make visible points related to ellipse characteristics. + int aResultIndex = 0; + SketchPlugin_Sketch::createPoint2DResult(this, aSketch, CENTER_ID(), aResultIndex++); + SketchPlugin_Sketch::createPoint2DResult(this, aSketch, FIRST_FOCUS_ID(), aResultIndex++); + SketchPlugin_Sketch::createPoint2DResult(this, aSketch, SECOND_FOCUS_ID(), aResultIndex++); + SketchPlugin_Sketch::createPoint2DResult(this, aSketch, MAJOR_AXIS_START_ID(), aResultIndex++); + SketchPlugin_Sketch::createPoint2DResult(this, aSketch, MAJOR_AXIS_END_ID(), aResultIndex++); + SketchPlugin_Sketch::createPoint2DResult(this, aSketch, MINOR_AXIS_START_ID(), aResultIndex++); + SketchPlugin_Sketch::createPoint2DResult(this, aSketch, MINOR_AXIS_END_ID(), aResultIndex++); + + // Make auxiliary axes + SketchPlugin_Sketch::createLine2DResult(this, aSketch, + MAJOR_AXIS_START_ID(), MAJOR_AXIS_END_ID(), aResultIndex++); + SketchPlugin_Sketch::createLine2DResult(this, aSketch, + MINOR_AXIS_START_ID(), MINOR_AXIS_END_ID(), aResultIndex++); + + // Mark already created results auxiliary + myAuxiliaryResults.clear(); + const std::list& aResults = results(); + std::list::const_iterator anIt = aResults.begin(); + for (int anIndex = 0; anIt != aResults.end() && anIndex < aResultIndex; ++anIt, ++anIndex) + myAuxiliaryResults.insert(*anIt); // Make a visible ellipse. - std::shared_ptr aCenter(aSketch->to3D(aCenterAttr->x(), aCenterAttr->y())); - std::shared_ptr aFocus(aSketch->to3D(aFocusAttr->x(), aFocusAttr->y())); - std::shared_ptr aNormal = aNDir->dir(); - std::shared_ptr aMajorAxis(new GeomAPI_Dir(aFocus->x() - aCenter->x(), - aFocus->y() - aCenter->y(), aFocus->z() - aCenter->z())); - - std::shared_ptr anEllipseShape = - GeomAlgoAPI_EdgeBuilder::ellipse(aCenter, aNormal, aMajorAxis, aMajorRadius, aMinorRadius); - - std::shared_ptr aResult = document()->createConstruction(data(), 1); - aResult->setShape(anEllipseShape); - aResult->setIsInHistory(false); - setResult(aResult, 1); + createEllipse(aSketch, aResultIndex); } bool SketchPlugin_Ellipse::isFixed() { return data()->selection(EXTERNAL_ID())->context().get() != NULL; } +bool SketchPlugin_Ellipse::isAuxiliary(ResultPtr theResult) +{ + return myAuxiliaryResults.find(theResult) != myAuxiliaryResults.end(); +} + void SketchPlugin_Ellipse::attributeChanged(const std::string& theID) { // the second condition for unability to move external segments anywhere if (theID == EXTERNAL_ID() || isFixed()) { @@ -125,7 +124,7 @@ void SketchPlugin_Ellipse::attributeChanged(const std::string& theID) { aCenterAttr->setValue(sketch()->to2D(anEllipse->center())); std::shared_ptr aFocusAttr = - std::dynamic_pointer_cast(attribute(FOCUS_ID())); + std::dynamic_pointer_cast(attribute(FIRST_FOCUS_ID())); aFocusAttr->setValue(sketch()->to2D(anEllipse->firstFocus())); real(MAJOR_RADIUS_ID())->setValue(anEllipse->majorRadius()); @@ -133,3 +132,87 @@ void SketchPlugin_Ellipse::attributeChanged(const std::string& theID) { } } } + +bool SketchPlugin_Ellipse::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 aMajorRadiusAttr = real(MAJOR_RADIUS_ID()); + AttributeDoublePtr aMinorRadiusAttr = real(MINOR_RADIUS_ID()); + + if (!aCenterAttr->isInitialized() || + !aFocusAttr->isInitialized() || + !aMajorRadiusAttr->isInitialized() || + !aMinorRadiusAttr->isInitialized()) { + return false; + } + + double aMajorRadius = aMajorRadiusAttr->value(); + double aMinorRadius = aMinorRadiusAttr->value(); + if (aMajorRadius < tolerance || 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())); + 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_Ellipse::createEllipse(SketchPlugin_Sketch* theSketch, const int theResultIndex) +{ + // 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())); + + anEllipseShape = + GeomAlgoAPI_EdgeBuilder::ellipse(aCenter, aNormal, aMajorAxis, aMajorRadius, aMinorRadius); + } + else { + // build circle instead of ellipse + anEllipseShape = GeomAlgoAPI_EdgeBuilder::lineCircle(aCenter, aNormal, aMajorRadius); + } + + ResultConstructionPtr aResult = document()->createConstruction(data(), theResultIndex); + aResult->setShape(anEllipseShape); + aResult->setIsInHistory(false); + setResult(aResult, theResultIndex); +} diff --git a/src/SketchPlugin/SketchPlugin_Ellipse.h b/src/SketchPlugin/SketchPlugin_Ellipse.h index e8c0252bd..bfa0478a7 100644 --- a/src/SketchPlugin/SketchPlugin_Ellipse.h +++ b/src/SketchPlugin/SketchPlugin_Ellipse.h @@ -17,10 +17,6 @@ // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -// File: SketchPlugin_Ellipse.h -// Created: 26 April 2017 -// Author: Artem ZHIDKOV - #ifndef SketchPlugin_Ellipse_H_ #define SketchPlugin_Ellipse_H_ @@ -49,9 +45,41 @@ class SketchPlugin_Ellipse: public SketchPlugin_SketchEntity } /// 2D point - focus of the ellipse - inline static const std::string& FOCUS_ID() + 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_focus"); + 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; } @@ -88,9 +116,20 @@ class SketchPlugin_Ellipse: public SketchPlugin_SketchEntity /// Use plugin manager for features creation SketchPlugin_Ellipse(); + /// Returns \c true if the result is marked as auxiliary + virtual bool isAuxiliary(ResultPtr theResult); + protected: /// \brief Initializes attributes of derived class. virtual void initDerivedClassAttributes(); + +private: + bool fillCharacteristicPoints(); + + void createEllipse(SketchPlugin_Sketch* theSketch, const int theResultIndex); + +private: + std::set myAuxiliaryResults; }; #endif diff --git a/src/SketchPlugin/SketchPlugin_Line.cpp b/src/SketchPlugin/SketchPlugin_Line.cpp index f68bf346b..f01a332f2 100644 --- a/src/SketchPlugin/SketchPlugin_Line.cpp +++ b/src/SketchPlugin/SketchPlugin_Line.cpp @@ -30,11 +30,11 @@ #include #include -#include +#include #include +#include #include -#include #include SketchPlugin_Line::SketchPlugin_Line() @@ -68,18 +68,7 @@ void SketchPlugin_Line::execute() std::shared_ptr anEndAttr = std::dynamic_pointer_cast< GeomDataAPI_Point2D>(data()->attribute(END_ID())); if (aStartAttr->isInitialized() && anEndAttr->isInitialized()) { - std::shared_ptr aStart(aSketch->to3D(aStartAttr->x(), aStartAttr->y())); - std::shared_ptr anEnd(aSketch->to3D(anEndAttr->x(), anEndAttr->y())); - //std::cout<<"Execute line "<x()<<" "<y()<<" "<z()<<" - " - // <x()<<" "<y()<<" "<z()< anEdge = GeomAlgoAPI_EdgeBuilder::line(aStart, anEnd); - // store the result - std::shared_ptr aConstr = document()->createConstruction( - data()); - aConstr->setShape(anEdge); - aConstr->setIsInHistory(false); - setResult(aConstr); + SketchPlugin_Sketch::createLine2DResult(this, aSketch, START_ID(), END_ID()); static Events_ID anId = ModelAPI_EventReentrantMessage::eventId(); std::shared_ptr aMessage = std::shared_ptr diff --git a/src/SketchPlugin/SketchPlugin_MacroEllipse.cpp b/src/SketchPlugin/SketchPlugin_MacroEllipse.cpp index 5bc378e9a..f46286af6 100644 --- a/src/SketchPlugin/SketchPlugin_MacroEllipse.cpp +++ b/src/SketchPlugin/SketchPlugin_MacroEllipse.cpp @@ -17,19 +17,16 @@ // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -// File: SketchPlugin_MacroEllipse.cpp -// Created: 26 April 2017 -// Author: Artem ZHIDKOV - #include #include +#include #include #include #include #include -#include +#include #include #include #include @@ -37,7 +34,6 @@ #include #include -#include #include #include @@ -55,10 +51,13 @@ SketchPlugin_MacroEllipse::SketchPlugin_MacroEllipse() void SketchPlugin_MacroEllipse::initAttributes() { - data()->addAttribute(CENTER_POINT_ID(), GeomDataAPI_Point2D::typeId()); - data()->addAttribute(CENTER_POINT_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(ELLIPSE_TYPE(), ModelAPI_AttributeString::typeId()); + data()->addAttribute(EDIT_ELLIPSE_TYPE(), ModelAPI_AttributeString::typeId()); + + data()->addAttribute(FIRST_POINT_ID(), GeomDataAPI_Point2D::typeId()); + data()->addAttribute(FIRST_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId()); + data()->addAttribute(SECOND_POINT_ID(), GeomDataAPI_Point2D::typeId()); + data()->addAttribute(SECOND_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId()); data()->addAttribute(PASSED_POINT_ID(), GeomDataAPI_Point2D::typeId()); data()->addAttribute(PASSED_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId()); @@ -66,20 +65,31 @@ void SketchPlugin_MacroEllipse::initAttributes() data()->addAttribute(MINOR_RADIUS_ID(), ModelAPI_AttributeDouble::typeId()); data()->addAttribute(AUXILIARY_ID(), ModelAPI_AttributeBoolean::typeId()); - ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), CENTER_POINT_REF_ID()); - ModelAPI_Session::get()->validators()-> - registerNotObligatory(getKind(), MAJOR_AXIS_POINT_REF_ID()); + string(EDIT_ELLIPSE_TYPE())->setValue(""); + + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), FIRST_POINT_REF_ID()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), SECOND_POINT_REF_ID()); ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PASSED_POINT_REF_ID()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EDIT_ELLIPSE_TYPE()); } void SketchPlugin_MacroEllipse::execute() { FeaturePtr anEllipse = createEllipseFeature(); - constraintsForEllipse(anEllipse); + + std::string aType = string(ELLIPSE_TYPE())->value(); + if (aType == ELLIPSE_TYPE_BY_CENTER_AXIS_POINT()) + constraintsForEllipseByCenterAxisAndPassed(anEllipse); + else if (aType == ELLIPSE_TYPE_BY_AXIS_AND_POINT()) + constraintsForEllipseByMajoxAxisAndPassed(anEllipse); // message to init reentrant operation - static Events_ID anId = ModelAPI_EventReentrantMessage::eventId(); - ReentrantMessagePtr aMessage(new ModelAPI_EventReentrantMessage(anId, this)); + static Events_ID anId = SketchPlugin_MacroArcReentrantMessage::eventId(); + std::shared_ptr aMessage = std::shared_ptr + (new SketchPlugin_MacroArcReentrantMessage(anId, this)); + + std::string anEditType = string(EDIT_ELLIPSE_TYPE())->value(); + aMessage->setTypeOfCreation(!anEditType.empty() ? anEditType : aType); aMessage->setCreatedFeature(anEllipse); Events_Loop::loop()->send(aMessage); } @@ -87,79 +97,105 @@ void SketchPlugin_MacroEllipse::execute() void SketchPlugin_MacroEllipse::attributeChanged(const std::string& theID) { static const int NB_POINTS = 3; - std::string aPointAttrName[NB_POINTS] = { CENTER_POINT_ID(), - MAJOR_AXIS_POINT_ID(), + std::string aPointAttrName[NB_POINTS] = { FIRST_POINT_ID(), + SECOND_POINT_ID(), PASSED_POINT_ID() }; - std::string aPointRefName[NB_POINTS] = { CENTER_POINT_REF_ID(), - MAJOR_AXIS_POINT_REF_ID(), + std::string aPointRefName[NB_POINTS] = { FIRST_POINT_REF_ID(), + SECOND_POINT_REF_ID(), PASSED_POINT_REF_ID() }; - int aNbInitialized = 0; - std::shared_ptr anEllipsePoints[NB_POINTS]; + // type of ellipse switched, thus reset all attributes + if (theID == ELLIPSE_TYPE()) { + for (int aPntIndex = 0; aPntIndex < NB_POINTS; ++aPntIndex) { + SketchPlugin_Tools::resetAttribute(this, aPointAttrName[aPntIndex]); + SketchPlugin_Tools::resetAttribute(this, aPointRefName[aPntIndex]); + } + } + else { + 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; + GeomShapePtr aTangentCurve; + SketchPlugin_Tools::convertRefAttrToPointOrTangentCurve( + aPointRef, aPointAttr, aTangentCurve, aPassedPoint); - for (int aPntIndex = 0; aPntIndex < NB_POINTS; ++aPntIndex) { - AttributePtr aPointAttr = attribute(aPointAttrName[aPntIndex]); - if (!aPointAttr->isInitialized()) - continue; + anEllipsePoints[aNbInitialized++] = aPassedPoint; + } - AttributeRefAttrPtr aPointRef = refattr(aPointRefName[aPntIndex]); - // calculate ellipse parameters - std::shared_ptr aPassedPoint; - std::shared_ptr aTangentCurve; - SketchPlugin_Tools::convertRefAttrToPointOrTangentCurve( - aPointRef, aPointAttr, aTangentCurve, aPassedPoint); + if (aNbInitialized <= 1) + return; // too few points for the ellipse - anEllipsePoints[aNbInitialized++] = aPassedPoint; - } + if (string(ELLIPSE_TYPE())->value() == ELLIPSE_TYPE_BY_AXIS_AND_POINT()) { + // ellipse is given by major axis and passing point, + // recalculate the first point to be a center + anEllipsePoints[0]->setX(0.5 * (anEllipsePoints[0]->x() + anEllipsePoints[1]->x())); + anEllipsePoints[0]->setY(0.5 * (anEllipsePoints[0]->y() + anEllipsePoints[1]->y())); + } - std::shared_ptr anEllipse; - if (aNbInitialized == 2) { - std::shared_ptr 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( + 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; + if (!anEllipse || anEllipse->implPtr() == 0) + return; - myCenter = anEllipse->center(); - myFocus = anEllipse->firstFocus(); - myMajorRadius = anEllipse->majorRadius(); - myMinorRadius = anEllipse->minorRadius(); + myCenter = anEllipse->center(); + myFocus = anEllipse->firstFocus(); + myMajorRadius = anEllipse->majorRadius(); + myMinorRadius = anEllipse->minorRadius(); - AttributeDoublePtr aMajorRadiusAttr = real(MAJOR_RADIUS_ID()); - AttributeDoublePtr aMinorRadiusAttr = real(MINOR_RADIUS_ID()); + AttributeDoublePtr aMajorRadiusAttr = real(MAJOR_RADIUS_ID()); + AttributeDoublePtr aMinorRadiusAttr = real(MINOR_RADIUS_ID()); - bool aWasBlocked = data()->blockSendAttributeUpdated(true); - // center attribute is used in processEvent() to set reference to reentrant arc - std::dynamic_pointer_cast(attribute(CENTER_POINT_ID()))->setValue(myCenter); - aMajorRadiusAttr->setValue(myMajorRadius); - aMinorRadiusAttr->setValue(myMinorRadius); - data()->blockSendAttributeUpdated(aWasBlocked, false); + bool aWasBlocked = data()->blockSendAttributeUpdated(true); + // center attribute is used in processEvent() to set reference to reentrant arc +//// std::dynamic_pointer_cast(attribute(FIRST_POINT_ID())) +//// ->setValue(myCenter); + aMajorRadiusAttr->setValue(myMajorRadius); + aMinorRadiusAttr->setValue(myMinorRadius); + data()->blockSendAttributeUpdated(aWasBlocked, false); + } } +// LCOV_EXCL_START std::string SketchPlugin_MacroEllipse::processEvent( const std::shared_ptr& theMessage) { std::string aFilledAttributeName; - ReentrantMessagePtr aReentrantMessage = - std::dynamic_pointer_cast(theMessage); + std::shared_ptr aReentrantMessage = + std::dynamic_pointer_cast(theMessage); if (aReentrantMessage) { FeaturePtr aCreatedFeature = aReentrantMessage->createdFeature(); + std::string anEllipseType = aReentrantMessage->typeOfCreation(); + + string(ELLIPSE_TYPE())->setValue(anEllipseType); + + aFilledAttributeName = ELLIPSE_TYPE(); ObjectPtr anObject = aReentrantMessage->selectedObject(); AttributePtr anAttribute = aReentrantMessage->selectedAttribute(); std::shared_ptr aClickedPoint = aReentrantMessage->clickedPoint(); if (aClickedPoint && (anObject || anAttribute)) { - aFilledAttributeName = CENTER_POINT_ID(); - std::string aReferenceAttributeName = CENTER_POINT_REF_ID(); + aFilledAttributeName = FIRST_POINT_ID(); + std::string aReferenceAttributeName = FIRST_POINT_REF_ID(); // fill 2d point attribute AttributePoint2DPtr aPointAttr = @@ -171,37 +207,64 @@ std::string SketchPlugin_MacroEllipse::processEvent( std::dynamic_pointer_cast(attribute(aReferenceAttributeName)); if (anAttribute) { if (!anAttribute->owner() || !anAttribute->owner()->data()->isValid()) { - if (aCreatedFeature && anAttribute->id() == CENTER_POINT_ID()) - anAttribute = aCreatedFeature->attribute(SketchPlugin_Ellipse::CENTER_ID()); + if (aCreatedFeature && anAttribute->id() == FIRST_POINT_ID()) + anAttribute = aCreatedFeature->attribute( + anEllipseType == ELLIPSE_TYPE_BY_CENTER_AXIS_POINT() ? + SketchPlugin_Ellipse::CENTER_ID() : + SketchPlugin_Ellipse::MAJOR_AXIS_START_ID()); } aRefAttr->setAttr(anAttribute); } else if (anObject.get()) { - // if presentation of previous reentrant macro arc is used, the object is invalid, - // we should use result of previous feature of the message(Arc) - if (!anObject->data()->isValid()) - anObject = aCreatedFeature->lastResult(); - aRefAttr->setObject(anObject); + // 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 = ELLIPSE_TYPE(); } } Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED)); } return aFilledAttributeName; } +// LCOV_EXCL_STOP -void SketchPlugin_MacroEllipse::constraintsForEllipse(FeaturePtr theEllipseFeature) +void SketchPlugin_MacroEllipse::constraintsForEllipseByCenterAxisAndPassed( + FeaturePtr theEllipseFeature) { + // tangency on-the-fly is not applicable for ellipses + static const bool isTangencyApplicable = false; // Create constraints. SketchPlugin_Tools::createCoincidenceOrTangency( - this, CENTER_POINT_REF_ID(), + this, FIRST_POINT_REF_ID(), theEllipseFeature->attribute(SketchPlugin_Ellipse::CENTER_ID()), - ObjectPtr(), false); + ObjectPtr(), isTangencyApplicable); + SketchPlugin_Tools::createCoincidenceOrTangency( + this, SECOND_POINT_REF_ID(), + theEllipseFeature->attribute(SketchPlugin_Ellipse::MAJOR_AXIS_END_ID()), + ObjectPtr(), isTangencyApplicable); + SketchPlugin_Tools::createCoincidenceOrTangency( + this, PASSED_POINT_REF_ID(), AttributePtr(), + theEllipseFeature->lastResult(), isTangencyApplicable); +} + +void SketchPlugin_MacroEllipse::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, MAJOR_AXIS_POINT_REF_ID(), AttributePtr(), - theEllipseFeature->lastResult(), true); + this, SECOND_POINT_REF_ID(), + theEllipseFeature->attribute(SketchPlugin_Ellipse::MAJOR_AXIS_END_ID()), + ObjectPtr(), isTangencyApplicable); SketchPlugin_Tools::createCoincidenceOrTangency( this, PASSED_POINT_REF_ID(), AttributePtr(), - theEllipseFeature->lastResult(), true); + theEllipseFeature->lastResult(), isTangencyApplicable); } FeaturePtr SketchPlugin_MacroEllipse::createEllipseFeature() @@ -213,7 +276,7 @@ FeaturePtr SketchPlugin_MacroEllipse::createEllipseFeature() aCenterAttr->setValue(myCenter->x(), myCenter->y()); AttributePoint2DPtr aFocusAttr = std::dynamic_pointer_cast( - aEllipseFeature->attribute(SketchPlugin_Ellipse::FOCUS_ID())); + aEllipseFeature->attribute(SketchPlugin_Ellipse::FIRST_FOCUS_ID())); aFocusAttr->setValue(myFocus->x(), myFocus->y()); aEllipseFeature->real(SketchPlugin_Ellipse::MAJOR_RADIUS_ID())->setValue(myMajorRadius); @@ -236,10 +299,10 @@ AISObjectPtr SketchPlugin_MacroEllipse::getAISObject(AISObjectPtr thePrevious) aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID())); // Compute a ellipse in 3D view. - std::shared_ptr aCenter(aSketch->to3D(myCenter->x(), myCenter->y())); - std::shared_ptr aFocus(aSketch->to3D(myFocus->x(), myFocus->y())); - std::shared_ptr aNormal = aNDir->dir(); - std::shared_ptr aMajorAxis(new GeomAPI_Dir(aFocus->x() - aCenter->x(), + GeomPointPtr aCenter(aSketch->to3D(myCenter->x(), myCenter->y())); + GeomPointPtr aFocus(aSketch->to3D(myFocus->x(), myFocus->y())); + GeomDirPtr aNormal = aNDir->dir(); + GeomDirPtr aMajorAxis(new GeomAPI_Dir(aFocus->x() - aCenter->x(), aFocus->y() - aCenter->y(), aFocus->z() - aCenter->z())); std::shared_ptr anEllipseShape = diff --git a/src/SketchPlugin/SketchPlugin_MacroEllipse.h b/src/SketchPlugin/SketchPlugin_MacroEllipse.h index 8d374df5c..5b7d2945a 100644 --- a/src/SketchPlugin/SketchPlugin_MacroEllipse.h +++ b/src/SketchPlugin/SketchPlugin_MacroEllipse.h @@ -17,10 +17,6 @@ // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -// File: SketchPlugin_MacroEllipse.h -// Created: 26 April 2017 -// Author: Artem ZHIDKOV - #ifndef SketchPlugin_MacroEllipse_H_ #define SketchPlugin_MacroEllipse_H_ @@ -48,35 +44,58 @@ class SketchPlugin_MacroEllipse: public SketchPlugin_SketchEntity, return ID; } - /// 2D point - center of the ellipse. - inline static const std::string& CENTER_POINT_ID() + static const std::string& ELLIPSE_TYPE() + { + static const std::string ID("ellipse_type"); + return ID; + } + + static const std::string& ELLIPSE_TYPE_BY_CENTER_AXIS_POINT() + { + static const std::string ID("by_center_axis_point"); + return ID; + } + static const std::string& ELLIPSE_TYPE_BY_AXIS_AND_POINT() + { + static const std::string ID("by_major_axis_and_point"); + return ID; + } + + static const std::string& EDIT_ELLIPSE_TYPE() + { + static const std::string ID("edit_ellipse_type"); + return ID; + } + + /// Attribute for the first point selected during ellipse creation. + inline static const std::string& FIRST_POINT_ID() { - static const std::string ID("center_point"); + static const std::string ID("first_point"); return ID; } - /// Reference for center point selection. - inline static const std::string& CENTER_POINT_REF_ID() + /// Reference to the first selected point. + inline static const std::string& FIRST_POINT_REF_ID() { - static const std::string ID("center_point_ref"); + static const std::string ID("first_point_ref"); return ID; } - /// 2D point - major axis point of the ellipse. - inline static const std::string& MAJOR_AXIS_POINT_ID() + /// Attribute for the second point selected during ellipse creation. + inline static const std::string& SECOND_POINT_ID() { - static const std::string ID("major_axis_point"); + static const std::string ID("second_point"); return ID; } - /// Reference for major axis point selection. - inline static const std::string& MAJOR_AXIS_POINT_REF_ID() + /// Reference to the second selected point. + inline static const std::string& SECOND_POINT_REF_ID() { - static const std::string ID("major_axis_point_ref"); + static const std::string ID("second_point_ref"); return ID; } - /// 2D point - passed point of the ellipse + /// Attribute for the third point selected during ellipse creation. inline static const std::string& PASSED_POINT_ID() { static const std::string ID("passed_point"); @@ -93,14 +112,14 @@ class SketchPlugin_MacroEllipse: public SketchPlugin_SketchEntity, /// Major radius of the ellipse inline static const std::string& MAJOR_RADIUS_ID() { - static const std::string ID("ellipse_major_radius"); + 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("ellipse_minor_radius"); + static const std::string ID("minor_radius"); return ID; } @@ -139,7 +158,8 @@ class SketchPlugin_MacroEllipse: public SketchPlugin_SketchEntity, SketchPlugin_MacroEllipse(); private: - void constraintsForEllipse(FeaturePtr theEllipseFeature); + void constraintsForEllipseByCenterAxisAndPassed(FeaturePtr theEllipseFeature); + void constraintsForEllipseByMajoxAxisAndPassed(FeaturePtr theEllipseFeature); FeaturePtr createEllipseFeature(); diff --git a/src/SketchPlugin/SketchPlugin_Plugin.cpp b/src/SketchPlugin/SketchPlugin_Plugin.cpp index 67d4e4656..3958b491c 100644 --- a/src/SketchPlugin/SketchPlugin_Plugin.cpp +++ b/src/SketchPlugin/SketchPlugin_Plugin.cpp @@ -317,6 +317,7 @@ std::shared_ptr SketchPlugin_Plugin aMsg->setState(SketchPlugin_Trim::ID(), aHasSketchPlane); aMsg->setState(SketchPlugin_MacroArc::ID(), aHasSketchPlane); aMsg->setState(SketchPlugin_MacroCircle::ID(), aHasSketchPlane); + aMsg->setState(SketchPlugin_MacroEllipse::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_Sketch.cpp b/src/SketchPlugin/SketchPlugin_Sketch.cpp index 0daeb330d..9c247446c 100644 --- a/src/SketchPlugin/SketchPlugin_Sketch.cpp +++ b/src/SketchPlugin/SketchPlugin_Sketch.cpp @@ -377,6 +377,35 @@ void SketchPlugin_Sketch::createPoint2DResult(ModelAPI_Feature* theFeature, theFeature->setResult(aResult, theIndex); } +void SketchPlugin_Sketch::createLine2DResult(ModelAPI_Feature* theFeature, + SketchPlugin_Sketch* theSketch, + const std::string& theStartAttrID, + const std::string& theEndAttrID, + const int theIndex) +{ + std::shared_ptr aStartAttr = + std::dynamic_pointer_cast(theFeature->attribute(theStartAttrID)); + std::shared_ptr anEndAttr = + std::dynamic_pointer_cast(theFeature->attribute(theEndAttrID)); + + if (!aStartAttr || !aStartAttr->isInitialized() || + !anEndAttr || !anEndAttr->isInitialized()) + return; + + std::shared_ptr aStart(theSketch->to3D(aStartAttr->x(), aStartAttr->y())); + std::shared_ptr anEnd(theSketch->to3D(anEndAttr->x(), anEndAttr->y())); + //std::cout<<"Execute line "<x()<<" "<y()<<" "<z()<<" - " + // <x()<<" "<y()<<" "<z()< anEdge = GeomAlgoAPI_EdgeBuilder::line(aStart, anEnd); + // store the result + std::shared_ptr aResult = + theFeature->document()->createConstruction(theFeature->data(), theIndex); + aResult->setShape(anEdge); + aResult->setIsInHistory(false); + theFeature->setResult(aResult, theIndex); +} + FeaturePtr SketchPlugin_Sketch::addUniqueNamedCopiedFeature(FeaturePtr theFeature, SketchPlugin_Sketch* theSketch, const bool theIsCopy) diff --git a/src/SketchPlugin/SketchPlugin_Sketch.h b/src/SketchPlugin/SketchPlugin_Sketch.h index 124ff670c..7f63c5bb2 100644 --- a/src/SketchPlugin/SketchPlugin_Sketch.h +++ b/src/SketchPlugin/SketchPlugin_Sketch.h @@ -230,6 +230,18 @@ class SketchPlugin_Sketch : public ModelAPI_CompositeFeature, public GeomAPI_ICu SketchPlugin_Sketch* theSketch, const std::string& theAttributeID, const int theIndex); + /// \brief Create a result for the segment given by a pair of attributes + /// \param theFeature a source feature + /// \param theSketch a sketch intance + /// \param theStartAttrID an attribute string + /// \param theEndAttrID an attribute string + /// \param theIndex an index of the result + static void createLine2DResult(ModelAPI_Feature* theFeature, + SketchPlugin_Sketch* theSketch, + const std::string& theStartAttrID, + const std::string& theEndAttrID, + const int theIndex = 0); + /// Add new feature and fill the data of the feature by the data of the parameter feature. /// The name of the created feature stays unique. /// \param theFeature a source feature diff --git a/src/SketchPlugin/SketchPlugin_SketchEntity.h b/src/SketchPlugin/SketchPlugin_SketchEntity.h index c207dd72b..1a736ad58 100644 --- a/src/SketchPlugin/SketchPlugin_SketchEntity.h +++ b/src/SketchPlugin/SketchPlugin_SketchEntity.h @@ -112,6 +112,10 @@ class SketchPlugin_SketchEntity : public SketchPlugin_Feature, public GeomAPI_IC } // LCOV_EXCL_START + /// Returns \c true if the result is marked as auxiliary + virtual bool isAuxiliary(ResultPtr theResult) + { return false; } + /// Customize presentation of the feature virtual bool customisePresentation(ResultPtr theResult, AISObjectPtr thePrs, std::shared_ptr theDefaultPrs) @@ -142,7 +146,8 @@ class SketchPlugin_SketchEntity : public SketchPlugin_Feature, public GeomAPI_IC std::vector aColor; std::shared_ptr anAuxiliaryAttr = data()->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID()); - bool isConstruction = anAuxiliaryAttr.get() != NULL && anAuxiliaryAttr->value(); + bool isConstruction = (anAuxiliaryAttr.get() != NULL && anAuxiliaryAttr->value()) + || isAuxiliary(theResult); if (isConstruction) { aColor = Config_PropManager::color("Visualization", "sketch_auxiliary_color"); } diff --git a/src/SketchPlugin/icons/ellipse.png b/src/SketchPlugin/icons/ellipse.png index 6f311635df843c220850f9dc54ac7459bf1c15db..e94e6c8317561df57a7fbae1bbeee6d1d4bc6f4b 100644 GIT binary patch delta 645 zcmV;00($+*1m^{iZGQq}NklDR6vsdB*L0W#mbtkyC?Yx}K?G4Efw~zL zsM~5?f)WqiLMl2)WM2A1kQouwA&-IKrb1=gbcdn{It0}viMo`|RW8Cb=YFq)IOfuK zd+@#=cptu^s;o4X2Lsh=H3$R&7m!vM7nP1=Jp2kkmIG8YHh*t4YI=c2;IF`lRmKF$ z5o&-fpgqahz}f!*E^o_G5xKWO=R$VY_N877{?5S<1U<%S-vTbg)Gh&3`uyz*-Jru( zv@I1K{FV=|@&?K?qA?MMRXGJD967Qtc*MX>gxAUFz@fsoJcmOSR)_=PiD;zD<@1*a zoG<{M`lg)*`+rd24N95Y7q}rJvKV%Io85MPJ|XC%WGvDJAR;BePf=CeK7RyspD8Nd z<*;PuvU5X%{8D5dbO-1f#oU>Ug|FqHzQ7>Za)-OYzYRl^3LWE5`ceQ}>sr0jj`T-C zs{jF+b51*Y7Q^f6{AI-s>P2{9WR;!){$w%><^et@dVgm{7|T;&taG+>aVaX&)4*!Y z%59^{9+1(gL?oRrO|4!AO#*W$SHC8PzAwrYr5zYbjzm5gkP3wHLhF<9f#;L8yEoYx zyCE5mTmq;Lg^Fz^69y?Y+3ZCC2e4jMX9@uT+SzI8Bv+zTI&&YWv6!ahXygNc0ipuO zt3#pU<$fTrP;Ixb1c45w1<@vK5kZT%(6_sZtHNfPX2>;B8^5VF1Iph-uu( zv$WO42Ch%-K^Zv1kp%9W+K{%f;zIa*O`aVu~YIJ*{)wJ)# z#6U+s*-qF3Y3Z1@WaF5^l8T*3#9ZXd=GT*X67BIm4 diff --git a/src/SketchPlugin/icons/ellipse_axes_32x32.png b/src/SketchPlugin/icons/ellipse_axes_32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..a1a83d59769b57ea745eeb1df14d12603f828a12 GIT binary patch literal 1295 zcmV+q1@QWbP)O-NrVBe0 zKlY_bnt~FFM1dGo;E%B)2qY1)sD$i?`D4t@Z6VHSqfA_pZGIF*qe!!z&2Le+osZ}4 z$Jy4IPTkfy_pkeXp8I~T>*0Ogmq%2U{~KOk(L;h$B34TgnF^W=Bmox$nn9ZaBz%6Q zq2l_Ty)s;ZjDo^Rs!l1&av%?o2ejPCy?Xh}%H|Vo2{u%RYRj+$G73u5)aqwIQPgl) z;TS5_82uJwZ`z>kbi^|e(HvmIa{u|6ADulJZTS|e+lC~N@nUI_qPqbv&ghF`?jNMim7F{6Mxl81VSTi^q6^Njnr>Po()|$T({*)mQ#HSoxG- z;5uLd18~c6M~)1KA`b(Gh#=y4eWml=VB+Z>co^Zm_RzJwp}>3M!@i|~?USb_dJ9Uu z1HS^1jles%9cS#e$BF=2Z=;nP>H zOaNH}V8k{WfMA!q9vBClX+K*Mh5oOrW)W&aAJDl$RS(-3*{{-aUXQTOusk zp=D*(q#yrjDeySZmX_k#7f*P)ufzw;0IqnFLVEy=Rg)i?*1cydDgyBoKzS2DRX*wc zts99LAtKH3WM>oSHLH(|y%Q_k>Zr)kr8aSblZ6!P(Xo>|mtFUlHu*=ygDlY?_#!AtJhU)VJ z)f!d(8bDN*!~&jCP@Eg;bXr7t6|f5H+KyKLaIbn}U8i<@AaHwY>o440bL-SsQ#u#s+4f`#ltoK3TQn literal 0 HcmV?d00001 diff --git a/src/SketchPlugin/icons/ellipse_cent_rad_32x32.png b/src/SketchPlugin/icons/ellipse_cent_rad_32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..5781d8c2db59a4f75da86f04e2773faeae2c42e7 GIT binary patch literal 1335 zcmV-71<3k|P)A;0=L=S;I9i6tV$c~tGH^+t9kgu( z_m@{&Yp>m0E7LWQSy;4C)ha_N2l4@#qU4{vzAIlHYCqNGc7jc)c1+7aW?@-|I{F1r z95o$M_zsl@jDCx8t~&u|&=S`IM00`d<^GGyKRJIo+U1+5*2HBX^ZBx3MfU;ez%Xz` zg~M(~n*KUke`T`Tes@ym>|o#lqly9oejwY91w3c%+S#r^@*YJi2p69Y8f)v{&4+%8 z)qHATqVl0Y?L=o_9g$CJ^u!+MXzQR|69NY? zYMoFV9C-4UGjMEfR;weTjtI_w({+i0hb27#0?FeHNOiT@lKVu>YY(lE&Y39z73l;j zQ9YYTe9##lj)c}Y1D@~O-v=!^G%x%5%KU=IEyr1e>gS1s1K74JEgb2{n1S>)MA;c;$sVn$a*XHXPwRmPfv${H z*TES3)B%^H#+QlVuJCwEy}(l7sw+9TAHa6h6ohX)J#fCZb|fae>M$ZX#Cr&pH^Sxe z+32-yOV|-2(jF5$+62V<#Ktj)Q z5g0U%6klp>xHwU+QPpn%L}gtf;F*ObdBH)eLzGtlM`2snv4$USmv0=~@&Px1m7dk5 zCDR2ft~^|UtBPF81nkJNPu@H z4u5lfPpt591|a<14%pXrfmQ-3Q`9QZhEOLGs`oehevbz{p@C7Qu3w*)JZx_R$yZno tWC24UgQ)(hM(UMNLvKstjK^&#I!AYrKY3^}Jq{Q1OJ#dzD z&ilOQ9GMwOv3G22r}wMptYl{pS&SZor=G>PR+pEm?KyP(I5yX?tx9oX@9M}SpNgq6Bc%D zqwx|LkW-;nUVN5xS}=0zAkuqa9w_?lMvBI5gMB9NSX6%aA@MN)(lx+d^rg71DgSqIX>Ahzwr^%O6=Li)b{4P#t(N$rdNOiegapcO6gMK2KDOw znzQ&MVz-M~S^w^>$@Ch~zt*Sa!0Pf+wVpdXXtEO~6_8B;H-I(ZIdF3`z;9n9rt1E8 Rf!_cC002ovPDHLkV1g+r{uBTJ literal 0 HcmV?d00001 diff --git a/src/SketchPlugin/icons/radius_major.png b/src/SketchPlugin/icons/radius_major.png new file mode 100644 index 0000000000000000000000000000000000000000..ef86a077cc85e86c442c6ff79a9006fc513869e3 GIT binary patch literal 387 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4JY;jWZ-sC^?=M>NT-XgKsCh&yo|5k^>Pl0~3x^Enmnzp&+xK4iI zyl>V1$!bR=rcQpQ)3>2lI_8mLbBdGpjU!fi8|HtjUcWFTTjzn4{te&Xdk==|PM@5{ znm)sMZ-XA&jURmLu0%!e;4++(;ltNFkHWAJqKb6Mw<&;$VAo1NDH literal 0 HcmV?d00001 diff --git a/src/SketchPlugin/icons/radius_minor.png b/src/SketchPlugin/icons/radius_minor.png new file mode 100644 index 0000000000000000000000000000000000000000..3be332a86175f25eec6db5a0c7f2a1743d816a2c GIT binary patch literal 426 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4tN zy46)tu2Ev! - + + + + + - - - - - + + + + + + + + + + + + + + - - - diff --git a/src/SketchSolver/PlaneGCSSolver/CMakeLists.txt b/src/SketchSolver/PlaneGCSSolver/CMakeLists.txt index af72c4b13..fab1f0356 100644 --- a/src/SketchSolver/PlaneGCSSolver/CMakeLists.txt +++ b/src/SketchSolver/PlaneGCSSolver/CMakeLists.txt @@ -25,7 +25,7 @@ SET(PLANEGCSSOLVER_HEADERS PlaneGCSSolver_Storage.h PlaneGCSSolver_ConstraintWrapper.h PlaneGCSSolver_EdgeWrapper.h - PlaneGCSSolver_EdgeWrapper.h + PlaneGCSSolver_EntityWrapper.h PlaneGCSSolver_PointWrapper.h PlaneGCSSolver_ScalarWrapper.h PlaneGCSSolver_AngleWrapper.h diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Defs.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Defs.h index e4851a295..e63fa6b91 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Defs.h +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Defs.h @@ -50,7 +50,9 @@ enum SketchSolver_EntityType { ENTITY_POINT, ENTITY_LINE, ENTITY_CIRCLE, - ENTITY_ARC + ENTITY_ARC, + ENTITY_ELLIPSE, + ENTITY_ELLIPTICAL_ARC }; /// Types of constraints diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EdgeWrapper.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EdgeWrapper.cpp index 7ec36cf23..bb8af7873 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EdgeWrapper.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EdgeWrapper.cpp @@ -31,6 +31,11 @@ PlaneGCSSolver_EdgeWrapper::PlaneGCSSolver_EdgeWrapper(const GCSCurvePtr theEnti 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; + } } } } @@ -62,5 +67,9 @@ bool PlaneGCSSolver_EdgeWrapper::isDegenerated() const return aSqRadius < aSqTol || aSqRadius > aMaxRadius * aMaxRadius || // <- arc radius anAngleDiff < anAngleTol || fabs(anAngleDiff - 2*PI) < anAngleTol; // <- arc angle } + else if (myType == ENTITY_ELLIPSE) { + std::shared_ptr anEllipse = std::dynamic_pointer_cast(myEntity); + return *anEllipse->radmin < tolerance; + } return false; } diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EntityWrapper.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EntityWrapper.h index 0d224cbdb..5eceaf63c 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EntityWrapper.h +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EntityWrapper.h @@ -28,6 +28,9 @@ #include #include +class PlaneGCSSolver_EntityWrapper; +typedef std::shared_ptr EntityWrapperPtr; + /** * Wrapper providing operations with entities regardless the solver. */ @@ -45,10 +48,16 @@ public: /// \brief Return the External flag bool isExternal() const { return myExternal; } + /// \brief Store names of attributes and their values if necessary + void setAdditionalAttributes(const std::map& theAttribues) + { myAdditionalAttributes = theAttribues; } + /// \brief Return the list of additional attributes + const std::map& additionalAttributes() const + { return myAdditionalAttributes; } + private: bool myExternal; + std::map myAdditionalAttributes; }; -typedef std::shared_ptr EntityWrapperPtr; - #endif diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_FeatureBuilder.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_FeatureBuilder.cpp index d491a0049..4755eb6bf 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_FeatureBuilder.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_FeatureBuilder.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -40,6 +41,7 @@ static EntityWrapperPtr createLine(const AttributeEntityMap& theAttributes); static EntityWrapperPtr createCircle(const AttributeEntityMap& theAttributes); static EntityWrapperPtr createArc(const AttributeEntityMap& theAttributes, PlaneGCSSolver_Storage* theStorage); +static EntityWrapperPtr createEllipse(const AttributeEntityMap& theAttributes); PlaneGCSSolver_FeatureBuilder::PlaneGCSSolver_FeatureBuilder( @@ -90,6 +92,9 @@ EntityWrapperPtr PlaneGCSSolver_FeatureBuilder::createFeature(FeaturePtr theFeat // Arc else if (aFeatureKind == SketchPlugin_Arc::ID()) aResult = createArc(myAttributes, myStorage); + // Ellipse + else if (aFeatureKind == SketchPlugin_Ellipse::ID()) + aResult = createEllipse(myAttributes); // 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()) { @@ -210,6 +215,38 @@ EntityWrapperPtr createArc(const AttributeEntityMap& theAttributes, return anArcWrapper; } +EntityWrapperPtr createEllipse(const AttributeEntityMap& theAttributes) +{ + std::shared_ptr aNewEllipse(new GCS::Ellipse); + + 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_Ellipse::CENTER_ID()) + aNewEllipse->center = *(aPoint->point()); + else if (anIt->first->id() == SketchPlugin_Ellipse::FIRST_FOCUS_ID()) + aNewEllipse->focus1 = *(aPoint->point()); + else + anAdditionalAttributes[anIt->first->id()] = anIt->second; + } + else if (anIt->first->id() == SketchPlugin_Ellipse::MINOR_RADIUS_ID()) { + ScalarWrapperPtr aScalar = + std::dynamic_pointer_cast(anIt->second); + aNewEllipse->radmin = aScalar->scalar(); + } + else + anAdditionalAttributes[anIt->first->id()] = anIt->second; + } + + EntityWrapperPtr anEllipseWrapper(new PlaneGCSSolver_EdgeWrapper(aNewEllipse)); + anEllipseWrapper->setAdditionalAttributes(anAdditionalAttributes); + return anEllipseWrapper; +} + bool isAttributeApplicable(const std::string& theAttrName, const std::string& theOwnerName) { if (theOwnerName == SketchPlugin_Arc::ID()) { @@ -226,6 +263,17 @@ bool isAttributeApplicable(const std::string& theAttrName, const std::string& th return theAttrName == SketchPlugin_Line::START_ID() || theAttrName == SketchPlugin_Line::END_ID(); } + else if (theOwnerName == SketchPlugin_Ellipse::ID()) { + return theAttrName == SketchPlugin_Ellipse::CENTER_ID() || + theAttrName == SketchPlugin_Ellipse::FIRST_FOCUS_ID() || + theAttrName == SketchPlugin_Ellipse::SECOND_FOCUS_ID() || + theAttrName == SketchPlugin_Ellipse::MAJOR_AXIS_START_ID() || + theAttrName == SketchPlugin_Ellipse::MAJOR_AXIS_END_ID() || + theAttrName == SketchPlugin_Ellipse::MINOR_AXIS_START_ID() || + theAttrName == SketchPlugin_Ellipse::MINOR_AXIS_END_ID() || + theAttrName == SketchPlugin_Ellipse::MAJOR_RADIUS_ID() || + theAttrName == SketchPlugin_Ellipse::MINOR_RADIUS_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 5c8cebe53..ba86322fd 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -195,7 +196,7 @@ bool PlaneGCSSolver_Storage::update(FeaturePtr theFeature, bool theForce) // (do not want to add several copies of it while adding attributes) aRelated = createFeature(theFeature, &aBuilder); myFeatureMap[theFeature] = aRelated; - createArcConstraints(aRelated); + createAuxiliaryConstraints(aRelated); isUpdated = true; } @@ -265,7 +266,7 @@ void PlaneGCSSolver_Storage::makeExternal(const EntityWrapperPtr& theEntity) if (theEntity->isExternal()) return; - removeArcConstraints(theEntity); + removeAuxiliaryConstraints(theEntity); GCS::SET_pD aParameters = PlaneGCSSolver_Tools::parameters(theEntity); mySketchSolver->removeParameters(aParameters); @@ -282,17 +283,17 @@ void PlaneGCSSolver_Storage::makeNonExternal(const EntityWrapperPtr& theEntity) mySketchSolver->addParameters(aParameters); theEntity->setExternal(false); - createArcConstraints(theEntity); + createAuxiliaryConstraints(theEntity); myNeedToResolve = true; } -void PlaneGCSSolver_Storage::createArcConstraints(const EntityWrapperPtr& theArc) +static void createArcConstraints(const EntityWrapperPtr& theArc, + const SolverPtr& theSolver, + const ConstraintID theConstraintID, + std::map& theConstraints) { - if (!theArc || theArc->type() != ENTITY_ARC || theArc->isExternal()) - return; - EdgeWrapperPtr anEdge = std::dynamic_pointer_cast(theArc); std::shared_ptr anArc = std::dynamic_pointer_cast(anEdge->entity()); @@ -300,39 +301,110 @@ void PlaneGCSSolver_Storage::createArcConstraints(const EntityWrapperPtr& theArc std::list anArcConstraints; // constrain the start point on the arc anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintCurveValue( - anArc->start, anArc->start.x, *anArc, anArc->startAngle))); + anArc->start, anArc->start.x, *anArc, anArc->startAngle))); anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintCurveValue( - anArc->start, anArc->start.y, *anArc, anArc->startAngle))); + anArc->start, anArc->start.y, *anArc, anArc->startAngle))); // constrain the end point on the arc anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintCurveValue( - anArc->end, anArc->end.x, *anArc, anArc->endAngle))); + anArc->end, anArc->end.x, *anArc, anArc->endAngle))); anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintCurveValue( - anArc->end, anArc->end.y, *anArc, anArc->endAngle))); + anArc->end, anArc->end.y, *anArc, anArc->endAngle))); + + ConstraintWrapperPtr aWrapper( + new PlaneGCSSolver_ConstraintWrapper(anArcConstraints, CONSTRAINT_UNKNOWN)); + aWrapper->setId(theConstraintID); + constraintsToSolver(aWrapper, theSolver); + + theConstraints[theArc] = aWrapper; +} + +static void createEllipseConstraints( + const EntityWrapperPtr& theEllipse, + const SolverPtr& theSolver, + const ConstraintID theConstraintID, + std::map& theConstraints) +{ + EdgeWrapperPtr anEdge = std::dynamic_pointer_cast(theEllipse); + std::shared_ptr anEllipse = + std::dynamic_pointer_cast(anEdge->entity()); + + // Additional constaints to fix ellipse's extra points + std::list anEllipseConstraints; + + const std::map& anAttributes = theEllipse->additionalAttributes(); + for (std::map::const_iterator anIt = anAttributes.begin(); + anIt != anAttributes.end(); ++anIt) { + std::shared_ptr aPoint = + std::dynamic_pointer_cast(anIt->second); + if (!aPoint) + continue; + + GCS::InternalAlignmentType anAlignmentX, anAlignmentY; + if (anIt->first == SketchPlugin_Ellipse::SECOND_FOCUS_ID()) + anAlignmentX = GCS::EllipseFocus2X; + else if (anIt->first == SketchPlugin_Ellipse::MAJOR_AXIS_START_ID()) + anAlignmentX = GCS::EllipseNegativeMajorX; + else if (anIt->first == SketchPlugin_Ellipse::MAJOR_AXIS_END_ID()) + anAlignmentX = GCS::EllipsePositiveMajorX; + else if (anIt->first == SketchPlugin_Ellipse::MINOR_AXIS_START_ID()) + anAlignmentX = GCS::EllipseNegativeMinorX; + else if (anIt->first == SketchPlugin_Ellipse::MINOR_AXIS_END_ID()) + anAlignmentX = GCS::EllipsePositiveMinorX; + + anEllipseConstraints.push_back(GCSConstraintPtr( + new GCS::ConstraintInternalAlignmentPoint2Ellipse(*anEllipse, *(aPoint->point()), anAlignmentX))); + anAlignmentY = (GCS::InternalAlignmentType)((int)anAlignmentX + 1); + anEllipseConstraints.push_back(GCSConstraintPtr( + new GCS::ConstraintInternalAlignmentPoint2Ellipse(*anEllipse, *(aPoint->point()), anAlignmentY))); + } + + // constraint to bind the major radius value + std::shared_ptr aMajorAxisStart = + std::dynamic_pointer_cast( + anAttributes.at(SketchPlugin_Ellipse::MAJOR_AXIS_START_ID())); + ScalarWrapperPtr aMajorRadius = + std::dynamic_pointer_cast( + anAttributes.at(SketchPlugin_Ellipse::MAJOR_RADIUS_ID())); + anEllipseConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance( + anEllipse->center, *(aMajorAxisStart->point()), aMajorRadius->scalar()))); ConstraintWrapperPtr aWrapper( - new PlaneGCSSolver_ConstraintWrapper(anArcConstraints, CONSTRAINT_UNKNOWN)); - aWrapper->setId(++myConstraintLastID); - constraintsToSolver(aWrapper, mySketchSolver); + new PlaneGCSSolver_ConstraintWrapper(anEllipseConstraints, CONSTRAINT_UNKNOWN)); + aWrapper->setId(theConstraintID); + constraintsToSolver(aWrapper, theSolver); - myArcConstraintMap[theArc] = aWrapper; + theConstraints[theEllipse] = aWrapper; } -void PlaneGCSSolver_Storage::removeArcConstraints(const EntityWrapperPtr& theArc) +void PlaneGCSSolver_Storage::createAuxiliaryConstraints(const EntityWrapperPtr& theEntity) +{ + if (!theEntity || theEntity->isExternal()) + return; + + if (theEntity->type() == ENTITY_ARC) + createArcConstraints(theEntity, mySketchSolver, ++myConstraintLastID, myAuxConstraintMap); + else if (theEntity->type() == ENTITY_ELLIPSE) + createEllipseConstraints(theEntity, mySketchSolver, ++myConstraintLastID, myAuxConstraintMap); +} + +void PlaneGCSSolver_Storage::removeAuxiliaryConstraints(const EntityWrapperPtr& theEntity) { std::map::iterator - aFound = myArcConstraintMap.find(theArc); - if (aFound != myArcConstraintMap.end()) { + aFound = myAuxConstraintMap.find(theEntity); + if (aFound != myAuxConstraintMap.end()) { mySketchSolver->removeConstraint(aFound->second->id()); - myArcConstraintMap.erase(aFound); + myAuxConstraintMap.erase(aFound); } } void PlaneGCSSolver_Storage::adjustParametrizationOfArcs() { - std::map::iterator anIt = myArcConstraintMap.begin(); - for (; anIt != myArcConstraintMap.end(); ++anIt) { + 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; @@ -417,7 +489,7 @@ void PlaneGCSSolver_Storage::removeInvalidEntities() aDestroyer.remove(aFIter->second); // remove invalid arc - removeArcConstraints(aFIter->second); + removeAuxiliaryConstraints(aFIter->second); } std::list::const_iterator anInvFIt = anInvalidFeatures.begin(); for (; anInvFIt != anInvalidFeatures.end(); ++anInvFIt) diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.h index 107e4205d..cfa195c5c 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.h +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.h @@ -88,7 +88,7 @@ public: /// \brief Check the storage has constraints virtual bool isEmpty() const - { return SketchSolver_Storage::isEmpty() && myArcConstraintMap.empty(); } + { return SketchSolver_Storage::isEmpty() && myAuxConstraintMap.empty(); } /// \brief Make parametrization of arcs consistent. /// Forward arcs should have the last parameter greater than the first parameter. @@ -104,14 +104,17 @@ private: EntityWrapperPtr createAttribute(const AttributePtr& theAttribute, PlaneGCSSolver_EntityBuilder* theBuilder); - void createArcConstraints(const EntityWrapperPtr& theArc); - void removeArcConstraints(const EntityWrapperPtr& theArc); + /// \brief Create additional constaints: + /// * for arc to fix extra parameters; + /// * for ellipse to keep auxiliary points on their places + void createAuxiliaryConstraints(const EntityWrapperPtr& theEntity); + void removeAuxiliaryConstraints(const EntityWrapperPtr& theEntity); private: ConstraintID myConstraintLastID; ///< identifier of last added constraint - /// additional constraints for correct processing of the arcs - std::map myArcConstraintMap; + /// additional constraints for correct processing of the arcs, ellipses, elliptical arcs + std::map myAuxConstraintMap; /// list of removed constraints to notify solver std::list myRemovedConstraints; diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.cpp index e90def0d2..d5ff3cb3d 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.cpp @@ -114,6 +114,7 @@ static GCS::SET_pD pointParameters(const PointWrapperPtr& thePoint); 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); @@ -296,6 +297,8 @@ GCS::SET_pD PlaneGCSSolver_Tools::parameters(const EntityWrapperPtr& theEntity) return circleParameters(GCS_EDGE_WRAPPER(theEntity)); case ENTITY_ARC: return arcParameters(GCS_EDGE_WRAPPER(theEntity)); + case ENTITY_ELLIPSE: + return ellipseParameters(GCS_EDGE_WRAPPER(theEntity)); default: break; } return GCS::SET_pD(); @@ -346,6 +349,13 @@ ConstraintWrapperPtr createConstraintPointOnEntity( new GCS::ConstraintP2PDistance(*(thePoint->point()), aCirc->center, aCirc->rad)); break; } + case ENTITY_ELLIPSE: + case ENTITY_ELLIPTICAL_ARC: { + std::shared_ptr anEllipse = + std::dynamic_pointer_cast(theEntity->entity()); + aNewConstr = GCSConstraintPtr(new GCS::ConstraintPointOnEllipse(*(thePoint->point()), *anEllipse)); + break; + } default: return ConstraintWrapperPtr(); } @@ -567,7 +577,19 @@ ConstraintWrapperPtr createConstraintEqual( std::shared_ptr aCirc2 = std::dynamic_pointer_cast(theEntity2->entity()); - aConstrList.push_back(GCSConstraintPtr(new GCS::ConstraintEqual(aCirc1->rad, aCirc2->rad))); + if (aCirc1 && aCirc2) + aConstrList.push_back(GCSConstraintPtr(new GCS::ConstraintEqual(aCirc1->rad, aCirc2->rad))); + else { + std::shared_ptr anEllipse1 = + std::dynamic_pointer_cast(theEntity1->entity()); + std::shared_ptr anEllipse2 = + std::dynamic_pointer_cast(theEntity2->entity()); + + aConstrList.push_back(GCSConstraintPtr( + new GCS::ConstraintEqual(anEllipse1->radmin, anEllipse2->radmin))); + aConstrList.push_back(GCSConstraintPtr( + new GCS::ConstraintEqualMajorAxesConic(anEllipse1.get(), anEllipse2.get()))); + } } std::shared_ptr aResult( @@ -628,3 +650,16 @@ GCS::SET_pD arcParameters(const EdgeWrapperPtr& theArc) aParams.insert(anArc->rad); return aParams; } + +GCS::SET_pD ellipseParameters(const EdgeWrapperPtr& theEllipse) +{ + GCS::SET_pD aParams; + std::shared_ptr anEllipse = + std::dynamic_pointer_cast(theEllipse->entity()); + aParams.insert(anEllipse->center.x); + aParams.insert(anEllipse->center.y); + aParams.insert(anEllipse->focus1.x); + aParams.insert(anEllipse->focus1.y); + aParams.insert(anEllipse->radmin); + return aParams; +} diff --git a/src/SketchSolver/SketchSolver_ConstraintFixed.cpp b/src/SketchSolver/SketchSolver_ConstraintFixed.cpp index f61c8a49a..2cb632522 100644 --- a/src/SketchSolver/SketchSolver_ConstraintFixed.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintFixed.cpp @@ -141,6 +141,16 @@ GCS::VEC_pD toParameters(const EntityWrapperPtr& theEntity) aParameters.push_back(anArc->endAngle); break; } + case ENTITY_ELLIPSE: { + std::shared_ptr anEllipse = + std::dynamic_pointer_cast(anEntity->entity()); + aParameters.push_back(anEllipse->center.x); + aParameters.push_back(anEllipse->center.y); + aParameters.push_back(anEllipse->focus1.x); + aParameters.push_back(anEllipse->focus1.y); + aParameters.push_back(anEllipse->radmin); + break; + } default: break; } diff --git a/src/SketchSolver/SketchSolver_ConstraintMovement.cpp b/src/SketchSolver/SketchSolver_ConstraintMovement.cpp index fdc4b0e78..1c752f47d 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMovement.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintMovement.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -33,6 +34,16 @@ #include +#include + +static GCS::Point createGCSPoint(double* x, double* y) +{ + GCS::Point aPoint; + aPoint.x = x; + aPoint.y = y; + return aPoint; +} + SketchSolver_ConstraintMovement::SketchSolver_ConstraintMovement(FeaturePtr theFeature) : SketchSolver_ConstraintFixed(ConstraintPtr()), @@ -78,7 +89,8 @@ static bool isSimpleMove(FeaturePtr theMovedFeature, AttributePtr theDraggedPoin { bool isSimple = true; #ifdef CHANGE_RADIUS_WHILE_MOVE - if (theMovedFeature->getKind() == SketchPlugin_Circle::ID()) + if (theMovedFeature->getKind() == SketchPlugin_Circle::ID() || + theMovedFeature->getKind() == SketchPlugin_Ellipse::ID()) isSimple = (theDraggedPoint.get() != 0); else if (theMovedFeature->getKind() == SketchPlugin_Arc::ID()) { isSimple = (theDraggedPoint.get() != 0 && @@ -117,8 +129,14 @@ ConstraintWrapperPtr SketchSolver_ConstraintMovement::initMovement() else { if (myDraggedPoint) // start or end point of arc has been moved aConstraint = fixArcExtremity(anEntity); - else // arc or circle has been moved + else if (anEntity->type() == ENTITY_CIRCLE || anEntity->type() == ENTITY_ARC) { + // arc or circle has been moved aConstraint = fixPointOnCircle(anEntity); + } + else if (anEntity->type() == ENTITY_ELLIPSE || anEntity->type() == ENTITY_ELLIPTICAL_ARC) { + // ellipse or elliptical arc has been moved + aConstraint = fixPointOnEllipse(anEntity); + } } return aConstraint; @@ -172,9 +190,7 @@ ConstraintWrapperPtr SketchSolver_ConstraintMovement::fixPointOnCircle( myFixedValues.push_back(*aCircular->center.y); // create a moved point - GCS::Point aPointOnCircle; - aPointOnCircle.x = &myFixedValues[0]; - aPointOnCircle.y = &myFixedValues[1]; + GCS::Point aPointOnCircle = createGCSPoint(&myFixedValues[0], &myFixedValues[1]); std::list aConstraints; // point-on-circle @@ -197,6 +213,69 @@ ConstraintWrapperPtr SketchSolver_ConstraintMovement::fixPointOnCircle( new PlaneGCSSolver_ConstraintWrapper(aConstraints, getType())); } +ConstraintWrapperPtr SketchSolver_ConstraintMovement::fixPointOnEllipse( + const EntityWrapperPtr& theConic) +{ + static const double scale = 0.01; + static const int nbParams = 6; + myFixedValues.reserve(nbParams); // moved point; center and focus of ellipse + + EdgeWrapperPtr anEdge = std::dynamic_pointer_cast(theConic); + std::shared_ptr aConic = std::dynamic_pointer_cast(anEdge->entity()); + + // major axis direction + double dx = *aConic->focus1.x - *aConic->center.x; + double dy = *aConic->focus1.y - *aConic->center.y; + double norm = sqrt(dx * dx + dy* dy); + if (norm < tolerance) { + dx = 1.0; + dy = 0.0; + } + else { + dx /= norm; + dy /= norm; + } + + double aMajorRad = aConic->getRadMaj(); + + // initialize fixed values + myFixedValues.push_back(*aConic->center.x + dx * aMajorRad); + myFixedValues.push_back(*aConic->center.y + dy * aMajorRad); + myFixedValues.push_back(*aConic->center.x); + myFixedValues.push_back(*aConic->center.y); + myFixedValues.push_back(*aConic->focus1.x); + myFixedValues.push_back(*aConic->focus1.y); + + // create a moved point + GCS::Point aPointOnEllipse = createGCSPoint(&myFixedValues[0], &myFixedValues[1]); + + std::list aConstraints; + // point-on-circle + GCSConstraintPtr aNewConstraint( + new GCS::ConstraintPointOnEllipse(aPointOnEllipse, *aConic)); + aNewConstraint->rescale(scale); + aConstraints.push_back(aNewConstraint); + // fixed center (x) + aNewConstraint = GCSConstraintPtr( + new GCS::ConstraintEqual(&myFixedValues[2], aConic->center.x)); + aNewConstraint->rescale(scale); + aConstraints.push_back(aNewConstraint); + // fixed center (y) + aNewConstraint = GCSConstraintPtr( + new GCS::ConstraintEqual(&myFixedValues[3], aConic->center.y)); + aNewConstraint->rescale(scale); + aConstraints.push_back(aNewConstraint); + // focus on the major axis + GCS::Point aStartPoint = createGCSPoint(&myFixedValues[2], &myFixedValues[3]); + GCS::Point aEndPoint = createGCSPoint(&myFixedValues[4], &myFixedValues[5]); + aNewConstraint = GCSConstraintPtr( + new GCS::ConstraintPointOnLine(aConic->focus1, aStartPoint, aEndPoint)); + aNewConstraint->rescale(scale); + aConstraints.push_back(aNewConstraint); + + return ConstraintWrapperPtr( + new PlaneGCSSolver_ConstraintWrapper(aConstraints, getType())); +} void SketchSolver_ConstraintMovement::startPoint( const std::shared_ptr& theStartPoint) diff --git a/src/SketchSolver/SketchSolver_ConstraintMovement.h b/src/SketchSolver/SketchSolver_ConstraintMovement.h index 1735a70b0..4d14eb42d 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMovement.h +++ b/src/SketchSolver/SketchSolver_ConstraintMovement.h @@ -66,9 +66,12 @@ protected: /// \brief Create constraint to fix moved arc extremity ConstraintWrapperPtr fixArcExtremity(const EntityWrapperPtr& theArcExtremity); - /// \brief Creat constraint to fix moved point on circle/arc + /// \brief Create constraint to fix moved point on circle/arc ConstraintWrapperPtr fixPointOnCircle(const EntityWrapperPtr& theCircular); + /// \brief Create constraint to fix moved point on ellipse/elliptical arc + ConstraintWrapperPtr fixPointOnEllipse(const EntityWrapperPtr& theConic); + private: FeaturePtr myMovedFeature; ///< fixed feature (if set, myBaseConstraint should be NULL) AttributePtr myDraggedPoint; ///< one of the feature points which has been moved -- 2.39.2