From f64e1300ed35bb1e9a2486cdb5713355e832dd39 Mon Sep 17 00:00:00 2001 From: asozinov Date: Fri, 23 Jun 2023 02:06:02 +0100 Subject: [PATCH 1/1] bos#35152 [EDF] (2023-T1) Sketch Circle should allow user to position construction point WIll be modified Sketch Circle feature: Current implementation provide possibility change sewing point and rotate this point Sketch.addCircleWithPoint(CenterPoint, Radius, Angle) Sketch.addCircleWithPoint(CenterPoint, PassedPoint, Angle) Sketch.addCircleWithPoint(PassPoint1, PassPoint2, PassPoint3, Angle) Get new point: SketchCircle.createdPoint() //Last modification (06/07/23): change comment --- src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.cpp | 6 +- src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.h | 3 +- src/SketchAPI/SketchAPI_Circle.cpp | 135 +++++++++++-- src/SketchAPI/SketchAPI_Circle.h | 29 ++- src/SketchAPI/SketchAPI_MacroCircle.cpp | 77 ++++++-- src/SketchAPI/SketchAPI_MacroCircle.h | 33 +++- src/SketchAPI/SketchAPI_Sketch.cpp | 110 ++++++++++- src/SketchAPI/SketchAPI_Sketch.h | 67 ++++++- src/SketchPlugin/SketchPlugin_Circle.cpp | 77 +++++++- src/SketchPlugin/SketchPlugin_Circle.h | 31 +++ src/SketchPlugin/SketchPlugin_MacroCircle.cpp | 182 +++++++++++++++++- src/SketchPlugin/SketchPlugin_MacroCircle.h | 32 +++ .../Test/TestCreateCircleByCenterAndPassed.py | 46 ++++- .../Test/TestCreateCircleByThreePoints.py | 58 +++++- .../Test/TestCreateCircleChangeType.py | 2 +- src/SketchPlugin/Test/TestMoveCircle.py | 2 +- src/SketchPlugin/doc/circleFeature.rst | 41 +++- .../doc/images/Circle_panel_3pt.png | Bin 21622 -> 15489 bytes .../doc/images/Circle_panel_edit.png | Bin 10400 -> 7577 bytes .../doc/images/Circle_panel_pt_rad.png | Bin 19105 -> 14567 bytes src/SketchPlugin/plugin-Sketch.xml | 18 ++ .../PlaneGCSSolver/PlaneGCSSolver_Tools.cpp | 3 +- 22 files changed, 875 insertions(+), 77 deletions(-) diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.cpp index f19425a48..86fe03d7b 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.cpp +++ b/src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.cpp @@ -162,12 +162,16 @@ std::shared_ptr GeomAlgoAPI_EdgeBuilder::cylinderAxis( std::shared_ptr GeomAlgoAPI_EdgeBuilder::lineCircle( std::shared_ptr theCenter, std::shared_ptr theNormal, - double theRadius) + double theRadius, double theRotationAngle) { const gp_Pnt& aCenter = theCenter->impl(); const gp_Dir& aDir = theNormal->impl(); + gp_Ax1 anAx(aCenter, aDir); + gp_Circ aCircle(gp_Ax2(aCenter, aDir), theRadius); + if (Abs(theRotationAngle) > 1.e-7) // Tolerance + aCircle.Rotate(anAx, theRotationAngle); BRepBuilderAPI_MakeEdge anEdgeBuilder(aCircle); std::shared_ptr aRes(new GeomAPI_Edge); diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.h b/src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.h index 465074028..fabae078a 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.h +++ b/src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.h @@ -65,7 +65,8 @@ class GEOMALGOAPI_EXPORT GeomAlgoAPI_EdgeBuilder /// Creates linear edge in a form of a circle by a point and a circle radius static std::shared_ptr lineCircle(std::shared_ptr theCenter, std::shared_ptr theNormal, - double theRadius); + double theRadius, + double theRotationAngle = 0.); /// Creates linear edge in a form of a circle by GeomAPI_Circle static std::shared_ptr lineCircle(std::shared_ptr theCircle); diff --git a/src/SketchAPI/SketchAPI_Circle.cpp b/src/SketchAPI/SketchAPI_Circle.cpp index 41853fe1d..95d48f397 100644 --- a/src/SketchAPI/SketchAPI_Circle.cpp +++ b/src/SketchAPI/SketchAPI_Circle.cpp @@ -26,6 +26,9 @@ #include #include +#include +#include + //================================================================================================== SketchAPI_Circle::SketchAPI_Circle(const std::shared_ptr & theFeature) : SketchAPI_SketchEntity(theFeature) @@ -37,22 +40,22 @@ SketchAPI_Circle::SketchAPI_Circle(const std::shared_ptr & the SketchAPI_Circle::SketchAPI_Circle(const std::shared_ptr& theFeature, double theCenterX, double theCenterY, - double theRadius) + double theRadius, double theAngle) : SketchAPI_SketchEntity(theFeature) { if(initialize()) { - setByCenterAndRadius(theCenterX, theCenterY, theRadius); + setByCenterAndRadius(theCenterX, theCenterY, theRadius, theAngle); } } //================================================================================================== SketchAPI_Circle::SketchAPI_Circle(const std::shared_ptr& theFeature, const std::shared_ptr& theCenter, - double theRadius) + double theRadius, double theAngle) : SketchAPI_SketchEntity(theFeature) { if(initialize()) { - setByCenterAndRadius(theCenter, theRadius); + setByCenterAndRadius(theCenter, theRadius, theAngle); } } @@ -82,23 +85,90 @@ SketchAPI_Circle::~SketchAPI_Circle() } +// Create point on circle line +void SketchAPI_Circle::createPoint() +{ + // Find sketch + CompositeFeaturePtr aSketch; + const std::set& aRefs = feature()->data()->refsToMe(); + for (std::set::const_iterator anIt = aRefs.begin(); anIt != aRefs.end(); ++anIt) + if ((*anIt)->id() == SketchPlugin_Sketch::FEATURES_ID()) + { + aSketch = std::dynamic_pointer_cast((*anIt)->owner()); + break; + } + if (!aSketch) + return; + + // create point on line + FeaturePtr aPointFeature = aSketch->addFeature(SketchPlugin_Point::ID()); + aPointFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(feature()); + + AttributePoint2DPtr aCoord = std::dynamic_pointer_cast( + aPointFeature->attribute(SketchPlugin_Point::COORD_ID())); + + GeomPnt2dPtr aPnt = std::dynamic_pointer_cast( + feature()->attribute(SketchPlugin_Circle::ROTATE_ID()))->pnt(); + + aCoord->setValue(aPnt); + aPointFeature->execute(); + + FeaturePtr aConstraint = aSketch->addFeature(SketchPlugin_ConstraintCoincidenceInternal::ID()); + AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast( + aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); + aRefAttr->setAttr(feature()->attribute(SketchPlugin_Circle::ROTATE_ID())); + + aRefAttr = std::dynamic_pointer_cast( + aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B())); + aRefAttr->setAttr(aCoord); + + feature()->reference(SketchPlugin_Circle::ROTATE_REF_ID())->setValue(aPointFeature); +} + //================================================================================================== -void SketchAPI_Circle::setByCenterAndRadius(double theCenterX, double theCenterY, double theRadius) +void SketchAPI_Circle::setByCenterAndRadius(double theCenterX, double theCenterY, + double theRadius, double theAngle) { fillAttribute(center(), theCenterX, theCenterY); fillAttribute(theRadius, myradius); + fillAttribute(theAngle, myangle); - execute(); + bool isNeedPoint = + feature()->integer(SketchPlugin_Circle::VERSION_ID())->value() > SketchPlugin_Circle::THE_VERSION_0; + if (isNeedPoint) + { + fillAttribute(theAngle, angle()); + + execute(); + createPoint(); + } + else + { + execute(); + } } //================================================================================================== void SketchAPI_Circle::setByCenterAndRadius(const std::shared_ptr& theCenter, - double theRadius) + double theRadius, double theAngle) { fillAttribute(theCenter, mycenter); fillAttribute(theRadius, myradius); - execute(); + bool isNeedPoint = + feature()->integer(SketchPlugin_Circle::VERSION_ID())->value() > SketchPlugin_Circle::THE_VERSION_0; + + if (isNeedPoint) + { + fillAttribute(theAngle, angle()); + + execute(); + createPoint(); + } + else + { + execute(); + } } //================================================================================================== @@ -141,6 +211,32 @@ void SketchAPI_Circle::setRadius(double theRadius) execute(); } +//================================================================================================== +void SketchAPI_Circle::setAngle(double theAngle) +{ + fillAttribute(ModelHighAPI_Double(theAngle), myangle); + + execute(); +} + +//================================================================================================== +// Return created point +std::shared_ptr SketchAPI_Circle::createdPoint() const +{ + std::shared_ptr anEnt; + + AttributeReferencePtr anRef = feature()->reference(SketchPlugin_Circle::ROTATE_REF_ID()); + if (!anRef->isInitialized()) + return anEnt; + + FeaturePtr aFeature = ModelAPI_Feature::feature(anRef->value()); + if (aFeature && aFeature->getKind() == SketchPlugin_Point::ID()) + { + anEnt = std::shared_ptr < SketchAPI_SketchEntity>(new SketchAPI_Point(aFeature)); + } + return anEnt; +} + //================================================================================================== void SketchAPI_Circle::dump(ModelHighAPI_Dumper& theDumper) const { @@ -151,13 +247,26 @@ void SketchAPI_Circle::dump(ModelHighAPI_Dumper& theDumper) const const std::string& aSketchName = theDumper.parentName(aBase); AttributeSelectionPtr anExternal = aBase->selection(SketchPlugin_SketchEntity::EXTERNAL_ID()); + std::string aComName = aBase->integer(SketchPlugin_Circle::VERSION_ID())->value() > SketchPlugin_Circle::THE_VERSION_0 ? + "addCircleWithPoint" : "addCircle"; + if (anExternal->context()) { // circle is external - theDumper << aBase << " = " << aSketchName << ".addCircle(" << anExternal << ")" << std::endl; - } else { - // circle given by center and radius - theDumper << aBase << " = " << aSketchName << ".addCircle(" - << center() << ", " << radius() << ")" << std::endl; + theDumper << aBase << " = " << aSketchName << "." << aComName << "(" << anExternal << ")" << std::endl; + } + else {// circle given by center and radius + theDumper << aBase << " = " << aSketchName << "." << aComName << "(" << center() << ", " << radius(); + if (aBase->integer(SketchPlugin_Circle::VERSION_ID())->value() > SketchPlugin_Circle::THE_VERSION_0) + { + theDumper << ", " << angle() << ")" << std::endl; + std::shared_ptr aPoint = createdPoint(); + if (aPoint) + theDumper << aPoint->feature() << " = " << theDumper.name(aBase) << ".createdPoint()" << std::endl; + } + else + { + theDumper << ")" << std::endl; + } } // dump "auxiliary" flag if necessary SketchAPI_SketchEntity::dump(theDumper); diff --git a/src/SketchAPI/SketchAPI_Circle.h b/src/SketchAPI/SketchAPI_Circle.h index dcc58c715..96744ebf5 100644 --- a/src/SketchAPI/SketchAPI_Circle.h +++ b/src/SketchAPI/SketchAPI_Circle.h @@ -42,13 +42,15 @@ public: SketchAPI_Circle(const std::shared_ptr& theFeature, double theCenterX, double theCenterY, - double theRadius); + double theRadius, + double theAngle); /// Constructor with values. SKETCHAPI_EXPORT SketchAPI_Circle(const std::shared_ptr& theFeature, const std::shared_ptr& theCenter, - double theRadius); + double theRadius, + double theAngle); /// Constructor with values. SKETCHAPI_EXPORT @@ -64,21 +66,25 @@ public: SKETCHAPI_EXPORT virtual ~SketchAPI_Circle(); - INTERFACE_3(SketchPlugin_Circle::ID(), + INTERFACE_4(SketchPlugin_Circle::ID(), center, SketchPlugin_Circle::CENTER_ID(), GeomDataAPI_Point2D, /** Center point */, radius, SketchPlugin_Circle::RADIUS_ID(), ModelAPI_AttributeDouble, /** Radius */, external, SketchPlugin_Circle::EXTERNAL_ID(), - ModelAPI_AttributeSelection, /** External */) + ModelAPI_AttributeSelection, /** External */, + angle, SketchPlugin_Circle::ANGLE_ID(), + ModelAPI_AttributeDouble, /** Angle */) /// Set by center and radius. SKETCHAPI_EXPORT - void setByCenterAndRadius(double theCenterX, double theCenterY, double theRadius); + void setByCenterAndRadius(double theCenterX, double theCenterY, + double theRadius, double theAngle); /// Set by center and radius. SKETCHAPI_EXPORT - void setByCenterAndRadius(const std::shared_ptr& theCenter, double theRadius); + void setByCenterAndRadius(const std::shared_ptr& theCenter, + double theRadius, double theAngle); /// Set by external. SKETCHAPI_EXPORT @@ -100,9 +106,20 @@ public: SKETCHAPI_EXPORT void setRadius(double theRadius); + /// Set angle. + SKETCHAPI_EXPORT + void setAngle(double theAngle); + + /// Returns created points on circle + SKETCHAPI_EXPORT + std::shared_ptr createdPoint() const; + /// Dump wrapped feature SKETCHAPI_EXPORT virtual void dump(ModelHighAPI_Dumper& theDumper) const; + +private: + void createPoint(); }; /// Pointer on Circle object. diff --git a/src/SketchAPI/SketchAPI_MacroCircle.cpp b/src/SketchAPI/SketchAPI_MacroCircle.cpp index f5e459a40..640893214 100644 --- a/src/SketchAPI/SketchAPI_MacroCircle.cpp +++ b/src/SketchAPI/SketchAPI_MacroCircle.cpp @@ -26,6 +26,9 @@ #include #include +#include +#include + //================================================================================================== SketchAPI_MacroCircle::SketchAPI_MacroCircle(const std::shared_ptr& theFeature) : SketchAPI_SketchEntity(theFeature) @@ -38,22 +41,24 @@ SketchAPI_MacroCircle::SketchAPI_MacroCircle(const std::shared_ptr& theFeature, const std::shared_ptr& theCenterPoint, - const std::shared_ptr& thePassedPoint) + const std::shared_ptr& thePassedPoint, + double theAngle) : SketchAPI_SketchEntity(theFeature) { if(initialize()) { - setByCenterAndPassedPoints(theCenterPoint, thePassedPoint); + setByCenterAndPassedPoints(theCenterPoint, thePassedPoint, theAngle); } } @@ -61,11 +66,12 @@ SketchAPI_MacroCircle::SketchAPI_MacroCircle(const std::shared_ptr& theFeature, double theX1, double theY1, double theX2, double theY2, - double theX3, double theY3) + double theX3, double theY3, + double theAngle) : SketchAPI_SketchEntity(theFeature) { if(initialize()) { - setByThreePoints(theX1, theY1, theX2, theY2, theX3, theY3); + setByThreePoints(theX1, theY1, theX2, theY2, theX3, theY3, theAngle); } } @@ -73,11 +79,12 @@ SketchAPI_MacroCircle::SketchAPI_MacroCircle(const std::shared_ptr& theFeature, const std::shared_ptr& thePoint1, const std::shared_ptr& thePoint2, - const std::shared_ptr& thePoint3) + const std::shared_ptr& thePoint3, + double theAngle) : SketchAPI_SketchEntity(theFeature) { if(initialize()) { - setByThreePoints(thePoint1, thePoint2, thePoint3); + setByThreePoints(thePoint1, thePoint2, thePoint3, theAngle); } } @@ -90,49 +97,95 @@ SketchAPI_MacroCircle::~SketchAPI_MacroCircle() void SketchAPI_MacroCircle::setByCenterAndPassedPoints(double theCenterX, double theCenterY, double thePassedX, - double thePassedY) + double thePassedY, + double theAngle) { fillAttribute(SketchPlugin_MacroCircle::CIRCLE_TYPE_BY_CENTER_AND_PASSED_POINTS(), mycircleType); fillAttribute(centerPoint(), theCenterX, theCenterY); fillAttribute(passedPoint(), thePassedX, thePassedY); + bool isNeedPoint = + feature()->integer(SketchPlugin_MacroCircle::VERSION_ID())->value() > 0; + + if (isNeedPoint) + fillAttribute(theAngle, angle()); + execute(); } //================================================================================================== void SketchAPI_MacroCircle::setByCenterAndPassedPoints( const std::shared_ptr& theCenterPoint, - const std::shared_ptr& thePassedPoint) + const std::shared_ptr& thePassedPoint, + double theAngle) { fillAttribute(SketchPlugin_MacroCircle::CIRCLE_TYPE_BY_CENTER_AND_PASSED_POINTS(), mycircleType); fillAttribute(theCenterPoint, mycenterPoint); fillAttribute(thePassedPoint, mypassedPoint); + bool isNeedPoint = + feature()->integer(SketchPlugin_MacroCircle::VERSION_ID())->value() > 0; + + if (isNeedPoint) + fillAttribute(theAngle, angle()); + execute(); } //================================================================================================== void SketchAPI_MacroCircle::setByThreePoints(double theX1, double theY1, double theX2, double theY2, - double theX3, double theY3) + double theX3, double theY3, + double theAngle) { fillAttribute(SketchPlugin_MacroCircle::CIRCLE_TYPE_BY_THREE_POINTS(), mycircleType); fillAttribute(firstPoint(), theX1, theY1); fillAttribute(secondPoint(), theX2, theY2); fillAttribute(thirdPoint(), theX3, theY3); + bool isNeedPoint = + feature()->integer(SketchPlugin_MacroCircle::VERSION_ID())->value() > 0; + + if (isNeedPoint) + fillAttribute(theAngle, angle()); + execute(); } //================================================================================================== void SketchAPI_MacroCircle::setByThreePoints(const std::shared_ptr& thePoint1, const std::shared_ptr& thePoint2, - const std::shared_ptr& thePoint3) + const std::shared_ptr& thePoint3, + double theAngle) { fillAttribute(SketchPlugin_MacroCircle::CIRCLE_TYPE_BY_THREE_POINTS(), mycircleType); fillAttribute(thePoint1, myfirstPoint); fillAttribute(thePoint2, mysecondPoint); fillAttribute(thePoint3, mythirdPoint); + bool isNeedPoint = + feature()->integer(SketchPlugin_MacroCircle::VERSION_ID())->value() > 0; + + if (isNeedPoint) + fillAttribute(theAngle, angle()); + execute(); } + +// return created point +std::shared_ptr SketchAPI_MacroCircle::createdPoint() const +{ + std::shared_ptr anEnt; + + AttributeRefAttrPtr anRef = feature()->refattr(SketchPlugin_MacroCircle::ROTATE_POINT_REF_ID()); + if (!anRef->isInitialized()) + return anEnt; + + ObjectPtr aPointObj = anRef->object(); + FeaturePtr aFeature = ModelAPI_Feature::feature(aPointObj); + if (aFeature && aFeature->getKind() == SketchPlugin_Point::ID()) + { + anEnt = std::shared_ptr < SketchAPI_SketchEntity>(new SketchAPI_Point(aFeature)); + } + return anEnt; +} diff --git a/src/SketchAPI/SketchAPI_MacroCircle.h b/src/SketchAPI/SketchAPI_MacroCircle.h index 725edeacb..ee278b9f9 100644 --- a/src/SketchAPI/SketchAPI_MacroCircle.h +++ b/src/SketchAPI/SketchAPI_MacroCircle.h @@ -43,33 +43,37 @@ public: double theCenterX, double theCenterY, double thePassedX, - double thePassedY); + double thePassedY, + double theAngle); /// Constructor with values. SKETCHAPI_EXPORT SketchAPI_MacroCircle(const std::shared_ptr& theFeature, const std::shared_ptr& theCenterPoint, - const std::shared_ptr& thePassedPoint); + const std::shared_ptr& thePassedPoint, + double theAngle); /// Constructor with values. SKETCHAPI_EXPORT SketchAPI_MacroCircle(const std::shared_ptr& theFeature, double theX1, double theY1, double theX2, double theY2, - double theX3, double theY3); + double theX3, double theY3, + double theAngle); /// Constructor with values. SKETCHAPI_EXPORT SketchAPI_MacroCircle(const std::shared_ptr& theFeature, const std::shared_ptr& thePoint1, const std::shared_ptr& thePoint2, - const std::shared_ptr& thePoint3); + const std::shared_ptr& thePoint3, + double theAngle); /// Destructor. SKETCHAPI_EXPORT virtual ~SketchAPI_MacroCircle(); - INTERFACE_6(SketchPlugin_MacroCircle::ID(), + INTERFACE_7(SketchPlugin_MacroCircle::ID(), circleType, SketchPlugin_MacroCircle::CIRCLE_TYPE(), ModelAPI_AttributeString, /** Circle type */, centerPoint, SketchPlugin_MacroCircle::CENTER_POINT_ID(), @@ -81,26 +85,35 @@ public: secondPoint, SketchPlugin_MacroCircle::SECOND_POINT_ID(), GeomDataAPI_Point2D, /** Second point */, thirdPoint, SketchPlugin_MacroCircle::THIRD_POINT_ID(), - GeomDataAPI_Point2D, /** Third point */) + GeomDataAPI_Point2D, /** Third point */, + angle, SketchPlugin_MacroCircle::CIRCLE_ROTATE_ANGLE_ID(), + ModelAPI_AttributeDouble, /** Angle */) + /// Returns created points on circle + SKETCHAPI_EXPORT + std::shared_ptr createdPoint() const; private: /// Set by center and passed points. void setByCenterAndPassedPoints(double theCenterX, double theCenterY, - double thePassedX, double thePassedY); + double thePassedX, double thePassedY, + double theAngle); /// Set by center and passed points. void setByCenterAndPassedPoints(const std::shared_ptr& theCenterPoint, - const std::shared_ptr& thePassedPoint); + const std::shared_ptr& thePassedPoint, + double theAngle); /// Set by three points. void setByThreePoints(double theX1, double theY1, double theX2, double theY2, - double theX3, double theY3); + double theX3, double theY3, + double theAngle); /// Set by three points. void setByThreePoints(const std::shared_ptr& thePoint1, const std::shared_ptr& thePoint2, - const std::shared_ptr& thePoint3); + const std::shared_ptr& thePoint3, + double theAngle); }; /// Pointer on Circle object. diff --git a/src/SketchAPI/SketchAPI_Sketch.cpp b/src/SketchAPI/SketchAPI_Sketch.cpp index b0836ae12..3c30c146a 100644 --- a/src/SketchAPI/SketchAPI_Sketch.cpp +++ b/src/SketchAPI/SketchAPI_Sketch.cpp @@ -589,25 +589,31 @@ std::shared_ptr SketchAPI_Sketch::addRectangleCentered( return aRect; } +// Old way for create circle //-------------------------------------------------------------------------------------- +[[deprecated("Use addCircleWithPoint method instead.")]] std::shared_ptr SketchAPI_Sketch::addCircle(double theCenterX, double theCenterY, double theRadius) { std::shared_ptr aFeature = compositeFeature()->addFeature(SketchPlugin_Circle::ID()); - return CirclePtr(new SketchAPI_Circle(aFeature, theCenterX, theCenterY, theRadius)); + fillAttribute(SketchPlugin_Circle::THE_VERSION_0, aFeature->integer(SketchPlugin_Circle::VERSION_ID())); + return CirclePtr(new SketchAPI_Circle(aFeature, theCenterX, theCenterY, theRadius, 0)); } +[[deprecated("Use addCircleWithPoint method instead.")]] std::shared_ptr SketchAPI_Sketch::addCircle( const std::shared_ptr& theCenter, double theRadius) { std::shared_ptr aFeature = compositeFeature()->addFeature(SketchPlugin_Circle::ID()); - return CirclePtr(new SketchAPI_Circle(aFeature, theCenter, theRadius)); + fillAttribute(SketchPlugin_Circle::THE_VERSION_0, aFeature->integer(SketchPlugin_Circle::VERSION_ID())); + return CirclePtr(new SketchAPI_Circle(aFeature, theCenter, theRadius, 0)); } +[[deprecated("Use addCircleWithPoint method instead.")]] std::shared_ptr SketchAPI_Sketch::addCircle(double theCenterX, double theCenterY, double thePassedX, @@ -615,30 +621,37 @@ std::shared_ptr SketchAPI_Sketch::addCircle(double theCen { std::shared_ptr aFeature = compositeFeature()->addFeature(SketchPlugin_MacroCircle::ID()); + fillAttribute(SketchPlugin_Circle::THE_VERSION_0, aFeature->integer(SketchPlugin_MacroCircle::VERSION_ID())); return MacroCirclePtr(new SketchAPI_MacroCircle(aFeature, theCenterX, theCenterY, - thePassedX, thePassedY)); + thePassedX, thePassedY, 0)); } +[[deprecated("Use addCircleWithPoint method instead.")]] std::shared_ptr SketchAPI_Sketch::addCircle( const std::shared_ptr& theCenterPoint, const std::shared_ptr& thePassedPoint) { std::shared_ptr aFeature = compositeFeature()->addFeature(SketchPlugin_MacroCircle::ID()); - return MacroCirclePtr(new SketchAPI_MacroCircle(aFeature, theCenterPoint, thePassedPoint)); + fillAttribute(SketchPlugin_Circle::THE_VERSION_0, aFeature->integer(SketchPlugin_MacroCircle::VERSION_ID())); + return MacroCirclePtr(new SketchAPI_MacroCircle(aFeature, theCenterPoint, thePassedPoint, 0)); } +[[deprecated("Use addCircleWithPoint method instead.")]] std::shared_ptr SketchAPI_Sketch::addCircle(double theX1, double theY1, double theX2, double theY2, double theX3, double theY3) { std::shared_ptr aFeature = compositeFeature()->addFeature(SketchPlugin_MacroCircle::ID()); + fillAttribute(SketchPlugin_Circle::THE_VERSION_0, aFeature->integer(SketchPlugin_MacroCircle::VERSION_ID())); + return MacroCirclePtr(new SketchAPI_MacroCircle(aFeature, theX1, theY1, theX2, theY2, - theX3, theY3)); + theX3, theY3, 0)); } +[[deprecated("Use addCircleWithPoint method instead.")]] std::shared_ptr SketchAPI_Sketch::addCircle( const std::shared_ptr& thePoint1, const std::shared_ptr& thePoint2, @@ -646,9 +659,11 @@ std::shared_ptr SketchAPI_Sketch::addCircle( { std::shared_ptr aFeature = compositeFeature()->addFeature(SketchPlugin_MacroCircle::ID()); - return MacroCirclePtr(new SketchAPI_MacroCircle(aFeature, thePoint1, thePoint2, thePoint3)); + fillAttribute(SketchPlugin_Circle::THE_VERSION_0, aFeature->integer(SketchPlugin_Circle::VERSION_ID())); + return MacroCirclePtr(new SketchAPI_MacroCircle(aFeature, thePoint1, thePoint2, thePoint3, 0)); } +[[deprecated("Use addCircleWithPoint method instead.")]] std::shared_ptr SketchAPI_Sketch::addCircle(const ModelHighAPI_Selection & theExternal) { @@ -657,6 +672,7 @@ std::shared_ptr return CirclePtr(new SketchAPI_Circle(aFeature, theExternal)); } +[[deprecated("Use addCircleWithPoint method instead.")]] std::shared_ptr SketchAPI_Sketch::addCircle(const std::wstring & theExternalName) { std::shared_ptr aFeature = @@ -664,6 +680,88 @@ std::shared_ptr SketchAPI_Sketch::addCircle(const std::wstring return CirclePtr(new SketchAPI_Circle(aFeature, theExternalName)); } +// New way for create Circle +//-------------------------------------------------------------------------------------- +std::shared_ptr SketchAPI_Sketch::addCircleWithPoint(double theCenterX, + double theCenterY, + double theRadius, + double theAngle) +{ + std::shared_ptr aFeature = + compositeFeature()->addFeature(SketchPlugin_Circle::ID()); + return CirclePtr(new SketchAPI_Circle(aFeature, theCenterX, theCenterY, theRadius, theAngle)); +} + +std::shared_ptr SketchAPI_Sketch::addCircleWithPoint( + const std::shared_ptr& theCenter, + double theRadius, + double theAngle) +{ + std::shared_ptr aFeature = + compositeFeature()->addFeature(SketchPlugin_Circle::ID()); + return CirclePtr(new SketchAPI_Circle(aFeature, theCenter, theRadius, theAngle)); +} + +std::shared_ptr SketchAPI_Sketch::addCircleWithPoint(double theCenterX, + double theCenterY, + double thePassedX, + double thePassedY, + double theAngle) +{ + std::shared_ptr aFeature = + compositeFeature()->addFeature(SketchPlugin_MacroCircle::ID()); + return MacroCirclePtr(new SketchAPI_MacroCircle(aFeature, theCenterX, theCenterY, + thePassedX, thePassedY, theAngle)); +} + +std::shared_ptr SketchAPI_Sketch::addCircleWithPoint( + const std::shared_ptr& theCenterPoint, + const std::shared_ptr& thePassedPoint, + double theAngle) +{ + std::shared_ptr aFeature = + compositeFeature()->addFeature(SketchPlugin_MacroCircle::ID()); + return MacroCirclePtr(new SketchAPI_MacroCircle(aFeature, theCenterPoint, thePassedPoint, theAngle)); +} + +std::shared_ptr SketchAPI_Sketch::addCircleWithPoint(double theX1, double theY1, + double theX2, double theY2, + double theX3, double theY3, + double theAngle) +{ + std::shared_ptr aFeature = + compositeFeature()->addFeature(SketchPlugin_MacroCircle::ID()); + return MacroCirclePtr(new SketchAPI_MacroCircle(aFeature, theX1, theY1, + theX2, theY2, + theX3, theY3, theAngle)); +} + +std::shared_ptr SketchAPI_Sketch::addCircleWithPoint( + const std::shared_ptr& thePoint1, + const std::shared_ptr& thePoint2, + const std::shared_ptr& thePoint3, + double theAngle) +{ + std::shared_ptr aFeature = + compositeFeature()->addFeature(SketchPlugin_MacroCircle::ID()); + return MacroCirclePtr(new SketchAPI_MacroCircle(aFeature, thePoint1, thePoint2, thePoint3, theAngle)); +} + +std::shared_ptr +SketchAPI_Sketch::addCircleWithPoint(const ModelHighAPI_Selection& theExternal) +{ + std::shared_ptr aFeature = + compositeFeature()->addFeature(SketchPlugin_Circle::ID()); + return CirclePtr(new SketchAPI_Circle(aFeature, theExternal)); +} + +std::shared_ptr SketchAPI_Sketch::addCircleWithPoint(const std::wstring& theExternalName) +{ + std::shared_ptr aFeature = + compositeFeature()->addFeature(SketchPlugin_Circle::ID()); + return CirclePtr(new SketchAPI_Circle(aFeature, theExternalName)); +} + //-------------------------------------------------------------------------------------- std::shared_ptr SketchAPI_Sketch::addArc(double theCenterX, double theCenterY, double theStartX, double theStartY, diff --git a/src/SketchAPI/SketchAPI_Sketch.h b/src/SketchAPI/SketchAPI_Sketch.h index 993e6ef90..7f2fa98ea 100644 --- a/src/SketchAPI/SketchAPI_Sketch.h +++ b/src/SketchAPI/SketchAPI_Sketch.h @@ -187,45 +187,96 @@ public: const std::pair, ModelHighAPI_RefAttr> & theCenter, const std::pair, ModelHighAPI_RefAttr> & theCorner); - /// Add circle + /// Add circle. + /// [DEPRECATED]: use addCircleWithPoint() instead. SKETCHAPI_EXPORT std::shared_ptr addCircle( double theCenterX, double theCenterY, double theRadius); - /// Add circle + /// Add circle. + /// [DEPRECATED]: use addCircleWithPoint() instead. SKETCHAPI_EXPORT std::shared_ptr addCircle( const std::shared_ptr& theCenter, double theRadius); - /// Add circle + /// Add circle. + /// [DEPRECATED]: use addCircleWithPoint() instead. SKETCHAPI_EXPORT std::shared_ptr addCircle( double theCenterX, double theCenterY, double thePassedX, double thePassedY); - /// Add circle + /// Add circle. + /// [DEPRECATED]: use addCircleWithPoint() instead. SKETCHAPI_EXPORT std::shared_ptr addCircle( const std::shared_ptr& theCenterPoint, const std::shared_ptr& thePassedPoint); - /// Add circle + /// Add circle. + /// [DEPRECATED]: use addCircleWithPoint() instead. SKETCHAPI_EXPORT std::shared_ptr addCircle( double theX1, double theY1, double theX2, double theY2, double theX3, double theY3); - /// Add circle + /// Add circle. + /// [DEPRECATED]: use addCircleWithPoint() instead. SKETCHAPI_EXPORT std::shared_ptr addCircle( const std::shared_ptr& thePoint1, const std::shared_ptr& thePoint2, const std::shared_ptr& thePoint3); - /// Add circle + /// Add circle. + /// [DEPRECATED]: use addCircleWithPoint() instead. SKETCHAPI_EXPORT std::shared_ptr addCircle(const ModelHighAPI_Selection & theExternal); - /// Add circle + /// Add circle. + /// [DEPRECATED]: use addCircleWithPoint() instead. SKETCHAPI_EXPORT std::shared_ptr addCircle(const std::wstring & theExternalName); + /// Add circle with point + SKETCHAPI_EXPORT + std::shared_ptr addCircleWithPoint( + double theCenterX, double theCenterY, + double theRadius, double theAngle); + /// Add circle with point + SKETCHAPI_EXPORT + std::shared_ptr addCircleWithPoint( + const std::shared_ptr& theCenter, + double theRadius, double theAngle); + /// Add circle with point + SKETCHAPI_EXPORT + std::shared_ptr addCircleWithPoint( + double theCenterX, double theCenterY, + double thePassedX, double thePassedY, + double theAngle); + /// Add circle with point + SKETCHAPI_EXPORT + std::shared_ptr addCircleWithPoint( + const std::shared_ptr& theCenterPoint, + const std::shared_ptr& thePassedPoint, + double theAngle); + /// Add circle with point + SKETCHAPI_EXPORT + std::shared_ptr addCircleWithPoint( + double theX1, double theY1, + double theX2, double theY2, + double theX3, double theY3, + double theAngle); + /// Add circle with point + SKETCHAPI_EXPORT + std::shared_ptr addCircleWithPoint( + const std::shared_ptr& thePoint1, + const std::shared_ptr& thePoint2, + const std::shared_ptr& thePoint3, + double theAngle); + /// Add circle with point + SKETCHAPI_EXPORT + std::shared_ptr addCircleWithPoint(const ModelHighAPI_Selection& theExternal); + /// Add circle with point + SKETCHAPI_EXPORT + std::shared_ptr addCircleWithPoint(const std::wstring& theExternalName); + /// Add arc SKETCHAPI_EXPORT std::shared_ptr addArc( diff --git a/src/SketchPlugin/SketchPlugin_Circle.cpp b/src/SketchPlugin/SketchPlugin_Circle.cpp index c0eecf508..86d5721e8 100644 --- a/src/SketchPlugin/SketchPlugin_Circle.cpp +++ b/src/SketchPlugin/SketchPlugin_Circle.cpp @@ -19,16 +19,22 @@ #include "SketchPlugin_Circle.h" #include "SketchPlugin_Sketch.h" +#include "SketchPlugin_Tools.h" #include #include #include +#include +#include #include #include #include #include +#include +#include #include #include +#include #include #include #include @@ -41,6 +47,7 @@ #include const double tolerance = 1e-7; +const double PI = 3.141592653589793238463; SketchPlugin_Circle::SketchPlugin_Circle() @@ -51,10 +58,27 @@ SketchPlugin_Circle::SketchPlugin_Circle() void SketchPlugin_Circle::initDerivedClassAttributes() { data()->addAttribute(CENTER_ID(), GeomDataAPI_Point2D::typeId()); + data()->addAttribute(ROTATE_ID(), GeomDataAPI_Point2D::typeId()); + data()->addAttribute(ROTATE_REF_ID(), ModelAPI_AttributeReference::typeId()); data()->addAttribute(RADIUS_ID(), ModelAPI_AttributeDouble::typeId()); + data()->addAttribute(ANGLE_ID(), ModelAPI_AttributeDouble::typeId()); + + // While exist addCircle without creating point. + AttributeIntegerPtr aVerAttr = std::dynamic_pointer_cast( + data()->addAttribute(VERSION_ID(), ModelAPI_AttributeInteger::typeId())); + aVerAttr->setIsArgument(false); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), VERSION_ID()); + if (!aVerAttr->isInitialized()) { + // this is a newly created feature (not read from file), + // so, initialize the latest version + aVerAttr->setValue(SketchPlugin_Circle::THE_VERSION_1); + } data()->addAttribute(EXTERNAL_ID(), ModelAPI_AttributeSelection::typeId()); ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EXTERNAL_ID()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), ROTATE_ID()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), ROTATE_REF_ID()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), ANGLE_ID()); } void SketchPlugin_Circle::execute() @@ -68,6 +92,7 @@ void SketchPlugin_Circle::execute() std::shared_ptr aCenterAttr = std::dynamic_pointer_cast(data()->attribute(CENTER_ID())); AttributeDoublePtr aRadiusAttr = real(RADIUS_ID()); + AttributeDoublePtr anAngleAttr = real(ANGLE_ID()); if(!aCenterAttr->isInitialized() || !aRadiusAttr->isInitialized()) { return; } @@ -77,7 +102,10 @@ void SketchPlugin_Circle::execute() return; } - // Make a visible point. + if (!anAngleAttr->isInitialized()) + anAngleAttr->setValue(0); + + // Make a visible center point. SketchPlugin_Sketch::createPoint2DResult(this, sketch(), CENTER_ID(), 0); // Make a visible circle. @@ -86,8 +114,21 @@ void SketchPlugin_Circle::execute() aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID())); std::shared_ptr aNormal(new GeomAPI_Dir(aNDir->x(), aNDir->y(), aNDir->z())); - std::shared_ptr aCircleShape = - GeomAlgoAPI_EdgeBuilder::lineCircle(aCenter, aNormal, aRadius); + std::shared_ptr aCircleShape; + if (integer(VERSION_ID())->value() > SketchPlugin_Circle::THE_VERSION_0) + { + double aValAn = anAngleAttr->value(); + aCircleShape = GeomAlgoAPI_EdgeBuilder::lineCircle(aCenter, aNormal, aRadius, aValAn / 180 * PI); + + // Update corrdinates for point on circle + bool aWasBlocked = data()->blockSendAttributeUpdated(true); + GeomPnt2dPtr aCircleSewPoint = aSketch->to2D(aCircleShape->firstPoint()); + std::dynamic_pointer_cast(data()->attribute(ROTATE_ID())) + ->setValue(aCircleSewPoint->x(), aCircleSewPoint->y()); + data()->blockSendAttributeUpdated(aWasBlocked, false); + } + else + aCircleShape = GeomAlgoAPI_EdgeBuilder::lineCircle(aCenter, aNormal, aRadius); std::shared_ptr aResult = document()->createConstruction(data(), 1); aResult->setShape(aCircleShape); @@ -116,7 +157,37 @@ void SketchPlugin_Circle::attributeChanged(const std::string& theID) { std::shared_ptr aCenterAttr = std::dynamic_pointer_cast(attribute(CENTER_ID())); aCenterAttr->setValue(sketch()->to2D(aCirc->center())); + real(RADIUS_ID())->setValue(aCirc->radius()); + real(ANGLE_ID())->setValue(0); + } + } + else if (integer(VERSION_ID())->value() > SketchPlugin_Circle::THE_VERSION_0 && + theID == ROTATE_ID()) + { + // get cricle from results + std::shared_ptr aSelection; + ResultPtr aCircleRes = lastResult(); + if (aCircleRes) + aSelection = aCircleRes->shape(); + if (aSelection && !aSelection->isNull() && aSelection->isEdge()) { + std::shared_ptr anEdge(new GeomAPI_Edge(aSelection)); + std::shared_ptr aCirc = anEdge->circle(); + + // Get point and project it on line + std::shared_ptr aNewPntRot = + std::dynamic_pointer_cast(attribute(ROTATE_ID())); + GeomPointPtr aPntRot3D = aCirc->project( sketch()->to3D(aNewPntRot->x(), aNewPntRot->y())); + + // Compute new angle + GeomPointPtr aNorm = sketch()->to3D(real(RADIUS_ID())->value(), 0); + double aStartParam, anEndParam; + aCirc->parameter(aPntRot3D, 1.e-4, anEndParam); + aCirc->parameter(aNorm, 1.e-4, aStartParam); + + bool aWasBlocked = data()->blockSendAttributeUpdated(true); + real(ANGLE_ID())->setValue((anEndParam - aStartParam) / PI * 180.0); + data()->blockSendAttributeUpdated(aWasBlocked, false); } } } diff --git a/src/SketchPlugin/SketchPlugin_Circle.h b/src/SketchPlugin/SketchPlugin_Circle.h index c5035fba2..0f620d7a7 100644 --- a/src/SketchPlugin/SketchPlugin_Circle.h +++ b/src/SketchPlugin/SketchPlugin_Circle.h @@ -45,6 +45,20 @@ class SketchPlugin_Circle: public SketchPlugin_SketchEntity return ID; } + /// 2D point - rotate of the circle + inline static const std::string& ROTATE_ID() + { + static const std::string ID("circle_rotate"); + return ID; + } + + /// Contain created point as feature + inline static const std::string& ROTATE_REF_ID() + { + static const std::string ID("circle_rotate_point"); + return ID; + } + /// Radius of the circle inline static const std::string& RADIUS_ID() { @@ -52,6 +66,13 @@ class SketchPlugin_Circle: public SketchPlugin_SketchEntity return ID; } + /// Angle of rotation sewing point of the circle + inline static const std::string& ANGLE_ID() + { + static const std::string ID("circle_angle"); + return ID; + } + /// Returns the kind of a feature SKETCHPLUGIN_EXPORT virtual const std::string& getKind() { @@ -59,6 +80,16 @@ class SketchPlugin_Circle: public SketchPlugin_SketchEntity return MY_KIND; } + static const int THE_VERSION_0 = 0; + static const int THE_VERSION_1 = 20232206; + + /// Attribute name of the version of Circle feature + inline static const std::string& VERSION_ID() + { + static const std::string MY_VERSION_ID("version"); + return MY_VERSION_ID; + } + /// Returns true is sketch element is under the rigid constraint SKETCHPLUGIN_EXPORT virtual bool isFixed(); diff --git a/src/SketchPlugin/SketchPlugin_MacroCircle.cpp b/src/SketchPlugin/SketchPlugin_MacroCircle.cpp index 2725d0be9..4f107ebe5 100644 --- a/src/SketchPlugin/SketchPlugin_MacroCircle.cpp +++ b/src/SketchPlugin/SketchPlugin_MacroCircle.cpp @@ -23,10 +23,14 @@ #include "SketchPlugin_Point.h" #include "SketchPlugin_Tools.h" #include "SketchPlugin_MacroArcReentrantMessage.h" +#include +#include #include #include #include +#include +#include #include #include #include @@ -35,8 +39,10 @@ #include #include +#include #include #include +#include #include #include @@ -63,7 +69,8 @@ namespace { SketchPlugin_MacroCircle::SketchPlugin_MacroCircle() : SketchPlugin_SketchEntity(), - myRadius(0.0) + myRadius(0.0), + myAngle(0.0) { } @@ -84,17 +91,39 @@ void SketchPlugin_MacroCircle::initAttributes() data()->addAttribute(SECOND_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId()); data()->addAttribute(THIRD_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId()); + // Attrs for rotation point + data()->addAttribute(ROTATE_POINT_ID(), GeomDataAPI_Point2D::typeId()); + data()->addAttribute(ROTATE_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId()); + data()->addAttribute(CIRCLE_RADIUS_ID(), ModelAPI_AttributeDouble::typeId()); + data()->addAttribute(CIRCLE_ROTATE_ANGLE_ID(), ModelAPI_AttributeDouble::typeId()); data()->addAttribute(AUXILIARY_ID(), ModelAPI_AttributeBoolean::typeId()); - string(EDIT_CIRCLE_TYPE())->setValue(""); + // When circle create using addCircle command, angle is not define and new point nor create + // This lines must be removed when command for create circle without additional point will be removed from SHAPER + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), CIRCLE_ROTATE_ANGLE_ID()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), ROTATE_POINT_ID()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), ROTATE_POINT_REF_ID()); ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), CENTER_POINT_REF_ID()); ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PASSED_POINT_REF_ID()); 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(), THIRD_POINT_REF_ID()); ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EDIT_CIRCLE_TYPE()); + + // While exist addCircle without creating point. + AttributeIntegerPtr aVerAttr = std::dynamic_pointer_cast( + data()->addAttribute(VERSION_ID(), ModelAPI_AttributeInteger::typeId())); + aVerAttr->setIsArgument(false); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), VERSION_ID()); + if (!aVerAttr->isInitialized()) { + // this is a newly created feature (not read from file), + // so, initialize the latest version + aVerAttr->setValue(SketchPlugin_Circle::THE_VERSION_1); + } + + string(EDIT_CIRCLE_TYPE())->setValue(""); } void SketchPlugin_MacroCircle::execute() @@ -191,6 +220,12 @@ void SketchPlugin_MacroCircle::constraintsForCircleByCenterAndPassed(FeaturePtr SketchPlugin_Tools::createCoincidenceOrTangency( this, PASSED_POINT_REF_ID(), AttributePtr(), theCircleFeature->lastResult(), true); + + if (integer(VERSION_ID())->value() > SketchPlugin_Circle::THE_VERSION_0) + SketchPlugin_Tools::createCoincidenceOrTangency( + this, ROTATE_POINT_REF_ID(), + AttributePtr(), + theCircleFeature->lastResult(), false); } void SketchPlugin_MacroCircle::constraintsForCircleByThreePoints(FeaturePtr theCircleFeature) @@ -205,6 +240,66 @@ void SketchPlugin_MacroCircle::constraintsForCircleByThreePoints(FeaturePtr theC SketchPlugin_Tools::createCoincidenceOrTangency( this, aPointRef[i], AttributePtr(), aCircleResult, true); } + + if (integer(VERSION_ID())->value() > SketchPlugin_Circle::THE_VERSION_0) + SketchPlugin_Tools::createCoincidenceOrTangency( + this, ROTATE_POINT_REF_ID(), + AttributePtr(), + aCircleResult, false); +} + +void SketchPlugin_MacroCircle::computeNewAngle(std::shared_ptr& theCircle) +{ + if (integer(VERSION_ID())->value() < SketchPlugin_Circle::THE_VERSION_1) + return; + + AttributePtr aRotateAtr = attribute(ROTATE_POINT_ID()); + if (aRotateAtr->isInitialized()) + { + AttributeRefAttrPtr aRotRef = refattr(ROTATE_POINT_REF_ID()); + std::shared_ptr aRotPoit; + std::shared_ptr aTangentCurve; + SketchPlugin_Tools::convertRefAttrToPointOrTangentCurve( + aRotRef, aRotateAtr, aTangentCurve, aRotPoit); + + myRotPoint = theCircle->project(aRotPoit); + + std::shared_ptr aNorm(new GeomAPI_Pnt2d(myRadius, 0)); + double anEndParam, aStartParam; + theCircle->parameter(myRotPoint, 1.e-4, anEndParam); + theCircle->parameter(aNorm, 1.e-4, aStartParam); + myAngle = (anEndParam - aStartParam) / 3.14 * 180.0; + } + else + { + std::shared_ptr aRotPoit = + std::shared_ptr(new GeomAPI_Pnt2d(myCenter->x() + myRadius, myCenter->y())); + myRotPoint = theCircle->project(aRotPoit); + std::dynamic_pointer_cast(attribute(ROTATE_POINT_ID()))->setValue(myRotPoint); + myAngle = 0; + } +} + +static FeaturePtr CreatePoint(FeaturePtr theCircleFeature, + GeomPnt2dPtr thePoint) +{ + SketchPlugin_Sketch* aSketch = + std::dynamic_pointer_cast(theCircleFeature)->sketch(); + + // create point at sewing point of circle + FeaturePtr aPointFeature = aSketch->addFeature(SketchPlugin_Point::ID()); + aPointFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(theCircleFeature); + + AttributePoint2DPtr aCoord = std::dynamic_pointer_cast( + aPointFeature->attribute(SketchPlugin_Point::COORD_ID())); + aCoord->setValue(thePoint); + aPointFeature->execute(); + + SketchPlugin_Tools::createConstraintAttrAttr(aSketch, SketchPlugin_ConstraintCoincidenceInternal::ID(), + theCircleFeature->attribute(SketchPlugin_Circle::ROTATE_ID()), aCoord); + + theCircleFeature->reference(SketchPlugin_Circle::ROTATE_REF_ID())->setValue(aPointFeature); + return aPointFeature; } FeaturePtr SketchPlugin_MacroCircle::createCircleFeature() @@ -213,10 +308,23 @@ FeaturePtr SketchPlugin_MacroCircle::createCircleFeature() std::dynamic_pointer_cast( aCircleFeature->attribute(SketchPlugin_Circle::CENTER_ID()))->setValue(myCenter->x(), myCenter->y()); + if (integer(VERSION_ID())->value() > SketchPlugin_Circle::THE_VERSION_0) + { + aCircleFeature->real(SketchPlugin_Circle::ANGLE_ID())->setValue(myAngle); + } aCircleFeature->real(SketchPlugin_Circle::RADIUS_ID())->setValue(myRadius); + aCircleFeature->integer(SketchPlugin_Circle::VERSION_ID())->setValue(integer(VERSION_ID())->value()); aCircleFeature->boolean(SketchPlugin_Circle::AUXILIARY_ID()) ->setValue(boolean(AUXILIARY_ID())->value()); + aCircleFeature->execute(); + + if (integer(VERSION_ID())->value() > SketchPlugin_Circle::THE_VERSION_0) + { + // Create point + FeaturePtr aNPoint = CreatePoint(aCircleFeature, myRotPoint); + } + return aCircleFeature; } @@ -258,6 +366,8 @@ void SketchPlugin_MacroCircle::fillByCenterAndPassed() if (aCircle) { myCenter = aCircle->center(); myRadius = aCircle->radius(); + + computeNewAngle(aCircle); } } @@ -299,6 +409,8 @@ void SketchPlugin_MacroCircle::fillByThreePoints() if (aCircle) { myCenter = aCircle->center(); myRadius = aCircle->radius(); + + computeNewAngle(aCircle); } } @@ -356,25 +468,30 @@ void SketchPlugin_MacroCircle::fillByTwoPassedPoints() if (aCircle) { myCenter = aCircle->center(); myRadius = aCircle->radius(); + + computeNewAngle(aCircle); } } AISObjectPtr SketchPlugin_MacroCircle::getAISObject(AISObjectPtr thePrevious) { SketchPlugin_Sketch* aSketch = sketch(); - if(!aSketch || !myCenter || myRadius == 0) { + if (!aSketch || !myCenter || myRadius == 0) { return AISObjectPtr(); } // Compute a circle in 3D view. std::shared_ptr aCenter(aSketch->to3D(myCenter->x(), myCenter->y())); std::shared_ptr aNDir = - std::dynamic_pointer_cast( - aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID())); + std::dynamic_pointer_cast( + aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID())); std::shared_ptr aNormal = aNDir->dir(); - GeomShapePtr aCircleShape = GeomAlgoAPI_EdgeBuilder::lineCircle(aCenter, aNormal, myRadius); + GeomShapePtr aCircleShape = GeomAlgoAPI_EdgeBuilder::lineCircle(aCenter, aNormal, myRadius, + attribute(ROTATE_POINT_ID())->isInitialized() ? myAngle / 180 * 3.14 : 0); + GeomShapePtr aCenterPointShape = GeomAlgoAPI_PointBuilder::vertex(aCenter); - if(!aCircleShape.get() || !aCenterPointShape.get()) { + + if (!aCircleShape.get() || !aCenterPointShape.get()) { return AISObjectPtr(); } @@ -382,6 +499,18 @@ AISObjectPtr SketchPlugin_MacroCircle::getAISObject(AISObjectPtr thePrevious) aShapes.push_back(aCircleShape); aShapes.push_back(aCenterPointShape); + // For addCircle command skip creating point + if (integer(VERSION_ID())->value() > SketchPlugin_Circle::THE_VERSION_0) + { + std::shared_ptr aRotPoint; + if (myRotPoint.get()) + aRotPoint = std::shared_ptr(aSketch->to3D(myRotPoint->x(), myRotPoint->y())); + else + aRotPoint = std::shared_ptr(aSketch->to3D(myCenter->x() + myRadius, myCenter->y())); + GeomShapePtr aNewPnt = GeomAlgoAPI_PointBuilder::vertex(aRotPoint); + aShapes.push_back(aNewPnt); + } + std::shared_ptr aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes); AISObjectPtr anAIS = thePrevious; if(!anAIS.get()) { @@ -395,9 +524,25 @@ AISObjectPtr SketchPlugin_MacroCircle::getAISObject(AISObjectPtr thePrevious) return anAIS; } +namespace +{ + static bool isRotPoint(const std::string& theID, const std::string& theCurType, const std::string& theType) + { + return theCurType == theType + && (theID == SketchPlugin_MacroCircle::ROTATE_POINT_ID() || theID == SketchPlugin_MacroCircle::ROTATE_POINT_REF_ID()); + } +} + void SketchPlugin_MacroCircle::attributeChanged(const std::string& theID) { + std::shared_ptr aCircle; // If circle type switched reset all attributes. if(theID == CIRCLE_TYPE()) { + if (integer(VERSION_ID())->value() > SketchPlugin_Circle::THE_VERSION_0) + { + SketchPlugin_Tools::resetAttribute(this, ROTATE_POINT_ID()); + SketchPlugin_Tools::resetAttribute(this, ROTATE_POINT_REF_ID()); + } + SketchPlugin_Tools::resetAttribute(this, CENTER_POINT_ID()); SketchPlugin_Tools::resetAttribute(this, CENTER_POINT_REF_ID()); SketchPlugin_Tools::resetAttribute(this, PASSED_POINT_ID()); @@ -409,11 +554,13 @@ void SketchPlugin_MacroCircle::attributeChanged(const std::string& theID) { SketchPlugin_Tools::resetAttribute(this, THIRD_POINT_ID()); SketchPlugin_Tools::resetAttribute(this, THIRD_POINT_REF_ID()); } else if(theID == CENTER_POINT_ID() || theID == PASSED_POINT_ID() || - theID == CENTER_POINT_REF_ID() || theID == PASSED_POINT_REF_ID()) + theID == CENTER_POINT_REF_ID() || theID == PASSED_POINT_REF_ID() || + isRotPoint(theID, string(CIRCLE_TYPE())->value(), CIRCLE_TYPE_BY_CENTER_AND_PASSED_POINTS())) fillByCenterAndPassed(); else if(theID == FIRST_POINT_ID() || theID == FIRST_POINT_REF_ID() || theID == SECOND_POINT_ID() || theID == SECOND_POINT_REF_ID() || - theID == THIRD_POINT_ID() || theID == THIRD_POINT_REF_ID()) { + theID == THIRD_POINT_ID() || theID == THIRD_POINT_REF_ID() || + isRotPoint(theID, string(CIRCLE_TYPE())->value(), CIRCLE_TYPE_BY_THREE_POINTS())) { std::shared_ptr aPoints[3]; int aNbInitialized = 0; for(int i = 1; i <= 3; ++i) { @@ -432,12 +579,29 @@ void SketchPlugin_MacroCircle::attributeChanged(const std::string& theID) { } AttributeDoublePtr aRadiusAttr = real(CIRCLE_RADIUS_ID()); + bool aWasBlocked = data()->blockSendAttributeUpdated(true); if(myCenter.get()) { // center attribute is used in processEvent() to set reference to reentrant arc std::dynamic_pointer_cast(attribute(CENTER_POINT_ID())) ->setValue(myCenter); } + + if (integer(VERSION_ID())->value() > SketchPlugin_Circle::THE_VERSION_0) + { + AttributeDoublePtr anAngleAttr = real(CIRCLE_ROTATE_ANGLE_ID()); + + if (myRotPoint.get()) + { + AttributePoint2DPtr aPointAttr = std::dynamic_pointer_cast(attribute(ROTATE_POINT_ID())); + aPointAttr->setValue(myRotPoint); + } + + if (anAngleAttr->isInitialized()) + anAngleAttr->setValue(myAngle); + } + aRadiusAttr->setValue(myRadius); + data()->blockSendAttributeUpdated(aWasBlocked, false); } diff --git a/src/SketchPlugin/SketchPlugin_MacroCircle.h b/src/SketchPlugin/SketchPlugin_MacroCircle.h index c810eb061..d5b45c59f 100644 --- a/src/SketchPlugin/SketchPlugin_MacroCircle.h +++ b/src/SketchPlugin/SketchPlugin_MacroCircle.h @@ -87,6 +87,19 @@ class SketchPlugin_MacroCircle: public SketchPlugin_SketchEntity, return ID; } + /// 2D point - center of the circle. + inline static const std::string& ROTATE_POINT_ID() + { + static const std::string ID("rotate_point"); + return ID; + } + + /// Reference for center point selection. + inline static const std::string& ROTATE_POINT_REF_ID() + { + static const std::string ID("rotate_point_ref"); + return ID; + } /// 2D point - passed point of the circle inline static const std::string& PASSED_POINT_ID() { @@ -150,6 +163,21 @@ class SketchPlugin_MacroCircle: public SketchPlugin_SketchEntity, return ID; } + /// Rotate angle of the circle + inline static const std::string& CIRCLE_ROTATE_ANGLE_ID() + { + static const std::string ID("circle_angle"); + return ID; + } + + /// Attribute name of the version of Circle feature + /// Need for compability with old way of creating circle + inline static const std::string& VERSION_ID() + { + static const std::string MY_VERSION_ID("version"); + return MY_VERSION_ID; + } + /// Returns the kind of a feature SKETCHPLUGIN_EXPORT virtual const std::string& getKind() { @@ -191,11 +219,15 @@ private: void constraintsForCircleByCenterAndPassed(FeaturePtr theCircleFeature); void constraintsForCircleByThreePoints(FeaturePtr theCircleFeature); + void computeNewAngle(std::shared_ptr& theCircle); + FeaturePtr createCircleFeature(); private: std::shared_ptr myCenter; + std::shared_ptr myRotPoint; double myRadius; + double myAngle; }; #endif diff --git a/src/SketchPlugin/Test/TestCreateCircleByCenterAndPassed.py b/src/SketchPlugin/Test/TestCreateCircleByCenterAndPassed.py index 14c3c554e..7e5ba93c0 100644 --- a/src/SketchPlugin/Test/TestCreateCircleByCenterAndPassed.py +++ b/src/SketchPlugin/Test/TestCreateCircleByCenterAndPassed.py @@ -33,7 +33,7 @@ from SketchAPI import SketchAPI_Sketch from salome.shaper import model import math -__updated__ = "2017-03-22" +__updated__ = "2023-06-28" #========================================================================= @@ -68,6 +68,13 @@ def verifyTangentCircleLine(theCircle, theLine): aDistCL = model.distancePointLine(aCenter, theLine) assert math.fabs(aDistCL - aRadius) < TOLERANCE, "Circle and line are not tangent" +#========================================================================= +# Set old version of Circle for avoid create point. +#========================================================================= +def setVersionOfCircle(theCircle, theVersion): + aCircleVersion = theCircle.integer("version") + assert (type(aCircleVersion) == ModelAPI_AttributeInteger) + aCircleVersion.setValue(theVersion) #========================================================================= # Start of test @@ -100,6 +107,7 @@ aCircleCenter = geomDataAPI_Point2D(aCircle.attribute("circle_center")) assert (not aCircleCenter.isInitialized()) aCircleRadius = aCircle.real("circle_radius") assert (type(aCircleRadius) == ModelAPI_AttributeDouble) +setVersionOfCircle(aCircle, 0) # ModelAPI_AttributeDouble.typeId() is checked in ModelAPI_TestConstants assert (aCircleRadius.attributeType() == ModelAPI_AttributeDouble.typeId()) aCircleCenter.setValue(-25., -25) @@ -133,6 +141,7 @@ assert (not aCirclePassed.isInitialized()) aCircleType = aCircle.string("circle_type") assert (not aCircleType.isInitialized()) aCircleType.setValue("circle_type_by_center_and_passed_points") +setVersionOfCircle(aCircle, 0) aCircleCenter.setValue(-25., -25) aCirclePassed.setValue(0., -25.) aRadius = model.distancePointPoint(aCircleCenter, aCirclePassed) @@ -166,6 +175,7 @@ aCircleType = aCircle.string("circle_type") assert (not aCircleType.isInitialized()) # initialize attributes aCircleType.setValue("circle_type_by_center_and_passed_points") +setVersionOfCircle(aCircle, 0) aCenterRef.setObject(aPoint.lastResult()) aCenter.setValue(aPointCoord.pnt()) aPassedRef.setAttr(aPrevCenter) @@ -205,6 +215,7 @@ aPassedRef = aCircle.refattr("passed_point_ref") aCircleType = aCircle.string("circle_type") # initialize attributes aCircleType.setValue("circle_type_by_center_and_passed_points") +setVersionOfCircle(aCircle, 0) aCenterRef.setObject(aLine.lastResult()) anExpectedCenter = [(aLineStart[0] + aLineEnd[0]) * 0.5, (aLineStart[1] + aLineEnd[1]) * 0.5] aCenter.setValue(anExpectedCenter[0], anExpectedCenter[1]) @@ -239,6 +250,7 @@ aPassedRef = aCircle.refattr("passed_point_ref") aCircleType = aCircle.string("circle_type") # initialize attributes aCircleType.setValue("circle_type_by_center_and_passed_points") +setVersionOfCircle(aCircle, 0) anExpectedCenter = [(aLineStart[0] + aLineEnd[0]) * 0.5 + 10., (aLineStart[1] + aLineEnd[1]) * 0.5] aCenter.setValue(anExpectedCenter[0], anExpectedCenter[1]) aPassedRef.setObject(aLine.lastResult()) @@ -268,6 +280,7 @@ aPassedRef = aCircle.refattr("passed_point_ref") aCircleType = aCircle.string("circle_type") # initialize attributes aCircleType.setValue("circle_type_by_center_and_passed_points") +setVersionOfCircle(aCircle, 0) aCenterRef.setObject(aLine.lastResult()) aCenter.setValue(anExpectedCenter[0], anExpectedCenter[1]) aPassedRef.setObject(aLine.lastResult()) @@ -280,6 +293,37 @@ aDocument.removeFeature(aCircle) aSession.finishOperation() assert (aSketchFeature.numberOfSubs() == 12) +#========================================================================= +# Test 6. Create a circle with point on circle line (addCircleWithPoint) +#========================================================================= +# create new circle +aSession.startOperation() +aCircle = aSketchFeature.addFeature("SketchMacroCircle") +aCenter = geomDataAPI_Point2D(aCircle.attribute("center_point")) +aCenterRef = aCircle.refattr("center_point_ref") +aPassed = geomDataAPI_Point2D(aCircle.attribute("passed_point")) +aPassedRef = aCircle.refattr("passed_point_ref") +aCircleType = aCircle.string("circle_type") +aCircleAngle = aCircle.real("circle_angle") +# initialize attributes +aCircleType.setValue("circle_type_by_center_and_passed_points") +setVersionOfCircle(aCircle, 20232206) +aCenter.setValue(35., -35) +anExpectedCenter = [35., -35] +aPassed.setValue(45., -35) +aCircleAngle.setValue(90.) +anExpectedRot = [45., -35] +aSession.finishOperation() +assert (aSketchFeature.numberOfSubs() == 15) +# verify newly created circle +aCircle = model.lastSubFeature(aSketchFeature, "SketchCircle") +aCenter = geomDataAPI_Point2D(aCircle.attribute("circle_center")) +aRotPoint = geomDataAPI_Point2D(aCircle.attribute("circle_rotate")) +model.assertPoint(aCenter, anExpectedCenter) +model.assertPoint(aRotPoint, anExpectedRot) +model.testNbSubFeatures(aSketch, "SketchConstraintCoincidence", 3) +model.testNbSubFeatures(aSketch, "SketchConstraintTangent", 2) + #========================================================================= # End of test #========================================================================= diff --git a/src/SketchPlugin/Test/TestCreateCircleByThreePoints.py b/src/SketchPlugin/Test/TestCreateCircleByThreePoints.py index 29c2f1988..4c8a5cdfd 100644 --- a/src/SketchPlugin/Test/TestCreateCircleByThreePoints.py +++ b/src/SketchPlugin/Test/TestCreateCircleByThreePoints.py @@ -33,7 +33,7 @@ from SketchAPI import SketchAPI_Sketch from salome.shaper import model import math -__updated__ = "2017-03-22" +__updated__ = "2023-06-28" #========================================================================= @@ -82,6 +82,13 @@ def verifyTangentCircleLine(theCircle, theLine): aDistCL = model.distancePointLine(aCenter, theLine) assert math.fabs(aDistCL - aRadius) < TOLERANCE, "Circle and line are not tangent" +#========================================================================= +# Set old version of Circle for avoid create point. +#========================================================================= +def setOldVersionOfCircleFeature(theCircle): + aCircleVersion = theCircle.integer("version") + assert (type(aCircleVersion) == ModelAPI_AttributeInteger) + aCircleVersion.setValue(0) #========================================================================= # Start of test @@ -121,6 +128,7 @@ assert (not aCirclePnt3.isInitialized()) aCircleType = aCircle.string("circle_type") assert (not aCircleType.isInitialized()) aCircleType.setValue("circle_type_by_three_points") +setOldVersionOfCircleFeature(aCircle) aCirclePnt1.setValue(expectedCenter[0] - expectedRadius, expectedCenter[1]) aCirclePnt2.setValue(expectedCenter[0] + expectedRadius, expectedCenter[1]) aCirclePnt3.setValue(expectedCenter[0], expectedCenter[1] + expectedRadius) @@ -162,6 +170,7 @@ aCirclePnt3Ref = aCircle.refattr("third_point_ref") aCircleType = aCircle.string("circle_type") # initialize attributes aCircleType.setValue("circle_type_by_three_points") +setOldVersionOfCircleFeature(aCircle) aCirclePnt1Ref.setAttr(aPrevCenter) aCirclePnt1.setValue(aPrevCenter.pnt()) aCirclePnt2Ref.setObject(aPoint.lastResult()) @@ -209,6 +218,7 @@ aCirclePnt1Ref = aCircle.refattr("first_point_ref") aCirclePnt2Ref = aCircle.refattr("second_point_ref") aCirclePnt3Ref = aCircle.refattr("third_point_ref") aCircleType = aCircle.string("circle_type") +setOldVersionOfCircleFeature(aCircle) # initialize attributes aCircleType.setValue("circle_type_by_three_points") aCirclePnt1Ref.setObject(aPrevCircle.lastResult()) @@ -248,6 +258,7 @@ aCirclePnt3Ref = aCircle.refattr("third_point_ref") aCircleType = aCircle.string("circle_type") # initialize attributes aCircleType.setValue("circle_type_by_three_points") +setOldVersionOfCircleFeature(aCircle) aCirclePnt1Ref.setAttr(aStartPnt) aCirclePnt1.setValue(aStartPnt.pnt()) aCirclePnt2Ref.setAttr(aEndPnt) @@ -279,6 +290,7 @@ aCirclePnt3Ref = aCircle.refattr("third_point_ref") aCircleType = aCircle.string("circle_type") # initialize attributes aCircleType.setValue("circle_type_by_three_points") +setOldVersionOfCircleFeature(aCircle) aCirclePnt1.setValue(aLineStart[0] + aDistanceFromLine, aLineStart[1]) aCirclePnt2.setValue(aLineStart[0] - aDistanceFromLine, aLineStart[1]) aCirclePnt3Ref.setObject(aLine.lastResult()) @@ -324,6 +336,7 @@ aCirclePnt3Ref = aCircle.refattr("third_point_ref") aCircleType = aCircle.string("circle_type") # initialize attributes aCircleType.setValue("circle_type_by_three_points") +setOldVersionOfCircleFeature(aCircle) aCirclePnt1.setValue(0, 0) aCirclePnt2Ref.setObject(SketchLine_1.feature().lastResult()) aCirclePnt2.setValue(SketchLine_1.startPoint().x(), SketchLine_1.startPoint().y()) @@ -353,6 +366,7 @@ aCirclePnt3Ref = aCircle.refattr("third_point_ref") aCircleType = aCircle.string("circle_type") # initialize attributes aCircleType.setValue("circle_type_by_three_points") +setOldVersionOfCircleFeature(aCircle) aCirclePnt1.setValue(0, 0) aCirclePnt2Ref.setObject(SketchCircle_3.feature().lastResult()) aCirclePnt2.setValue(40, 0) @@ -382,6 +396,7 @@ aCirclePnt3Ref = aCircle.refattr("third_point_ref") aCircleType = aCircle.string("circle_type") # initialize attributes aCircleType.setValue("circle_type_by_three_points") +setOldVersionOfCircleFeature(aCircle) aCirclePnt1.setValue(0, 0) aCirclePnt2Ref.setObject(SketchLine_3.feature().lastResult()) aCirclePnt2.setValue(30, 0) @@ -411,6 +426,7 @@ aCirclePnt3Ref = aCircle.refattr("third_point_ref") aCircleType = aCircle.string("circle_type") # initialize attributes aCircleType.setValue("circle_type_by_three_points") +setOldVersionOfCircleFeature(aCircle) aCirclePnt1Ref.setObject(SketchLine_1.feature().lastResult()) aCirclePnt1.setValue(20, 0) aCirclePnt2Ref.setObject(SketchLine_2.feature().lastResult()) @@ -442,6 +458,7 @@ aCirclePnt3Ref = aCircle.refattr("third_point_ref") aCircleType = aCircle.string("circle_type") # initialize attributes aCircleType.setValue("circle_type_by_three_points") +setOldVersionOfCircleFeature(aCircle) aCirclePnt1Ref.setObject(SketchLine_1.feature().lastResult()) aCirclePnt1.setValue(20, 0) aCirclePnt2Ref.setObject(SketchLine_2.feature().lastResult()) @@ -473,6 +490,7 @@ aCirclePnt3Ref = aCircle.refattr("third_point_ref") aCircleType = aCircle.string("circle_type") # initialize attributes aCircleType.setValue("circle_type_by_three_points") +setOldVersionOfCircleFeature(aCircle) aCirclePnt1Ref.setObject(SketchCircle_1.feature().lastResult()) aCirclePnt1.setValue(10, 0) aCirclePnt2Ref.setObject(SketchCircle_2.feature().lastResult()) @@ -489,6 +507,44 @@ verifyTangentCircles(aCircle, SketchCircle_3.feature()) model.testNbSubFeatures(Sketch_1, "SketchConstraintCoincidence", 0) model.testNbSubFeatures(Sketch_1, "SketchConstraintTangent", 15) +#========================================================================= +# Test 12. Create a circle with point on circle line (addCircleWithPoint) +#========================================================================= +# create new circle +aSession.startOperation() +aCircle = aSketchFeature.addFeature("SketchMacroCircle") +aCirclePnt1 = geomDataAPI_Point2D(aCircle.attribute("first_point")) +aCirclePnt2 = geomDataAPI_Point2D(aCircle.attribute("second_point")) +aCirclePnt3 = geomDataAPI_Point2D(aCircle.attribute("third_point")) +aCirclePnt1Ref = aCircle.refattr("first_point_ref") +aCirclePnt2Ref = aCircle.refattr("second_point_ref") +aCirclePnt3Ref = aCircle.refattr("third_point_ref") +aCircleType = aCircle.string("circle_type") +aCircleAngle = aCircle.real("circle_angle") +# initialize attributes +aCircleType.setValue("circle_type_by_three_points") +aCirclePnt1Ref.setObject(SketchCircle_1.feature().lastResult()) +aCirclePnt1.setValue(20, 0) +aCirclePnt2Ref.setObject(SketchCircle_2.feature().lastResult()) +aCirclePnt2.setValue(40, 20) +aCirclePnt3Ref.setObject(SketchCircle_3.feature().lastResult()) +aCirclePnt3.setValue(50, 0) +aCircleAngle.setValue(180.) +anExpectedRot = [60.853417638885404, 4.3837725517883515] +aSession.finishOperation() +assert (aSketchFeature.numberOfSubs() == 33) +# verify newly created circle +aCircle = model.lastSubFeature(aSketchFeature, "SketchCircle") +aCenter = geomDataAPI_Point2D(aCircle.attribute("circle_center")) +aRotPoint = geomDataAPI_Point2D(aCircle.attribute("circle_rotate")) +model.assertPoint(aCenter, [35.2879593663427, 5.1151837465370855]) +model.assertPoint(aCirclePnt1, [20, 0]) +model.assertPoint(aCirclePnt2, [40, 20]) +model.assertPoint(aCirclePnt3, [50., 0.]) +model.assertPoint(aRotPoint, anExpectedRot) +model.testNbSubFeatures(aSketch, "SketchConstraintCoincidence", 3) +model.testNbSubFeatures(aSketch, "SketchConstraintTangent", 3) + #========================================================================= # End of test #========================================================================= diff --git a/src/SketchPlugin/Test/TestCreateCircleChangeType.py b/src/SketchPlugin/Test/TestCreateCircleChangeType.py index 803561bfc..c3bfdf523 100644 --- a/src/SketchPlugin/Test/TestCreateCircleChangeType.py +++ b/src/SketchPlugin/Test/TestCreateCircleChangeType.py @@ -181,7 +181,7 @@ aPassedPoint.setValue(aLineEnd.pnt()) aSession.finishOperation() aRadius = model.distancePointPoint(aLineStart, aLineEnd) -NB_FEATURES_EXPECTED = 4 # line, circle and two coincidences +NB_FEATURES_EXPECTED = 6 # line, circle, point on circle and three coincidences assert (aSketchFeature.numberOfSubs() == NB_FEATURES_EXPECTED), "Number of features in sketch {}, expected {}".format(aSketchFeature.numberOfSubs(), NB_FEATURES_EXPECTED) verifyLastCircle(aSketchFeature, aLineStart.x(), aLineStart.y(), aRadius) diff --git a/src/SketchPlugin/Test/TestMoveCircle.py b/src/SketchPlugin/Test/TestMoveCircle.py index b48900e2b..0bdcdbf10 100644 --- a/src/SketchPlugin/Test/TestMoveCircle.py +++ b/src/SketchPlugin/Test/TestMoveCircle.py @@ -35,7 +35,7 @@ class TestMoveCircle(unittest.TestCase): self.myCenter = [70., 50.] self.myRadius = 20. self.myCircle = self.mySketch.addCircle(self.myCenter[0], self.myCenter[1], self.myRadius) - self.myDOF = 3 + self.myDOF = 5 model.do() self.checkDOF() diff --git a/src/SketchPlugin/doc/circleFeature.rst b/src/SketchPlugin/doc/circleFeature.rst index b729a6d4d..fa24e9e29 100644 --- a/src/SketchPlugin/doc/circleFeature.rst +++ b/src/SketchPlugin/doc/circleFeature.rst @@ -3,7 +3,7 @@ Circle ====== -The feature Circle creates a circle in the current Sketch. +The feature Circle creates a circle and point on line in the current Sketch. To add a new Circle to the Sketch: @@ -32,14 +32,31 @@ By center and passed point .. figure:: images/Circle_panel_pt_rad.png :align: center -Click in the view once to set the center point, then move the mouse and click a second time to set the passed point. +Click in the view once to set the center point, then move the mouse and click a second time to set the passed point and finally +click third time to set point on the line. - When entering a center point by selecting either a point or a segment, a Coincident constraint is created. - When entering a passing point by selecting a point, a Coincident constraint is also created. - When entering a passing point by selecting a segment, a Tangent constraint is created. +- Point on the line show sewing point for circle. If rotate this point, sewing point also will be changed + **TUI Command**: +.. py:function:: Sketch_1.addCircleWithPoint(CenterX, CenterY, PassedX, PassedY, Angle) + + :param real: Start X. + :param real: Start Y. + :param real: Passed X. + :param real: Passed Y. + :param real: Rotation angle for sewing point + :return: Result object. + +.. py:function:: SketchCircle_1.createdPoint() + :return: Created point on circle line + +This method is deprecated, please, use addCircleWithPoint + .. py:function:: Sketch_1.addCircle(CenterX, CenterY, PassedX, PassedY) :param real: Start X. @@ -55,13 +72,31 @@ By three points :align: center Click in the view once to set the first passed point, then move the mouse and click a second time to set the second passed point -and finally move the mouse and click a third time to set the last passed point. +then move the mouse and click a third time to set the last passed point, and finally +click last time to set point on the line. - When entering a passing point by selecting a point, a Coincident constraint is created. - When entering a passing point by selecting a segment, a Tangent constraint is created. +- Point on the line show sewing point for circle. If rotate this point, sewing point also will be changed **TUI Command**: +.. py:function:: Sketch_1.addCircleWithPoint(X1, Y1, X2, Y2, X3, Y3, Angle) + + :param real: Start X. + :param real: Start Y. + :param real: Passed X. + :param real: Passed Y. + :param real: End X. + :param real: End Y. + :param real: Rotation angle for sewing point + :return: Result object. + +.. py:function:: SketchCircle_1.createdPoint() + :return: Created point on circle line + +This method is deprecated, please, use addCircleWithPoint + .. py:function:: Sketch_1.addCircle(X1, Y1, X2, Y2, X3, Y3) :param real: Start X. diff --git a/src/SketchPlugin/doc/images/Circle_panel_3pt.png b/src/SketchPlugin/doc/images/Circle_panel_3pt.png index c837accbf164d852ace07cf9f9ddec1359b363b0..88b1cfbc7d42fae8719ef7ed3a6b016426dfc124 100644 GIT binary patch literal 15489 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 literal 21622 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 Paw?#rpb0LPxBT#5g1v`I literal 10400 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 P6XE2g!JtY>lc4_(-dxXE literal 19105 zcmeFZWmpu@zAro$ArgupjkI(Oozl|XB_JT(T`H-xbc1wvmq^#pozmT1a~FHx^PaQc zyU+99_uKt&ee_YrVP?&W|NmEu@A9(ZsL%19Lm&`Ti4P)*5Xd7M@aHEI0(e9@BbWpH z_0(QSLKzAC@<93&2);(P`JiDBfuK=>?}0x$R9ZWMK;A+mLqnrHe}~CYEF39*>jF;gCLe^Hh3cs1A6ih^VN3d&kr#Z@IY>1VV{~2k#J( z$7ry0xSfr=V99>h%I78hoid3-+oujYGgw~+w5mU5s}2{K$W;qWbmgXv?3{Vrcf>jz zEQAbah^>0-7HO*Zqu*HHdkc7NO?v-+KT~Ns5Dzt}^SFAhL@Af)xT8v^UK{9xi2gGn zL9FWy&tWTKMrn05L*-&{@QY@hL&BR2;h&e1p^tPC&ri8m!-z@+~wsJKXx-7E1N<8l;|1Fh7v-20|Jzq+#HofEv%L0{Q?%r zxw-w->YbRc-g@0RLiGj{1n27q(^U&_xwfAu?q@N1FKExrX-`+Vqf^Nx|FTSE_q&!& zxn-W_;<~+TGe}Az(73$|3%*|xR=vN)G^@J(NbUP7GdtUEcTm9A(Xpem(;sRAGstGA zEerF>Ak)#?|5I%_i;Rl$Bu(r+M5o@Nvvs&^=v?gCcruSO#KwJfJ*Eud#isb(^%*2E zBxG%=RoLR*lB~J88FIQmUeWDkYkRai>-|NCr{?eaI>PVnmu;r_Q=vN?R`N}nY>^wJ zzVE!bxVTnV*GKXU#Ua%PQ$53mT^}SR8EQOnu#{mi7=*mNYh~-N{s>wlFW(6qzPX7r zX2! zFs;)y&T3_dw7xFqg>*%wW9o+|y(*Ag`Qdyc6q*|~hUze)p`FUho14+KtXRlYQfz>3 zPFAk-b?|eVXvvOt&yAdjXkWX<%ZEZL_Gmmd)lgqwzkkdR zLoQtEnMtuui)>dYYM=pv3~x(p!!M|TAr-Pl+j%&F?bki%t<`zxw`xYMJ9CXS^3 zLTTOIp|8Wq;@EY2IjPbsH^g2ar%Ep*BxSQT$Matha*GH_BKd7DH1TNFSgdsuiw9Xa z+m+_H*I0>Oa2*E>dn$K@5smao^#}zj4)65z!US_hv8M}F6ZMTu6_&8WsXd9BqY87K z?|d=5p)^>ksxfknVZ6cQzVf`tG$g*u67t9-ujRf;BBi^$QWiq$pgk=}6@E6lxPd7Y zc+6tgZo_}&V)u3MhX=1ci*+I|MeT7S6B&ijl5Q!l%+c&NE=onc2sOn-XQYe zsg|?{$!xFe?Ek3K=ots^-y4w}+Xm}v`I+Du2CH&YY@Mi5URhmROCRVH&Qi@7{w$yO z{0-K`&e`fGlgPx#fUIaNJd_pE?##5_-X8snyo$mp&!`{#&12?ck3%|>Do-7Rth9{| zrpFtnnZwik9ZSoH;#ev%mT`x+94wk@Q_K^X`sW8O4d5cijye{{oON}s1k=uev|3I} z>OHY(f_I0fHnj3A+6Cjbv@Ac`XjLOIUrKby5^fIN8D;$G-Ao(Va?q~F?Wh;d**g3a z#L3NV!*$Byd_b;$u=F8uy{InHE^HhTp7tvd>PT}Vsbf#_nqk}ODMxw9-{tk-&XJ$* zDgqTlA|sP!raBj|4o7gU{B;bxt%wHnh`-dt@)#Q%ubNhg_=?-CZ&W$JSD3IWSmJ_y z?8@#9t54w)EN+tb^uzv!p`=f7aT=H!^^_Tkm-aV{ce#z1P8!)Qw=3|@&Dq+YkdxCT z?as|95|&~tZ*_M|m|TP`mK~S=8R`8I*Zvu=q2}GVI$j9Z#6n8Dx`q-pS@Hzp1!lP! zYDC2Fr?u5rUi3+{1rwMKyXZ8=MmDp(2vC94g0JX zH@E!sXtEIxdPGdjkBkhc^TOet1m0j1i-=HX&hPgMDnq8{y%pDScB@iLt$R z+-$l2Vq_P&zAmc8?Wt7kWC-T=`1xFuzdI(1-n&cpTEgb}eEcd9peXiMIt>yV`Fy1l zQ&DE#W>t9b{ODoy?Jk9?1Y>WaEHTaJ*LOEu-q$Ze_9+!8_@eQv&yy^s6A+%K28_QYEcdU4#q++E@#io9iLFOZAV7>7{4m!T7_2Ml!5IEjAtSR zj%%-G-(P9mo;jB-JkBtsG4tfYdyR+igbJ5^t9Gg(JUr@43*{GXqBGRuF11(oP-wn# z!MA2TM%e;+*|?W(E`ivsqir#li9aLKrMTyOM-G3SPZtgMQQQ!WNE zDuo6o&z}c#f30@uuMybWx&{U|GhYiuwPf}`_3*qq%-w7qXe_vO-NE2;y*R+vlWP=G zmVFAq3Fr{viBU56E$34>wo0=Y_V)I-`Kq1y8c-Oo`cmtQp+~K<3{%xsUrW3xB8l~B z9OXqjscer_3B027?JgE{_B-c)xd-{P7AibL3E>r|Xs;M+ZGqO1kqv)l<*engV_u=7 zB7?srp%1Na{?=30(>gQbe;J2^S6BVJZ@58Qmf^Tk(`vC^rZewjic}rq96B|YJjWUu zb&f11K4H*AyZcmDGryFy1c_9^pNYH+=P@~RD2#-wM9tB5C`XMIon@$r?C%G={?P!w{-?=WwywhXQK2Rn(BFj zx%n=xLlxsEt7a!Q-@ACvShhGDu98haCD zYr4@SJaM1aHx_G&fHRvV!xRS(jV*ZHzYVT@K6o!?OsUI&mAkpFIP=#RV@Ek|)eocP>`B)$Mh`Ca`zd={1l()2d|;?A+z; z>LFJkUZkFNw&xmOCMR;xSUQumD`hf|$`3ZYJZnsyYtfLBlA=Rx ze3hYEP*zzEDs*L8R^wL;p(B8g((4E^clw-(V_za+j3Ev-~!LtHX3}YI^Bmh(1Ney0P`4t6R0zpWo+}LvgXT(MC-RxfS_MIYO5PTarR#q>oA~%Cbf0xmk+| z-&g%un3|qRQ_cG@*t;&K%xY4syV4zxGWR27Ba&DR<9z-?x&ilxk|s@kDB&nP0-?j^@Tgy6L*9L$@uIKaeSRV6q}n6vaRR!s41lpPS1GO=!elkd-rqyLNUJ40+qvX z#kRCc|5FJ=WvrZsFMB_gitO>(T}U6`)nTx6v=iS zYFr5SPPe9Dr3SCeFO+;tXJ)LHv-KV;*4bc_s_!OyBW**%YD=FS% ztA=CsaloKn>+pnsp3hCfsmr4;G*pNieC}mD_6QA7ld^hOOrp7+M=qA{z0Z^C`_}?z z3%P89C%G$`O>f101U>&gj`6%nuXhY$rom!YF(0|yVRLDyi{j$7TO^jCQzVN2_XSt_8j!{nMcHYLBqj#A=?x5kTEyDwql*^dmodc z-nGFQyyR43-C~A*xD5_X^bgkpj-N3R)F#S8QDl+dwl55GBx>Em{Ks!i6*J88oZ=>O zNxt*Bzn+d6DW`A?@s}jBa@m}7RvOFR>3QHqkE1R1>DBz3dpu|Pn~Bf; z1JiHpzVa4LY?htfI$}po<{7q%nVTQaR5G+c^SkalUu^rtYYy}#-wg4)l}P@S3}j*E z&IJ$_<7MoZk_MDV{JL2S>6Fypw+|YFD5;Uhy!Uji^#vvSu&>~I%OB-@@}nOP@?3~k z=fP6MQXmmW3h`aO-7M^p<;nV|LcIW3*T(l}(JeJpA?7MnTe{C%)r#*Or>SDSgrdF= z3p(zO+y!uJjnUj0B4G~?KW)6Twh$5?o}RMtoRC(;7eIe68A`XrHB@JV5z3s#peJ`1d`dXmV?Mt9-EXX|0AcbWjJ>Qdg{uo5Y&Q1 zRkfb=5hHEDcj+je1*}jpwb%#nii;O}Ljz9h2P0-OnVX@;b~QQ;LZ0|4Eqd4#tofT} z$fB;NPboQ1xgnPLW1ePIY?gRqPgDgsGp@~Lg#t&Q57Tt;Sbn(ZuqkVKDuqY<_v}HM z+bWS#aU#BcPz%}YAUY(uitQz_9Cdk1Lj@V0{R1_?X&MwC{77oB0?A$8I~#+U-SW;2 z#Udnmn$o0Lph9^k zJSlLjXt&@)H9IiSpR&zpjc1SQs;P6&zosTY(%ZQ?R#x2zum9ktI$V|g;}yr}x2{%{<)9O4WKsRqGlw zYm3Z@&$UrrADbd8>4u=v$hS5k7ied2imQUfhz?=!6;G)2;iaN_Q-0`Od?$%JRc5$Wjv>ri22!z{JX!t3Fwp z${M0#kMAOEaDiXt8CMnH&TkA;jcQGnJo&w#WRjvOPk4L63KpIBVsgVS?BPUQkCeEH z%FPk%AqNGM+{2m_o5C%AfWs>5rz37?1v_~}Ne4aa&eFTvR%y7>jAYhHr+0l zgng0zj}wf*I4gUkbv_YKg$nN2LzM%{!uMelWl$)7BRCFio!vHW97ZN#LJ~uh-qJ&Z zve^m}lqJ`PEAXo%MFTofyGPA5%3U`wd4fg=_=D#wO>-3$hc?d|UpeEaK3l||5<^mO zqil+rtFg4VD59Ij_ee=BJCZY#os;SNc$Y4qP@w$6i+L!sIV_;NMR&`$b1o^m;T#h; z_E6+oFE3~95HBm0tmMPik$z5tsD%$GnRw3RNk_g+rhp4lCGXa$n{mmk5Lhur_TsSA zfC7m-V)U1CZ%hyzK1-#j_El2Q_6+pVUZnM!PL&Sv+TpW?Ka}}6?H{!!JI2Z-n-ZTq zUg?$G5$bTk$+XKY8L5Oz{_gK~CuUJoWiZ}qkIt4j{F$wKOvMnuY(DO9=WS)?>c)_& zS|VIuhtS{Oy+8DI>}X|`i-x54dyk+|IhJAwyWZV3SQ{6|-y7FPO`&W#QHOT}@e8`KPlK;eMSPtyVV$qf4!t1EdNy>t!A| zp2cEieB2N%Ilb18iB>^auJ1dlEKR@cZ%u@ex;uVNRaoK-+WP&!Qf1t1FKwMiN8-yZ zP|eYagbl4aYaj7R>YPZHFme~>U%8x2&z2Zk8F!Xjy5sO2h$})-VqdVIGjcG7F{%}= zoTN^qjc?)br6JO9Pl}o7E3}_y-JAJhM6u*T%q~?|6ZM4;Pi)rQ9O&RFO>wS?)rrb0 zygVGSRfu6n6aAt|XboR8icnKq&dlOt7DkjjYM-*ZgmxGPD6}qw`k25@dZ*;nt1UUW z>gvQ0qhxaoCwnm5am)^u%zkywND+F_!ZVdArs99G{Vg%W zQzQG+p<;p8crRTl=g;qpB}=yVg0=v<38VHX$E&uLfNJ>#+xkHziP_cgnAm?Ywcm2$OGywQEk=vK==P z&=Mns^)$C!O;NdKmmL+-idf`=O>56XoTFKi8s#NfKHVqB*9cEVnIRh;c5&aH?=%%J8 znnl?5_9wTG9R?HX>bSsH?(PAkv&jU>L#9=^DrOGcE3s2z8x`E#H z20pz#!x6PpIJ~?~rKL>iHuIR7<7VGOzPEPNZF--EhKA17+CK62_U`ZRPdVQGkv+PF z)MERDiV6s?k_A&~KwbF)NY(eC?<5aA4KO9Z(`q?+USh~Mb)SFvV&?1bXG>2P+;Fka zzc!6E&@+roMMagb#yHDr*caDkd!MvdCGEmFFJ5n8^$J!fw?2V9gwKtT1jGN~=#9C}y4_(4i) z<#(&_8nZY_yFk)|lXjg=KNJ4b;<~rXttkbjqni%A9_a+m=BYgv7M3^x??*T12UKiq zA!4ZbEc(lwjZOO{tfMuHkjGDE?I>62-Z1L?86S^6TIm`o7e(m|CF}}KZaD7B*Sg>W z#!IAvVYTV#gVSQOHDZ+Q#Ty^1yRH0D*YgH7O=f2z2@Q>sZkGm_D8a-6G5)A{knp6W z{!`qF%ag&CTxA-~Dzly`bb;T)M_z=Nf+eWg&Lt^VCMsE6Xe1&>#lHTJjd(NaUlPeW zIIzy^ZfPz%VN%IbE>F5JhXO`W?>z6eL$+uzsS zWw*7p-JP#VHC4)yFEbF`wXnoxGkdBK5dq8&GVcaKAB5vM`$2spBT@Lhr-ZC5B?$?D z@y*;HA*gs`;zbPiOgCqH!jYXJWffIMn?oeE?zI)p2VTHawBH^xrIf`9NKC{}Ng)cx zzaR-fCnh0bE}J@%29xA#+p7$nulojt93342;{UpCU~l#!HpXl*{Sa3M%-VQ?+LJUP zzvow}TAG@V!lPAA2V4xhPEU_nU0(3>KYJ5dw@%vHWi) zBAuamGzOl{U7~zQO)d94Kho0P1OI2(tg5}eefjL|At{;lqou#5oRFa7%YVMEHy6MU zJ&}~9rlTbuP-mhVt9epd+Mu1u5~%h4W2gO@kl0u%LBX%mDZGAxfk@@$<+V0Pq-5fr z?_q}Kw^&`{1JR`gYQts+j8pPNhWwRQ^KP=q+%j%%+Qe@)Y2!xPUqOQD`wZL91&l0e^yGBK5I!CaaY5qMG)@f*M zA}+slM^V8K-^IMWyK}v0(tnCjwb93zGukvuE5?X-w4P{fv)WC}YBiDswlG61Gx7Fl z!<&;0#x&0WS&P~FpgY( zv#7J^^~7Z*q}9Q*uCF5H2gWa?wPTlW7(%?L|8$HlDCXg^6Gb|Ag*k71nZAMg`!9~t zKb0v3j!`HJ%Li%6KmGkLpwJ2`J}OWQzNi+67L5PhR(ynypZKbVjV5;)^ObFBP1nrK z^JvYG=WPc=$Rr}Rz~I|)06tn|c$^4Diyab8NGE|gzBwIhf?a$jh7cr8kveS|BnkeR z1&D}<*SCRY>?_2_$K$Gee~&~WovxS{T%Y{ubiko*4pS(K!_Z#T>kRWh1haozE=!~Z zqZ1SRet&&f^>2?;OEk|==IhVM>FJA^HSe~%yQ{qUVhf1KzF<$&p2CYMZN6`d0rs1@Gu8y!3jQ(1NOxZy5*0)jt>7visQ#z4)i zKOR5DeYS40c?0aO{$!q1G{$C;9d^Ost3$G%k&!YfEf|B6@!upfh7YGrM%5df2wPi8 zAin_h3oJnWX*U4yhSkrDAdzQ~csvnKsXq81i(0wwCO zbITSbzBD{C@lb|R$>R)IGS6V(%M8~#DU)jJ**}Hx(5V*qd#@X?FC$Y@U28Z}mI z$jHdjiRXDocU_@>$9e?fq3){RyUzL;AB0cVD;IC=@~BA!)K9Y$19X>8M6InRam**? z87*N(efM3(^X}@kHvBDCnsTzTXe-3Hi&Ix9M}<*WBPEj2G>sPv-f_oAtYD+y2$yo$H+!f49fY9k$0_%E`%D zSXyq)=AeV+`aoy=Y~>kBONLfW@#*$BCL*G{hX)Od(=HC=)vH%r&ilLvO*h2a+S)eG z_AB$wi~8`dKIG)&c)Qkx;OMKCXmo8Vkjd~b_@S(i7HTMg7tT}6dd}zWL`A+DJiOQi zq6xUS*XB=^OF|0@Xfwn@mrl1nl9G~2b0d(XMBCMgpKX7+zr4C)S!(^MDC{4#s3?z& z{QdU+X5u!h1~OCQ{&l|L0)v=X4pa|(c8g3<=W6Tfu(nfUW4l09!q(32mmd6Ur4?rT z5{LhK>Z9%9Cx@5#LSW|rMB;N7l0Le1>9S1~OvLsWe6+~03)|Kl;oO%P;qXNYPvVRH zc`|;IuQOHVYt{z`dbqT-w10|qq1QORE-}3zrb2^7I8#GLK@kn=*Duvr-raB#pDV{v z|5r6vo_(qh`*MRp=ll2X`m4Dw!%n@Qgw**nFglZgO^t{~^l2m$S+qGUE+)obwZLdJ zdohmP@p*%j71_H|dNT14N`8JKXATat@%$d=pk^v+>hHe3BG~lTMA4F>;5fA2cd9qv zQZ+U;B0YajH-5x#Hjv;5TDNg~;9oIMV)O$eJ}+D=Yin^g&DI+mp?4~EPgOu~Iay~+ zGYQ-8Pla24#c$0zlbnp@a$UyZskTlRyt{5Zo0tV<tw($dkDV{pF#=DNDN8sg_Q^+86a zZ2~s2bn7SojRg@%>qg6&)L>gie8=n>t+v$4_PRxOYijO~RLWDXt*<{`A0h#b>J=_- z$9#ixoy}iTkkRQFAIHMSH%CD8hz4mCSgL^D=NG_Qpiw!dJ&e~a5igm{a090D-de}* zbOmQAFbSQkatu0tsH>~X=g3+n^y2q#L7yw*eO{lgo1yYG zxZzg$8l7%sI3C-5{Vw#>larf!d4FAXDMiiYQU)}Dq(I87_S`_Z z>gn(Qbhcdu(f|q|j|1Vq+eKM$KPZvPX!g7=-I~;U$OPfy#?xt?3pj8S$|SNPd|d0* z<8(cK4IWM6b^QSj1M}$s$(0G2|8;Dp)J80)aFzDcmX*D1@lH?9jnzWbabo)cPpg|i(QG<&4Ol{GzZN*!G(o%2^`j)V_{SqVJb18p0ehK z67ywR&-_BA?&(;>2@MHqo9@B2x6g}Z07jUrtLFY(lTS{7c*LHXknkf{KVb56y#3$u zpZ@7)WvhJ#z+7Bcm#Bg`??oP{LxT*YbfUKh2EShu&c@7%IL3=Dvy%+iIb1fyv z=v%;sDJvvH&$Yu`q-1m|1}Q7sCjOGNjgiX|1~~0k?;zBLQDFQ4E+vWdxd;< znw^c!$C=8ocphv1zkfN9QBhaAD5S1-D@@h3wBAg2$>SQltFt)BV1YuXt345$+|J&e zG2_sTYAMF+8TR5NDzaZ4tuPyVDD}R0bLJVZIiV3~lHPxjo4{%+y~y7b&uRKRl2T3| zfOFtJG>ompD^@#q!E`>e;(>~;w(JCeafVR=d*fUc57fB7x8*fUwzRc`kr!$-GyB-$ z&=C&a;uuStsHa|bzg(b6mbO)P%gsK|>e{-2xp^PHj~=6~matJ^2=(mEP-jTu=DFnL z?J=WhJkvcH8sS{mUtz>JHhXRpSc+k9*C-_TpW_xb3PwHSaNzatpiW3JelIg}f5f2E+#gMwe!6QqXOs%CT9w)Or+&l?PLE3@TwGkS z=q)zo^V&?7&dyWtf)pXvlJS3+J2|onD=-Fs{34QL%Cb1PKEpR1$+Ru&I1bj&l`dg6 z3X`HSw2+)$T@KC3Jd&Y?YL8uJ$2ejyYq)L;s*DUc2phQ*O9BQpSv-HbHD54<6BbKC zbn;hRyY7{wsw#GRx_*Dk32KpMReNVA!n?YMm-KpgNojB4F2h{ua%Lm{AbbEwkdF$Z zx4806jApC%reV+$zWXWMK^$;n6{W7e|h#nUn`AFnI?&uP!Lu#@OA zeAsv#tj&2w$$l=_nXk(*mg6H7+l2z*9RC)I{+Dm7vmC;Q%9Zl^dl zaMyzE@dD=MyT7bfw;u6S7tZC!8>!MWUcU=`TpZtf*E=7a`x=wC!-?1I#MnL$y$2-O zcrYay?D3$BMPdm%J3H4G^k4?uw@ggT`*I`5J`8p*?M~Z6Uf{ETb34OVXlXrZ9IK;U z^oARLeUqeCeC-#@?VM#=5!1;0>0Ky(Cj-|Y};R$8>t&b!&2PTfHV%M810fg(XE7cbd#9fET@ z^HHhAjO1P+<+9!j?2|VTkP=Z>$1&u;MIui9;jlFl4=`r)y&IZTjECHwW)&zPMmOh# zWBDo-?d)GbVT(+TY#X5vSlV1|Ulv`2+N~lM-mjT}04K56D9OFKJCAG6k$Pj_YmC`0fK!HNS!W^-XU3SsL zLi3|()ynMFXaL~LQ!S#gZ;1~H3POQ2IPI->QS=1{2EK(tF~2;>Ll5$au{8W=iOJyK z{rQH6Ha+zF>sanfd4t)#*Q!$mP;UXpN4a+vC0<@$ z2I<`nKzyyO55zl9p1fsX$L5&)wRrF40FQ}Lg#b*7pA>-cE6ol$|3R1;o?`anmy?t< z01Fp?cP5>{X8t221eI3p{?9of&v6Y%uS$LVs0EPFZ1us?0LP-iV)MMZh6dK``hQ9w zTwK^Q)?h9H3nm9ii~v#PF-xDWmuGJw@auzj-@ZLQIz1IB7zaU+pxD?AAJ4hRzuQJf zFB!LAnnm;ClKPgVY_`Pg?pmC>@j0D4fu{1n{C=c*!>k3IcIDOwZep}*NPGJFgmcD! zMkj~J=FpZ6^z}soeT7mkMMy;CsfLDzcCAZ9LeqBvE`J7ruci%rC zfal5e#l{~$6be|4+<|U?YRi|QQl?uEPmRMpUQpx@!Z-}Mp~kRZKtTD2cxcf&MG7Mg zIRgp|ljAm3p=MPA=*IE41Th$J^86KX^sU7IxIfSb9S5ai!NrgXB*Bj#il@txeSwi{V2!UyWhvr1^7L#bZrRmQ`M$I6T>o*qP4#a^^$&IE zA8kW7ej7yS){i^!g-sWJaUGz;t?xGqRPX)(O0H35_RPu2i874Gu#*nxp6GLW=!fk` z8I)B544|-PW@TYrdjOrFwxJtXl0L23AFRgdtVq#^Vk1hxVydHm{3`sQ^+l;7fsKa&i@V};_ zq-1f2Y0D;YN?2JjeEn*9^?4TuuzaaoT|XC1fE=@iKVJesSE$nvy0nA=5fW}wznnMV zzqyT6^n3k#s>~4Z5V`gK6qWq*F2bpn03|ATKYV94ha&`!y?uV35Tro<7sZ20nubZN zrP=d&@R7@hN4Lj)W^_e#D4zU=>vVvTUb%MIRa@UAZ$BCb+A=G5GA#G5WU=%s8sSWt z=?b@(Zdp=rzceN9h}Guhi!wYO zK@*&5ZN;>mik!*o54nFcm#>@S4)(0c)p6?PaD}smvkncYAr`aEKDteAtKQY1TOzdF z<2@QLSlQn01^t)PlRFM{s*J9Xz`&1Z364N*D3_ldFPPjM%OgukNdfq1q(+YTXXHWn z<;Q3v;TvK$yQhp#pXpm$hk=+rpPR$VNLHU1v7W>o=6^4`yl#13i6N&{H<#fCP{Qr4 z2QJgcxBL56FK}6EdHp>}op$H^#4^%#8k`_=4bEYgzE8nrh3J-$7H^}%!a}45H+pyl zy;jX|xeC7S{!B71)EKLF3`D#=c+W7!!tlQO_;{v!R$E^@Zg4&z;pa~Q6^Y$q>I0yo zw)XZ=H#j;4Ir%XV^pT%in2#OdZkLFo|6Z~F0C3lzKYxA@2nXgAX@8Tq z+ybB7%(15p4VNWOkHhj^m`sB;^{w(@nC;l47BbmtKkd4Z6m_Ny8%~!6PJiFsQLfa zOX!b~k=K|l>KYubSk#JrM=Cb-VnxxdaRj`e+-z*9S`FVgA_w~Wb5#l`4f%08{a&2(K>i+I#8KfXXLfD=lHcNt2zA>1}VG0N8j+&a<0s*&gT%0;7S;h;Z zROY*;rp7ovcWlJ-1N}+Zo^ql3OB588?Xf(|!%IIGyj}w3AZ$+{)gfdMYfE}?8nY@W zC=_a{+#V~*T^nELqQh&jt}FoHyz6* z0q64Z$Nm6fThP8h9|f{4vpbBV(rg?!1^D$2UU|P6t$3U*o_!qeO~v6__Do7jIy^r% zn4dWVy&k0Qdq8Ccy*UHq#Skt^Mz?S{yhy>#meti&3{1>E(D#;>mwyVh{0tq8yMKTc zJ&`$JIagPEl=_png3_(gBDyer4WaDy+b)2n_e)psM%H#;+P+(V^=%kJ@X zAb~9l^i9gJ8xW_t+C5=BhBtsc2-%%(0xl<&&z|UXwIvS_zMf*+VqOE7@|KN0+If*M z22L>gAVkz${5!rhySW0yoc~oa5xtL>lekeU7=Hl9j4cU*>QgGadwZrsY5YNN=;>^T z^J`b2+1?FKjE8G#qgZhvibrB>Vb=?2@)EATX4J{{yZ8*ED5`^@f1)zdNJ^6FfBgA{d-?0 zUVA=2qKl%=B_JS(W8X7ehb77ZVGp#gOWPhr{u>LtiHQl(b7p0()~ND^PW9T4{9v^^ zfcQnDl0Q^o;w&Tt!IlET$+@c zn}}m+?~Ive8&6={;UpyJ4}94cV#T5C4>STW3hl_{sz;LQ!uF?K{A|OtY%ZGXT~CkFzFsfH8_t1Kq|-0Ovs?UL$QXL$N?X zq1HDLLkLGIjHpRg+}Ic!+@wON;h@Q#)7Alw9wiy{2^8uY0@6}WAUaW`8q|3ecGz0xIdl-oh0R!Tp_RPFLgE*|x z$9Hm94!Z1BZe8j`F+KRSQ`>p{FyJ34pN(e=cU@XsY38e*X4(#zIan2O?iEp2Y9i*v{p3 ze-&G}SX%bm#IQ5ic<8sr21+z#ZNa&vENF^<^~(;RcIbz zjFmE=KFL4aX%z_Ct+1L$(Df*LlIT6#%~+rs4qV?_Tg>Cxt`K~w4~G)#uw={Aucrr- zvEfURSKjEt&zAy-V-K%)e5UFQX&32lW0saaHYf0pZk~f%vt{NRR@jW1-3N&r5s{H? zwMW^5&TIL4rR9}0r&rSz8#n+dFt*J3flJEF?&s3yd-JJ_UYA4nkGm#HfF{6Z7DvqD z-z+D5=O@qYBk0I{iydO7OkM3cd-SnUn?}B^gcOW>-TU4nBwxGHwV<0nLp&^V9z}3! zc6McJOJXpEuhwNtkviKtNpz7u&Gp21Y`q?20iM%7{9FLgI~1$Tu-wjeB|dxz9Nv4d z=|VVksoth>7Z(?MFu9TE$R@9^4Wiatzx@bmoZ@!KGaoBNt%0xtLO#GU9SZErALcB0>$ z%xJRKr1CZ*|0oMIzQziwhfXYMB>++rw+DdbL+=H8 zOR$-oloaA`7_9iW6Y$zIV=?^0H0v!uE?Kt``0we}m6fbOpT_5~TppFnE;qT51)`Iy zcl$da@}O9@c(sYuJ9|GvK?!=CihtvYJ*kI80mV^vyuIUer*9nEaGIDPfd4iBhBrZ9 zzF23@k*Cv9GiBT0xFdPEg}J*>mF$nY16>`c>F(`i(ckt16jh->m7bsA*^M+xp+6;F;uh`| zKj#^+g1^U}#Bz4+x656$_7`v(aeH%oem)%&YlWZ|-CAFidhfShPJuG0_Sgxe`~+#DN#B0t{_*@mb6uvl zkFC3B-Z&5Q?aqvT3$H>*nW5!mDh6@D-mLSlva**z3_(Ik3>hy_g}k2()zf|s2@E>m z8f7zRM;i08pRwYC+yVu6Xa`ljZo4LCC%3%jwEyc_Rm+7UjZzv1PAR1&;R}Q(x3`ol zdo|AwrwsWnWW27Y6H5E2%7l5P1JG8Eu`=hRsLVvWkYH1CkiW9G#ArDu z_5OQycAx5+f_;X9mixqUUDX-h<4?~wfyY)=MY7!S&co@HG3I!8SG!QX4iD_7_mk;5 zu65ayXNy|Rl$P}1x!sR_Ffe(D{X{#M5(i?AU#}T7-oc0(%MGxM{b6FVFjaC2+M*c? ztNWKppUPDUL`1ha$M2?soe-6_d5@AoMR=g5>JK z46-*oZ*z0={U>GC=9_)eY`Ik9t7IXeZy;VdU&44Ws+;iK#Y?EDGv-FFNo&0h`8S#P1=m#-2b>z{w8dXtmRPQGc z`l2I$g)A0==QkDiIak>X@@4q5h|wCAdg)vJ-=1%OEpS(CaI-bl;ZmD13asqo?cGtSwtRIO-2>%89+Z-2ym3 z_-{usyIY?O=S~}e)6;ZatB$#yPK=JX`M1M7&O5q!&Gq{ZFV+~mIdwmG>pphQdPN>R zJ-vVvPl4^7m!EfauE>A0@6zAf#m@!pj(;>)p1)#UlTCnG#9!e_z&K60Vv~}4#w8@= zNkDn~i~rLOuP>S2H}R26>D0r#-p6_Fg}zZTntk@ii^s~q`UAN6{Rc?d!UXdbz`2vT z7yA>HQ`|I`1Zi&Cp7Tt_YU1Pq|JRFeDeieW>qX+x=YfI~KS+eQsMxTH3Uc;4y1E=n v4xpY;F>AwS(|G<;`;LyPqk=#i-q-)!&7@h~C9(o|#uS66tDnm{r-UW|w$}mP diff --git a/src/SketchPlugin/plugin-Sketch.xml b/src/SketchPlugin/plugin-Sketch.xml index f69c00040..ab5488d0a 100644 --- a/src/SketchPlugin/plugin-Sketch.xml +++ b/src/SketchPlugin/plugin-Sketch.xml @@ -65,6 +65,11 @@ tooltip="Center coordinates" accept_expressions="0" enable_value="enable_by_preferences"/> + + + + diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.cpp index 1f0fd0e7c..8f6ff982d 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.cpp @@ -480,7 +480,8 @@ bool PlaneGCSSolver_Tools::isAttributeApplicable(const std::string& theAttrName, } else if (theOwnerName == SketchPlugin_Circle::ID()) { return theAttrName == SketchPlugin_Circle::CENTER_ID() || - theAttrName == SketchPlugin_Circle::RADIUS_ID(); + theAttrName == SketchPlugin_Circle::RADIUS_ID() || + theAttrName == SketchPlugin_Circle::ROTATE_ID(); } else if (theOwnerName == SketchPlugin_Line::ID()) { return theAttrName == SketchPlugin_Line::START_ID() || -- 2.30.2