From a75b67fb7c1a4d8bf4acec94ecd441a48415634d Mon Sep 17 00:00:00 2001 From: asozinov Date: Tue, 6 Jun 2023 11:52:31 +0100 Subject: [PATCH] [EDF] (2023-T1) Sketch middle point constrain should create point if missing - Added new way for create middle point constraint: Only by segment - Added MacroMiddlePoint, which create point and middle constraint between point and passed object. Returns point - SketchAPI: added setMiddlePoint() command, which pass only object and create middle point for object. - will be updated documentation and tests --- src/SketchAPI/CMakeLists.txt | 2 + src/SketchAPI/SketchAPI.i | 2 + src/SketchAPI/SketchAPI_Constraint.cpp | 71 +++-- src/SketchAPI/SketchAPI_Constraint.h | 1 + src/SketchAPI/SketchAPI_MacroMiddlePoint.cpp | 71 +++++ src/SketchAPI/SketchAPI_MacroMiddlePoint.h | 58 ++++ src/SketchAPI/SketchAPI_Sketch.cpp | 255 ++++++++++-------- src/SketchAPI/SketchAPI_Sketch.h | 6 + src/SketchAPI/SketchAPI_swig.h | 1 + .../SketchPlugin_ConstraintMiddle.cpp | 91 ++++++- .../SketchPlugin_ConstraintMiddle.h | 39 +++ .../Test/TestConstraintMiddlePoint.py | 40 +++ .../Test/TestConstraintMiddlePointOnArc.py | 62 +++-- .../TestConstraintMiddlePointOnEllipticArc.py | 53 ++++ src/SketchPlugin/doc/examples/middle.py | 3 + .../doc/images/MiddlePoint_obj.png | Bin 0 -> 312 bytes .../doc/images/Middlepoint_obj_panel.png | Bin 0 -> 4992 bytes .../images/Middlepoint_obj_point_panel.png | Bin 0 -> 6698 bytes ..._res.png => Middlepoint_obj_point_res.png} | Bin .../doc/images/Middlepoint_obj_res.png | Bin 0 -> 8482 bytes .../doc/images/Middlepoint_panel.png | Bin 9647 -> 0 bytes src/SketchPlugin/doc/middleFeature.rst | 53 +++- src/SketchPlugin/icons/middlepoint_obj.png | Bin 0 -> 312 bytes src/SketchPlugin/plugin-Sketch.xml | 42 ++- .../PlaneGCSSolver/PlaneGCSSolver_Tools.cpp | 1 - 25 files changed, 681 insertions(+), 170 deletions(-) create mode 100644 src/SketchAPI/SketchAPI_MacroMiddlePoint.cpp create mode 100644 src/SketchAPI/SketchAPI_MacroMiddlePoint.h create mode 100644 src/SketchPlugin/doc/images/MiddlePoint_obj.png create mode 100644 src/SketchPlugin/doc/images/Middlepoint_obj_panel.png create mode 100644 src/SketchPlugin/doc/images/Middlepoint_obj_point_panel.png rename src/SketchPlugin/doc/images/{Middlepoint_res.png => Middlepoint_obj_point_res.png} (100%) create mode 100644 src/SketchPlugin/doc/images/Middlepoint_obj_res.png delete mode 100644 src/SketchPlugin/doc/images/Middlepoint_panel.png create mode 100644 src/SketchPlugin/icons/middlepoint_obj.png diff --git a/src/SketchAPI/CMakeLists.txt b/src/SketchAPI/CMakeLists.txt index 2d07f9a20..e83046e9e 100644 --- a/src/SketchAPI/CMakeLists.txt +++ b/src/SketchAPI/CMakeLists.txt @@ -32,6 +32,7 @@ SET(PROJECT_HEADERS SketchAPI_Line.h SketchAPI_MacroArc.h SketchAPI_MacroCircle.h + SketchAPI_MacroMiddlePoint.h SketchAPI_MacroEllipse.h SketchAPI_MacroEllipticArc.h SketchAPI_Mirror.h @@ -57,6 +58,7 @@ SET(PROJECT_SOURCES SketchAPI_Line.cpp SketchAPI_MacroArc.cpp SketchAPI_MacroCircle.cpp + SketchAPI_MacroMiddlePoint.cpp SketchAPI_MacroEllipse.cpp SketchAPI_MacroEllipticArc.cpp SketchAPI_Mirror.cpp diff --git a/src/SketchAPI/SketchAPI.i b/src/SketchAPI/SketchAPI.i index 19238b33b..ab4de1120 100644 --- a/src/SketchAPI/SketchAPI.i +++ b/src/SketchAPI/SketchAPI.i @@ -81,6 +81,7 @@ %shared_ptr(SketchAPI_Sketch) %shared_ptr(SketchAPI_SketchEntity) %shared_ptr(SketchAPI_Point) +%shared_ptr(SketchAPI_MacroMiddlePoint) %shared_ptr(SketchAPI_Projection) %shared_ptr(SketchAPI_Rectangle) %shared_ptr(SketchAPI_Rotation) @@ -573,6 +574,7 @@ // all supported interfaces (the order is very important according dependencies: base class first) %include "SketchAPI_SketchEntity.h" %include "SketchAPI_Point.h" +%include "SketchAPI_MacroMiddlePoint.h" %include "SketchAPI_IntersectionPoint.h" %include "SketchAPI_Line.h" %include "SketchAPI_Circle.h" diff --git a/src/SketchAPI/SketchAPI_Constraint.cpp b/src/SketchAPI/SketchAPI_Constraint.cpp index 9149d2395..d69c35f88 100644 --- a/src/SketchAPI/SketchAPI_Constraint.cpp +++ b/src/SketchAPI/SketchAPI_Constraint.cpp @@ -21,6 +21,8 @@ #include #include +#include +#include #include #include @@ -39,6 +41,7 @@ #include #include #include +#include #include @@ -198,35 +201,61 @@ void SketchAPI_Constraint::dump(ModelHighAPI_Dumper& theDumper) const return; } - // postpone constraint until all its attributes be dumped - if (!areAllAttributesDumped(theDumper)) - return; - const std::string& aSketchName = theDumper.parentName(aBase); - theDumper << aSketchName << "." << aSetter << "("; - bool isFirstAttr = true; - for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) { - AttributeRefAttrPtr aRefAttr = aBase->refattr(SketchPlugin_Constraint::ATTRIBUTE(i)); + // Dump middle constraint by object + if (SketchPlugin_ConstraintMiddle::ID() == aBase->getKind() && + aBase->string(SketchPlugin_ConstraintMiddle::MIDDLE_TYPE())->value() == SketchPlugin_ConstraintMiddle::MIDDLE_TYPE_BY_LINE()) + { + FeaturePtr aFeature; + AttributeRefAttrPtr aPointRefAttr = aBase->refattr(SketchPlugin_Constraint::ATTRIBUTE(1)); + AttributeRefAttrPtr aRefAttr = aBase->refattr(SketchPlugin_Constraint::ATTRIBUTE(0)); + + if (!theDumper.isDumped(aRefAttr)) + { + theDumper.postpone(aBase); + return; + } + aFeature = ModelAPI_Feature::feature(aPointRefAttr->object()); + + theDumper.name(aFeature, false, true, true); // mark point as dumped + + theDumper << theDumper.name(aFeature) << " = " << aSketchName << "." << aSetter << "("; if (aRefAttr && aRefAttr->isInitialized()) { - theDumper << (isFirstAttr ? "" : ", ") << aRefAttr; - isFirstAttr = false; + theDumper << aRefAttr; } + theDumper << ")" << std::endl; } + else + { + // postpone constraint until all its attributes be dumped + if (!areAllAttributesDumped(theDumper)) + return; + + theDumper << aSketchName << "." << aSetter << "("; + bool isFirstAttr = true; + for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) { + AttributeRefAttrPtr aRefAttr = aBase->refattr(SketchPlugin_Constraint::ATTRIBUTE(i)); + if (aRefAttr && aRefAttr->isInitialized()) { + theDumper << (isFirstAttr ? "" : ", ") << aRefAttr; + isFirstAttr = false; + } + } - AttributeDoublePtr aValueAttr; - if (aBase->getKind() == SketchPlugin_ConstraintDistanceHorizontal::ID() || + AttributeDoublePtr aValueAttr; + if (aBase->getKind() == SketchPlugin_ConstraintDistanceHorizontal::ID() || aBase->getKind() == SketchPlugin_ConstraintDistanceVertical::ID()) - aValueAttr = aBase->real(SketchPlugin_ConstraintDistanceAlongDir::DISTANCE_VALUE_ID()); - else - aValueAttr = aBase->real(SketchPlugin_Constraint::VALUE()); - if (aValueAttr && aValueAttr->isInitialized()) - theDumper << ", " << aValueAttr; + aValueAttr = aBase->real(SketchPlugin_ConstraintDistanceAlongDir::DISTANCE_VALUE_ID()); + else + aValueAttr = aBase->real(SketchPlugin_Constraint::VALUE()); + if (aValueAttr && aValueAttr->isInitialized()) + theDumper << ", " << aValueAttr; - if (aBase->getKind() == SketchPlugin_ConstraintDistance::ID()) { - AttributeBooleanPtr isSigned = aBase->boolean(SketchPlugin_ConstraintDistance::SIGNED()); - theDumper << ", " << isSigned->value(); + if (aBase->getKind() == SketchPlugin_ConstraintDistance::ID()) { + AttributeBooleanPtr isSigned = aBase->boolean(SketchPlugin_ConstraintDistance::SIGNED()); + theDumper << ", " << isSigned->value(); + } + theDumper << ")" << std::endl; } - theDumper << ")" << std::endl; } diff --git a/src/SketchAPI/SketchAPI_Constraint.h b/src/SketchAPI/SketchAPI_Constraint.h index 220d1d59d..fe4ece791 100644 --- a/src/SketchAPI/SketchAPI_Constraint.h +++ b/src/SketchAPI/SketchAPI_Constraint.h @@ -29,6 +29,7 @@ #include class ModelHighAPI_Double; +class SketchAPI_SketchEntity; /**\class SketchAPI_Constraint * \ingroup CPPHighAPI diff --git a/src/SketchAPI/SketchAPI_MacroMiddlePoint.cpp b/src/SketchAPI/SketchAPI_MacroMiddlePoint.cpp new file mode 100644 index 000000000..3ec3a3610 --- /dev/null +++ b/src/SketchAPI/SketchAPI_MacroMiddlePoint.cpp @@ -0,0 +1,71 @@ +// Copyright (C) 2019-2022 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "SketchAPI_MacroMiddlePoint.h" + +#include + +#include + +#include + +SketchAPI_MacroMiddlePoint::SketchAPI_MacroMiddlePoint( + const std::shared_ptr & theFeature) +: SketchAPI_Point(theFeature) +{ + ConstraintPtr aConstraint = std::dynamic_pointer_cast(theFeature); + if (aConstraint) + initialize(); +} + +SketchAPI_MacroMiddlePoint::SketchAPI_MacroMiddlePoint(const std::shared_ptr& theFeature, + const ModelHighAPI_RefAttr& theLine, const std::shared_ptr& thePoint) + : SketchAPI_Point(theFeature, thePoint) +{ + createConstraint(theLine); +} + +void SketchAPI_MacroMiddlePoint::createConstraint(const ModelHighAPI_RefAttr& theLine) +{ + // 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 middle constraint for line and poiunt + std::shared_ptr aConstrFeature = + aSketch->addFeature(SketchPlugin_ConstraintMiddle::ID()); + aConstrFeature->string(SketchPlugin_ConstraintMiddle::MIDDLE_TYPE())->setValue(SketchPlugin_ConstraintMiddle::MIDDLE_TYPE_BY_LINE()); + aConstrFeature->refattr(SketchPlugin_Constraint::ENTITY_A())->setObject(theLine.object()); + aConstrFeature->refattr(SketchPlugin_Constraint::ENTITY_B())->setAttr(coordinates()); + std::dynamic_pointer_cast(aConstrFeature->attribute(SketchPlugin_ConstraintMiddle::POINT_REF_ID()))->setValue(coordinates()->x(), coordinates()->y()); + + aConstrFeature->execute(); + + feature()->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(true); + feature()->reference(SketchPlugin_SketchEntity::PARENT_ID())->setValue(aConstrFeature); + feature()->execute(); +} diff --git a/src/SketchAPI/SketchAPI_MacroMiddlePoint.h b/src/SketchAPI/SketchAPI_MacroMiddlePoint.h new file mode 100644 index 000000000..2e747dff0 --- /dev/null +++ b/src/SketchAPI/SketchAPI_MacroMiddlePoint.h @@ -0,0 +1,58 @@ +// Copyright (C) 2019-2022 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef SRC_SKETCHAPI_SKETCHAPI_MACRO_MIDDLEPOINT_H_ +#define SRC_SKETCHAPI_SKETCHAPI_MACRO_MIDDLEPOINT_H_ + +#include "SketchAPI_SketchEntity.h" + +#include + +class ModelHighAPI_RefAttr; + + +/**\class SketchAPI_MacroMiddlePoint + * \ingroup CPPHighAPI + * \brief Interface for Middle Point feature + */ +class SketchAPI_MacroMiddlePoint : public SketchAPI_Point +{ +public: + /// Constructor without values + SKETCHAPI_EXPORT + explicit SketchAPI_MacroMiddlePoint(const std::shared_ptr & theFeature); + + /// Constructor with line and middle point coordinates + SKETCHAPI_EXPORT + SketchAPI_MacroMiddlePoint(const std::shared_ptr& theFeature, + const ModelHighAPI_RefAttr& theLine, + const std::shared_ptr& thePoint); + + static std::string ID() + { + static const std::string MY_SKETCH_CONSTRAINT_ID = "MacroConstraintMiddle"; + return MY_SKETCH_CONSTRAINT_ID; + } + virtual std::string getID() { return ID(); } + +protected: + void createConstraint(const ModelHighAPI_RefAttr& theLine); +}; + +#endif diff --git a/src/SketchAPI/SketchAPI_Sketch.cpp b/src/SketchAPI/SketchAPI_Sketch.cpp index 34503d972..b0836ae12 100644 --- a/src/SketchAPI/SketchAPI_Sketch.cpp +++ b/src/SketchAPI/SketchAPI_Sketch.cpp @@ -67,6 +67,7 @@ #include "SketchAPI_MacroCircle.h" #include "SketchAPI_MacroEllipse.h" #include "SketchAPI_MacroEllipticArc.h" +#include "SketchAPI_MacroMiddlePoint.h" #include "SketchAPI_Mirror.h" #include "SketchAPI_Offset.h" #include "SketchAPI_Point.h" @@ -74,6 +75,7 @@ #include "SketchAPI_Rectangle.h" #include "SketchAPI_Rotation.h" #include "SketchAPI_Translation.h" +#include "SketchAPI_Constraint.h" //-------------------------------------------------------------------------------------- #include #include @@ -85,6 +87,125 @@ #include #include //-------------------------------------------------------------------------------------- + + +static std::shared_ptr pointCoordinates(const AttributePtr& thePoint) +{ + AttributePoint2DPtr aPnt = std::dynamic_pointer_cast(thePoint); + return aPnt ? aPnt->pnt() : std::shared_ptr(); +} + +static std::shared_ptr middlePointOnLine(const FeaturePtr& theFeature) +{ + AttributePoint2DPtr aStartAttr = std::dynamic_pointer_cast( + theFeature->attribute(SketchPlugin_Line::START_ID())); + AttributePoint2DPtr aEndAttr = std::dynamic_pointer_cast( + theFeature->attribute(SketchPlugin_Line::END_ID())); + + if (!aStartAttr || !aEndAttr) + return std::shared_ptr(); + + std::shared_ptr aStartPoint = aStartAttr->pnt()->xy(); + std::shared_ptr aEndPoint = aEndAttr->pnt()->xy(); + return std::shared_ptr( + new GeomAPI_Pnt2d(aStartPoint->added(aEndPoint)->multiplied(0.5))); +} + +static std::shared_ptr pointOnCircle(const FeaturePtr& theFeature) +{ + AttributePoint2DPtr aCenter = std::dynamic_pointer_cast( + theFeature->attribute(SketchPlugin_Circle::CENTER_ID())); + AttributeDoublePtr aRadius = theFeature->real(SketchPlugin_Circle::RADIUS_ID()); + + if (!aCenter || !aRadius) + return std::shared_ptr(); + + return std::shared_ptr( + new GeomAPI_Pnt2d(aCenter->x() + aRadius->value(), aCenter->y())); +} + +static std::shared_ptr middlePointOnArc(const FeaturePtr& theFeature) +{ + static const double PI = 3.141592653589793238463; + + AttributePoint2DPtr aCenterAttr = std::dynamic_pointer_cast( + theFeature->attribute(SketchPlugin_Arc::CENTER_ID())); + AttributePoint2DPtr aStartAttr = std::dynamic_pointer_cast( + theFeature->attribute(SketchPlugin_Arc::START_ID())); + AttributePoint2DPtr aEndAttr = std::dynamic_pointer_cast( + theFeature->attribute(SketchPlugin_Arc::END_ID())); + + if (!aCenterAttr || !aStartAttr || !aEndAttr) + return std::shared_ptr(); + + std::shared_ptr aStartDir(new GeomAPI_Dir2d( + aStartAttr->x() - aCenterAttr->x(), aStartAttr->y() - aCenterAttr->y())); + std::shared_ptr aEndDir(new GeomAPI_Dir2d( + aEndAttr->x() - aCenterAttr->x(), aEndAttr->y() - aCenterAttr->y())); + + double anAngle = aStartDir->angle(aEndDir); + bool isReversed = theFeature->boolean(SketchPlugin_Arc::REVERSED_ID())->value(); + if (isReversed && anAngle > 0.) + anAngle -= 2.0 * PI; + else if (!isReversed && anAngle <= 0.) + anAngle += 2.0 * PI; + + double cosA = cos(anAngle); + double sinA = sin(anAngle); + + // rotate start dir to find middle point on arc + double aRadius = aStartAttr->pnt()->distance(aCenterAttr->pnt()); + double x = aCenterAttr->x() + aRadius * (aStartDir->x() * cosA - aStartDir->y() * sinA); + double y = aCenterAttr->y() + aRadius * (aStartDir->x() * sinA + aStartDir->y() * cosA); + + return std::shared_ptr(new GeomAPI_Pnt2d(x, y)); +} + +static std::shared_ptr pointOnEllipse(const FeaturePtr& theFeature, + bool isEllipse = true) +{ + const std::string& anAttrName = isEllipse ? SketchPlugin_Ellipse::MAJOR_AXIS_END_ID() : + SketchPlugin_EllipticArc::MAJOR_AXIS_END_ID(); + AttributePoint2DPtr aMajorAxisEnd = std::dynamic_pointer_cast( + theFeature->attribute(anAttrName)); + return aMajorAxisEnd ? aMajorAxisEnd->pnt() : std::shared_ptr(); +} + +static std::shared_ptr middlePointOnBSpline(const FeaturePtr& theFeature, + SketchAPI_Sketch* theSketch) +{ + GeomAPI_Edge anEdge(theFeature->lastResult()->shape()); + GeomPointPtr aMiddle = anEdge.middlePoint(); + return theSketch->to2D(aMiddle); +} + +static std::shared_ptr middlePoint(const ObjectPtr& theObject, + SketchAPI_Sketch* theSketch) +{ + std::shared_ptr aMiddlePoint; + FeaturePtr aFeature = ModelAPI_Feature::feature(theObject); + if (aFeature) { + // move only features of the following types + const std::string& aFeatureKind = aFeature->getKind(); + if (aFeatureKind == SketchPlugin_Point::ID()) + aMiddlePoint = pointCoordinates(aFeature->attribute(SketchPlugin_Point::COORD_ID())); + else if (aFeatureKind == SketchPlugin_Line::ID()) + aMiddlePoint = middlePointOnLine(aFeature); + else if (aFeatureKind == SketchPlugin_Circle::ID()) + aMiddlePoint = pointOnCircle(aFeature); + else if (aFeatureKind == SketchPlugin_Arc::ID()) + aMiddlePoint = middlePointOnArc(aFeature); + else if (aFeatureKind == SketchPlugin_Ellipse::ID()) + aMiddlePoint = pointOnEllipse(aFeature); + else if (aFeatureKind == SketchPlugin_EllipticArc::ID()) + aMiddlePoint = pointOnEllipse(aFeature, false); + else if (aFeatureKind == SketchPlugin_BSpline::ID() || + aFeatureKind == SketchPlugin_BSplinePeriodic::ID()) + aMiddlePoint = middlePointOnBSpline(aFeature, theSketch); + } + return aMiddlePoint; +} + SketchAPI_Sketch::SketchAPI_Sketch( const std::shared_ptr & theFeature) : ModelHighAPI_Interface(theFeature) @@ -1246,12 +1367,29 @@ std::shared_ptr SketchAPI_Sketch::setMiddlePoint( { std::shared_ptr aFeature = compositeFeature()->addFeature(SketchPlugin_ConstraintMiddle::ID()); + auto aType = aFeature->data()->string(SketchPlugin_ConstraintMiddle::MIDDLE_TYPE()); + fillAttribute(SketchPlugin_ConstraintMiddle::MIDDLE_TYPE_BY_LINE_AND_POINT(), aType); + fillAttribute(thePoint, aFeature->refattr(SketchPlugin_Constraint::ENTITY_A())); fillAttribute(theLine, aFeature->refattr(SketchPlugin_Constraint::ENTITY_B())); + aFeature->execute(); return InterfacePtr(new ModelHighAPI_Interface(aFeature)); } +std::shared_ptr SketchAPI_Sketch::setMiddlePoint( + const ModelHighAPI_RefAttr& theLine) +{ + std::shared_ptr aFeature = + compositeFeature()->addFeature(SketchPlugin_Point::ID()); + + ObjectPtr anObj = theLine.object(); + auto aPoint = middlePoint(anObj, this); + + return std::shared_ptr + (new SketchAPI_MacroMiddlePoint(aFeature, theLine, aPoint)); +} + std::shared_ptr SketchAPI_Sketch::setParallel( const ModelHighAPI_RefAttr & theLine1, const ModelHighAPI_RefAttr & theLine2) @@ -1312,123 +1450,6 @@ std::shared_ptr SketchAPI_Sketch::setVertical( //-------------------------------------------------------------------------------------- -static std::shared_ptr pointCoordinates(const AttributePtr& thePoint) -{ - AttributePoint2DPtr aPnt = std::dynamic_pointer_cast(thePoint); - return aPnt ? aPnt->pnt() : std::shared_ptr(); -} - -static std::shared_ptr middlePointOnLine(const FeaturePtr& theFeature) -{ - AttributePoint2DPtr aStartAttr = std::dynamic_pointer_cast( - theFeature->attribute(SketchPlugin_Line::START_ID())); - AttributePoint2DPtr aEndAttr = std::dynamic_pointer_cast( - theFeature->attribute(SketchPlugin_Line::END_ID())); - - if (!aStartAttr || !aEndAttr) - return std::shared_ptr(); - - std::shared_ptr aStartPoint = aStartAttr->pnt()->xy(); - std::shared_ptr aEndPoint = aEndAttr->pnt()->xy(); - return std::shared_ptr( - new GeomAPI_Pnt2d(aStartPoint->added(aEndPoint)->multiplied(0.5))); -} - -static std::shared_ptr pointOnCircle(const FeaturePtr& theFeature) -{ - AttributePoint2DPtr aCenter = std::dynamic_pointer_cast( - theFeature->attribute(SketchPlugin_Circle::CENTER_ID())); - AttributeDoublePtr aRadius = theFeature->real(SketchPlugin_Circle::RADIUS_ID()); - - if (!aCenter || !aRadius) - return std::shared_ptr(); - - return std::shared_ptr( - new GeomAPI_Pnt2d(aCenter->x() + aRadius->value(), aCenter->y())); -} - -static std::shared_ptr middlePointOnArc(const FeaturePtr& theFeature) -{ - static const double PI = 3.141592653589793238463; - - AttributePoint2DPtr aCenterAttr = std::dynamic_pointer_cast( - theFeature->attribute(SketchPlugin_Arc::CENTER_ID())); - AttributePoint2DPtr aStartAttr = std::dynamic_pointer_cast( - theFeature->attribute(SketchPlugin_Arc::START_ID())); - AttributePoint2DPtr aEndAttr = std::dynamic_pointer_cast( - theFeature->attribute(SketchPlugin_Arc::END_ID())); - - if (!aCenterAttr || !aStartAttr || !aEndAttr) - return std::shared_ptr(); - - std::shared_ptr aStartDir(new GeomAPI_Dir2d( - aStartAttr->x() - aCenterAttr->x(), aStartAttr->y() - aCenterAttr->y())); - std::shared_ptr aEndDir(new GeomAPI_Dir2d( - aEndAttr->x() - aCenterAttr->x(), aEndAttr->y() - aCenterAttr->y())); - - double anAngle = aStartDir->angle(aEndDir); - bool isReversed = theFeature->boolean(SketchPlugin_Arc::REVERSED_ID())->value(); - if (isReversed && anAngle > 0.) - anAngle -= 2.0 * PI; - else if (!isReversed && anAngle <= 0.) - anAngle += 2.0 * PI; - - double cosA = cos(anAngle); - double sinA = sin(anAngle); - - // rotate start dir to find middle point on arc - double aRadius = aStartAttr->pnt()->distance(aCenterAttr->pnt()); - double x = aCenterAttr->x() + aRadius * (aStartDir->x() * cosA - aStartDir->y() * sinA); - double y = aCenterAttr->y() + aRadius * (aStartDir->x() * sinA + aStartDir->y() * cosA); - - return std::shared_ptr(new GeomAPI_Pnt2d(x, y)); -} - -static std::shared_ptr pointOnEllipse(const FeaturePtr& theFeature, - bool isEllipse = true) -{ - const std::string& anAttrName = isEllipse ? SketchPlugin_Ellipse::MAJOR_AXIS_END_ID() : - SketchPlugin_EllipticArc::MAJOR_AXIS_END_ID(); - AttributePoint2DPtr aMajorAxisEnd = std::dynamic_pointer_cast( - theFeature->attribute(anAttrName)); - return aMajorAxisEnd ? aMajorAxisEnd->pnt() : std::shared_ptr(); -} - -static std::shared_ptr middlePointOnBSpline(const FeaturePtr& theFeature, - SketchAPI_Sketch* theSketch) -{ - GeomAPI_Edge anEdge(theFeature->lastResult()->shape()); - GeomPointPtr aMiddle = anEdge.middlePoint(); - return theSketch->to2D(aMiddle); -} - -static std::shared_ptr middlePoint(const ObjectPtr& theObject, - SketchAPI_Sketch* theSketch) -{ - std::shared_ptr aMiddlePoint; - FeaturePtr aFeature = ModelAPI_Feature::feature(theObject); - if (aFeature) { - // move only features of the following types - const std::string& aFeatureKind = aFeature->getKind(); - if (aFeatureKind == SketchPlugin_Point::ID()) - aMiddlePoint = pointCoordinates(aFeature->attribute(SketchPlugin_Point::COORD_ID())); - else if (aFeatureKind == SketchPlugin_Line::ID()) - aMiddlePoint = middlePointOnLine(aFeature); - else if (aFeatureKind == SketchPlugin_Circle::ID()) - aMiddlePoint = pointOnCircle(aFeature); - else if (aFeatureKind == SketchPlugin_Arc::ID()) - aMiddlePoint = middlePointOnArc(aFeature); - else if (aFeatureKind == SketchPlugin_Ellipse::ID()) - aMiddlePoint = pointOnEllipse(aFeature); - else if (aFeatureKind == SketchPlugin_EllipticArc::ID()) - aMiddlePoint = pointOnEllipse(aFeature, false); - else if (aFeatureKind == SketchPlugin_BSpline::ID() || - aFeatureKind == SketchPlugin_BSplinePeriodic::ID()) - aMiddlePoint = middlePointOnBSpline(aFeature, theSketch); - } - return aMiddlePoint; -} - void SketchAPI_Sketch::move(const ModelHighAPI_RefAttr& theMovedEntity, const std::shared_ptr& theTargetPoint) { diff --git a/src/SketchAPI/SketchAPI_Sketch.h b/src/SketchAPI/SketchAPI_Sketch.h index f9c8fdb79..993e6ef90 100644 --- a/src/SketchAPI/SketchAPI_Sketch.h +++ b/src/SketchAPI/SketchAPI_Sketch.h @@ -57,6 +57,7 @@ class SketchAPI_Projection; class SketchAPI_Rectangle; class SketchAPI_Rotation; class SketchAPI_Translation; +class SketchAPI_MacroMiddlePoint; //-------------------------------------------------------------------------------------- typedef std::pair, ModelHighAPI_RefAttr> PointOrReference; @@ -523,6 +524,11 @@ public: const ModelHighAPI_RefAttr & thePoint, const ModelHighAPI_RefAttr & theLine); + /// Set middle + SKETCHAPI_EXPORT + std::shared_ptr setMiddlePoint( + const ModelHighAPI_RefAttr& theLine); + /// Set parallel SKETCHAPI_EXPORT std::shared_ptr setParallel( diff --git a/src/SketchAPI/SketchAPI_swig.h b/src/SketchAPI/SketchAPI_swig.h index 9fb8e6211..111782427 100644 --- a/src/SketchAPI/SketchAPI_swig.h +++ b/src/SketchAPI/SketchAPI_swig.h @@ -41,6 +41,7 @@ #include "SketchAPI_Sketch.h" #include "SketchAPI_SketchEntity.h" #include "SketchAPI_Point.h" + #include "SketchAPI_MacroMiddlePoint.h" #include "SketchAPI_Projection.h" #include "SketchAPI_Rectangle.h" #include "SketchAPI_Rotation.h" diff --git a/src/SketchPlugin/SketchPlugin_ConstraintMiddle.cpp b/src/SketchPlugin/SketchPlugin_ConstraintMiddle.cpp index ad9ab3755..9d478833b 100644 --- a/src/SketchPlugin/SketchPlugin_ConstraintMiddle.cpp +++ b/src/SketchPlugin/SketchPlugin_ConstraintMiddle.cpp @@ -21,28 +21,113 @@ #include "SketcherPrs_Factory.h" +#include + +#include +#include + +#include +#include +#include + SketchPlugin_ConstraintMiddle::SketchPlugin_ConstraintMiddle() { } +// Create new point for Middle constraint +void SketchPlugin_ConstraintMiddle::CreatePoint() +{ + // Wait all objects being created, then send update events + static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED); + bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent); + if (isUpdateFlushed) + Events_Loop::loop()->setFlushed(anUpdateEvent, false); + + auto aTrPnt = std::dynamic_pointer_cast(data()->attribute(POINT_REF_ID())); + + if (!myPoint) + { + // Get last subfeature (constraintMiddle) for set as parent + FeaturePtr aCurrentFeature = sketch()->subFeature(sketch()->numberOfSubs() - 1); + keepCurrentFeature(); + myPoint = sketch()->addFeature(SketchPlugin_Point::ID()); + myPoint->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(true); + restoreCurrentFeature(); + + myPoint->reference(SketchPlugin_Point::PARENT_ID())->setValue(aCurrentFeature); + } + + AttributePoint2DPtr aCoord = std::dynamic_pointer_cast( + myPoint->attribute(SketchPlugin_Point::COORD_ID())); + aCoord->setValue(aTrPnt->pnt()); + + myPoint->execute(); + + // Init second attr for constraint + refattr(SketchPlugin_Constraint::ENTITY_B())->setObject(myPoint); + + + if (isUpdateFlushed) + Events_Loop::loop()->setFlushed(anUpdateEvent, true); +} + void SketchPlugin_ConstraintMiddle::initAttributes() { + data()->addAttribute(SketchPlugin_ConstraintMiddle::MIDDLE_TYPE(), ModelAPI_AttributeString::typeId()); + data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId()); data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId()); + + data()->addAttribute(POINT_REF_ID(), GeomDataAPI_Point2D::typeId()); + + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), POINT_REF_ID()); } void SketchPlugin_ConstraintMiddle::execute() { + if (string(MIDDLE_TYPE())->value() == MIDDLE_TYPE_BY_LINE()) + { + std::dynamic_pointer_cast(data()->attribute(POINT_REF_ID()))->setValue(1., 1.); + AttributeRefAttrPtr aPointRes = std::dynamic_pointer_cast( + data()->attribute(SketchPlugin_Constraint::ENTITY_B())); + + auto aRefAttr = data()->refattr(SketchPlugin_Constraint::ENTITY_A())->object(); + if (!aRefAttr.get()) + return; + + + if (!attribute(ENTITY_B())->isInitialized()) + CreatePoint(); // Create new point + } +} + +void SketchPlugin_ConstraintMiddle::attributeChanged(const std::string& theID) +{ + if (theID == MIDDLE_TYPE()) + { + SketchPlugin_Tools::resetAttribute(this, ENTITY_A()); + SketchPlugin_Tools::resetAttribute(this, ENTITY_B()); + } + else if (theID == POINT_REF_ID()) + { + if (!myPoint) + return; + + auto aTrPnt = std::dynamic_pointer_cast(data()->attribute(POINT_REF_ID())); + AttributePoint2DPtr aCoord = std::dynamic_pointer_cast( + myPoint->attribute(SketchPlugin_Point::COORD_ID())); + aCoord->setValue(aTrPnt->pnt()); + + myPoint->execute(); + } } AISObjectPtr SketchPlugin_ConstraintMiddle::getAISObject(AISObjectPtr thePrevious) { if (!sketch()) return thePrevious; - AISObjectPtr anAIS = SketcherPrs_Factory::middleConstraint(this, sketch(), thePrevious); + return anAIS; } - - diff --git a/src/SketchPlugin/SketchPlugin_ConstraintMiddle.h b/src/SketchPlugin/SketchPlugin_ConstraintMiddle.h index 6c0ac43ce..ddb3c2faa 100644 --- a/src/SketchPlugin/SketchPlugin_ConstraintMiddle.h +++ b/src/SketchPlugin/SketchPlugin_ConstraintMiddle.h @@ -24,6 +24,8 @@ #include #include "SketchPlugin_ConstraintBase.h" +class ModelAPI_Feature; + /** \class SketchPlugin_ConstraintMiddle * \ingroup Plugins * \brief Feature for creation of a new constraint which places a point in the middle of a line @@ -40,6 +42,35 @@ class SketchPlugin_ConstraintMiddle : public SketchPlugin_ConstraintBase static const std::string MY_CONSTRAINT_MIDDLE_ID("SketchConstraintMiddle"); return MY_CONSTRAINT_MIDDLE_ID; } + + /// Middle constraint kind + inline static const std::string& MIDDLE_TYPE() + { + static const std::string MY_TYPE_ID("middle_type"); + return MY_TYPE_ID; + } + + /// Middle constraint type by line and point + inline static const std::string& MIDDLE_TYPE_BY_LINE_AND_POINT() + { + static const std::string MY_TYPE_ID("middle_type_by_line_and_point"); + return MY_TYPE_ID; + } + + /// Middle constraint type by line + inline static const std::string& MIDDLE_TYPE_BY_LINE() + { + static const std::string MY_TYPE_ID("middle_type_by_line"); + return MY_TYPE_ID; + } + + /// Created points for middle type by line + inline static const std::string& POINT_REF_ID() + { + static const std::string MY_POINT_REF("point"); + return MY_POINT_REF; + } + /// \brief Returns the kind of a feature SKETCHPLUGIN_EXPORT virtual const std::string& getKind() { @@ -47,6 +78,9 @@ class SketchPlugin_ConstraintMiddle : public SketchPlugin_ConstraintBase return MY_KIND; } + /// Called on change of any argument-attribute of this object + SKETCHPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID); + /// \brief Creates a new part document if needed SKETCHPLUGIN_EXPORT virtual void execute(); @@ -58,6 +92,11 @@ class SketchPlugin_ConstraintMiddle : public SketchPlugin_ConstraintBase /// \brief Use plugin manager for features creation SketchPlugin_ConstraintMiddle(); + +private: + void CreatePoint(); + + std::shared_ptr myPoint; }; #endif diff --git a/src/SketchPlugin/Test/TestConstraintMiddlePoint.py b/src/SketchPlugin/Test/TestConstraintMiddlePoint.py index 36aef57cf..9814bb731 100644 --- a/src/SketchPlugin/Test/TestConstraintMiddlePoint.py +++ b/src/SketchPlugin/Test/TestConstraintMiddlePoint.py @@ -37,6 +37,7 @@ """ from GeomDataAPI import * from ModelAPI import * +from SketchAPI import * import math from salome.shaper import model @@ -105,6 +106,8 @@ aSession.startOperation() aConstraint = aSketchFeature.addFeature("SketchConstraintMiddle") reflistA = aConstraint.refattr("ConstraintEntityA") reflistB = aConstraint.refattr("ConstraintEntityB") +anAlgoType = aConstraint.string("middle_type") +anAlgoType.setValue("middle_type_by_line_and_point") reflistA.setAttr(aEndPoint2) reflistB.setObject(aLine1.lastResult()) aConstraint.execute() @@ -122,6 +125,8 @@ aEndPoint2.setValue(80., 25.) aConstraint = aSketchFeature.addFeature("SketchConstraintMiddle") reflistA = aConstraint.refattr("ConstraintEntityA") reflistB = aConstraint.refattr("ConstraintEntityB") +anAlgoType = aConstraint.string("middle_type") +anAlgoType.setValue("middle_type_by_line_and_point") reflistA.setAttr(aEndPoint2) reflistB.setObject(aLine1.lastResult()) aConstraint.execute() @@ -172,6 +177,8 @@ aSession.startOperation() aConstraint = aSketchFeature.addFeature("SketchConstraintMiddle") reflistA = aConstraint.refattr("ConstraintEntityA") reflistB = aConstraint.refattr("ConstraintEntityB") +anAlgoType = aConstraint.string("middle_type") +anAlgoType.setValue("middle_type_by_line_and_point") reflistA.setObject(aLine2.lastResult()) reflistB.setObject(anOrigin.lastResult()) aSession.finishOperation() @@ -205,6 +212,8 @@ aSession.startOperation() aMiddle = aSketchFeature.addFeature("SketchConstraintMiddle") reflistA = aMiddle.refattr("ConstraintEntityA") reflistB = aMiddle.refattr("ConstraintEntityB") +anAlgoType = aMiddle.string("middle_type") +anAlgoType.setValue("middle_type_by_line_and_point") reflistA.setAttr(aEndPoint3) reflistB.setObject(aLine1.lastResult()) aSession.finishOperation() @@ -225,6 +234,37 @@ aEndPoint1.setValue(aEndPoint1.x() + deltaX, aEndPoint1.y() + deltaY) aSession.finishOperation() checkMiddlePoint(aEndPoint3, aLine1) assert (model.dof(aSketchFeature) == 8) +#========================================================================= +# CreateLine +#========================================================================= +aSession.startOperation() +aLine4 = aSketchFeature.addFeature("SketchLine") +aStartPoint4 = geomDataAPI_Point2D(aLine4.attribute("StartPoint")) +aEndPoint4 = geomDataAPI_Point2D(aLine4.attribute("EndPoint")) +aStartPoint4.setValue(2., 8.) +aEndPoint4.setValue(20., 14.) +aRigidConstraint1 = aSketchFeature.addFeature("SketchConstraintRigid") +aRigidConstraint1.refattr("ConstraintEntityA").setAttr(aStartPoint4) +aRigidConstraint2 = aSketchFeature.addFeature("SketchConstraintRigid") +aRigidConstraint2.refattr("ConstraintEntityA").setAttr(aEndPoint4) +aSession.finishOperation() +#========================================================================= +# Set middle point on line +#========================================================================= +aSession.startOperation() +aMiddle = aSketchFeature.addFeature("SketchConstraintMiddle") +reflistA = aMiddle.refattr("ConstraintEntityA") +anAlgoType = aMiddle.string("middle_type") +anAlgoType.setValue("middle_type_by_line") +reflistA.setObject(aLine4.lastResult()) +aSession.finishOperation() +arefB = aMiddle.refattr("ConstraintEntityB") +aPointRes = ModelAPI_Feature.feature(arefB.object()) +aMidPoint = geomDataAPI_Point2D(SketchAPI_Point(aPointRes).coordinates()) + +# check the point, and no error message +checkMiddlePoint(aMidPoint, aLine4) + #========================================================================= # End of test diff --git a/src/SketchPlugin/Test/TestConstraintMiddlePointOnArc.py b/src/SketchPlugin/Test/TestConstraintMiddlePointOnArc.py index 3312d07ea..208cbf7d8 100644 --- a/src/SketchPlugin/Test/TestConstraintMiddlePointOnArc.py +++ b/src/SketchPlugin/Test/TestConstraintMiddlePointOnArc.py @@ -44,7 +44,7 @@ class TestMiddlePointOnArc(unittest.TestCase): def tearDown(self): if self.myTestPassed: model.assertArcValidity(self.myArc) - self.checkMiddlePoint(self.myLine.startPoint(), self.myArc) + self.checkMiddlePoint(self.myLine.startPoint().pnt(), self.myArc) self.checkDOF() model.end() assert(model.checkPythonDump()) @@ -55,7 +55,7 @@ class TestMiddlePointOnArc(unittest.TestCase): def checkMiddlePoint(self, thePoint, theArc): self.myTestPassed = False # check point on arc - dist = thePoint.pnt().distance(theArc.center().pnt()) + dist = thePoint.distance(theArc.center().pnt()) NB_DIGITS = 7 - math.floor(math.log10(theArc.radius().value())) self.assertAlmostEqual(dist, theArc.radius().value(), NB_DIGITS) # check middle point @@ -86,14 +86,14 @@ class TestMiddlePointOnArc(unittest.TestCase): while fullAngle < ANGLE_THRESHOLD: self.rotatePoint(self.myArc.startPoint(), self.myArc.center(), -ANGLE_STEP) model.do() - self.checkMiddlePoint(self.myLine.startPoint(), self.myArc) + self.checkMiddlePoint(self.myLine.startPoint().pnt(), self.myArc) fullAngle += ANGLE_STEP # move start point of the arc conterclockwise fullAngle = 0.0 while fullAngle < ANGLE_THRESHOLD: self.rotatePoint(self.myArc.startPoint(), self.myArc.center(), ANGLE_STEP) model.do() - self.checkMiddlePoint(self.myLine.startPoint(), self.myArc) + self.checkMiddlePoint(self.myLine.startPoint().pnt(), self.myArc) fullAngle += ANGLE_STEP # move end point of the arc clockwise @@ -101,14 +101,14 @@ class TestMiddlePointOnArc(unittest.TestCase): while fullAngle < ANGLE_THRESHOLD: self.rotatePoint(self.myArc.endPoint(), self.myArc.center(), -ANGLE_STEP) model.do() - self.checkMiddlePoint(self.myLine.startPoint(), self.myArc) + self.checkMiddlePoint(self.myLine.startPoint().pnt(), self.myArc) fullAngle += ANGLE_STEP # move end point of the arc conterclockwise fullAngle = 0.0 while fullAngle < ANGLE_THRESHOLD: self.rotatePoint(self.myArc.endPoint(), self.myArc.center(), ANGLE_STEP) model.do() - self.checkMiddlePoint(self.myLine.startPoint(), self.myArc) + self.checkMiddlePoint(self.myLine.startPoint().pnt(), self.myArc) fullAngle += ANGLE_STEP # move center of the arc @@ -118,14 +118,14 @@ class TestMiddlePointOnArc(unittest.TestCase): DELTA = [-DELTA[0], -DELTA[1]] self.mySketch.move(self.myArc.center(), self.myArc.center().x() + DELTA[0], self.myArc.center().y() + DELTA[1]) model.do() - self.checkMiddlePoint(self.myLine.startPoint(), self.myArc) + self.checkMiddlePoint(self.myLine.startPoint().pnt(), self.myArc) DELTA = [-1.0, 1.0] for i in range(0, 40): if i == 10 or i == 30: DELTA = [-DELTA[0], -DELTA[1]] self.mySketch.move(self.myArc.center(), self.myArc.center().x() + DELTA[0], self.myArc.center().y() + DELTA[1]) model.do() - self.checkMiddlePoint(self.myLine.startPoint(), self.myArc) + self.checkMiddlePoint(self.myLine.startPoint().pnt(), self.myArc) def moveLine(self): DELTA = [1.0, 0.0] @@ -134,14 +134,14 @@ class TestMiddlePointOnArc(unittest.TestCase): DELTA = [-DELTA[0], -DELTA[1]] self.mySketch.move(self.myLine.startPoint(), self.myLine.startPoint().x() + DELTA[0], self.myLine.startPoint().y() + DELTA[1]) model.do() - self.checkMiddlePoint(self.myLine.startPoint(), self.myArc) + self.checkMiddlePoint(self.myLine.startPoint().pnt(), self.myArc) DELTA = [0.0, 1.0] for i in range(0, 40): if i == 10 or i == 30: DELTA = [-DELTA[0], -DELTA[1]] self.mySketch.move(self.myLine.startPoint(), self.myLine.startPoint().x() + DELTA[0], self.myLine.startPoint().y() + DELTA[1]) model.do() - self.checkMiddlePoint(self.myLine.startPoint(), self.myArc) + self.checkMiddlePoint(self.myLine.startPoint().pnt(), self.myArc) def test_middle_point_PA(self): @@ -187,7 +187,7 @@ class TestMiddlePointOnArc(unittest.TestCase): self.myDOF -= 2 model.do() # this check will fail due to the limitation of PlanGCS - self.checkMiddlePoint(self.myLine.startPoint(), self.myArc) + self.checkMiddlePoint(self.myLine.startPoint().pnt(), self.myArc) def test_middle_point_move_arc(self): """ Test 6. Set middle point constraint and move arc @@ -195,7 +195,7 @@ class TestMiddlePointOnArc(unittest.TestCase): self.mySketch.setMiddlePoint(self.myLine.startPoint(), self.myArc.results()[1]) self.myDOF -= 2 model.do() - self.checkMiddlePoint(self.myLine.startPoint(), self.myArc) + self.checkMiddlePoint(self.myLine.startPoint().pnt(), self.myArc) self.moveArc() def test_middle_point_coincidence_move_arc(self): @@ -206,7 +206,7 @@ class TestMiddlePointOnArc(unittest.TestCase): self.mySketch.setMiddlePoint(self.myLine.startPoint(), self.myArc.results()[1]) self.myDOF -= 2 model.do() - self.checkMiddlePoint(self.myLine.startPoint(), self.myArc) + self.checkMiddlePoint(self.myLine.startPoint().pnt(), self.myArc) self.moveArc() def test_middle_point_move_line(self): @@ -215,7 +215,7 @@ class TestMiddlePointOnArc(unittest.TestCase): self.mySketch.setMiddlePoint(self.myLine.startPoint(), self.myArc.results()[1]) self.myDOF -= 2 model.do() - self.checkMiddlePoint(self.myLine.startPoint(), self.myArc) + self.checkMiddlePoint(self.myLine.startPoint().pnt(), self.myArc) self.moveLine() def test_middle_point_coincidence_move_line(self): @@ -226,7 +226,7 @@ class TestMiddlePointOnArc(unittest.TestCase): self.mySketch.setMiddlePoint(self.myLine.startPoint(), self.myArc.results()[1]) self.myDOF -= 2 model.do() - self.checkMiddlePoint(self.myLine.startPoint(), self.myArc) + self.checkMiddlePoint(self.myLine.startPoint().pnt(), self.myArc) self.moveLine() def test_remove_middle_point(self): @@ -236,7 +236,7 @@ class TestMiddlePointOnArc(unittest.TestCase): self.myDOF -= 2 model.do() model.assertArcValidity(self.myArc) - self.checkMiddlePoint(self.myLine.startPoint(), self.myArc) + self.checkMiddlePoint(self.myLine.startPoint().pnt(), self.myArc) self.checkDOF() # remove middle point self.myDocument.removeFeature(mp.feature()) @@ -246,6 +246,36 @@ class TestMiddlePointOnArc(unittest.TestCase): # set flag False to avoid checking middle point constraint in tearDown() method self.myTestPassed = False + def test_middle_point_by_object(self): + """ Test 11. Set middle point constraint on Arc + """ + self.myArc = self.mySketch.addArc(6, 4, 15, 1, 14, 9, False) + self.mySketch.setFixed(self.myArc.center()) + self.mySketch.setRadius(self.myArc.results()[1], 10) + + SketchLine_2 = self.mySketch.addLine(6, 4, 16, 4) + SketchLine_2.setAuxiliary(True) + self.mySketch.setCoincident(self.myArc.center(), SketchLine_2.startPoint()) + self.mySketch.setCoincident(self.myArc.startPoint(), SketchLine_2.endPoint()) + self.mySketch.setHorizontal(SketchLine_2.result()) + + SketchLine_3 = self.mySketch.addLine(6, 4, 14.66025403784439, 9) + SketchLine_3.setAuxiliary(True) + self.mySketch.setCoincident(self.myArc.center(), SketchLine_3.startPoint()) + self.mySketch.setCoincident(self.myArc.endPoint(), SketchLine_3.endPoint()) + + ### Create SketchConstraintAngle + self.mySketch.setAngle(SketchLine_2.result(), SketchLine_3.result(), 30, type = "Direct") + + # Ajout d'un point auxiliaire au milieu + SketchPoint_02 = self.mySketch.setMiddlePoint(self.myArc.results()[1]) + model.do() + + aPoint = SketchPoint_02.coordinates().pnt() + self.checkMiddlePoint(aPoint, self.myArc) + + # set flag False to avoid checking middle point constraint in tearDown() method + self.myTestPassed = False if __name__ == "__main__": test_program = unittest.main(exit=False) diff --git a/src/SketchPlugin/Test/TestConstraintMiddlePointOnEllipticArc.py b/src/SketchPlugin/Test/TestConstraintMiddlePointOnEllipticArc.py index 794a7d37b..714f9e949 100644 --- a/src/SketchPlugin/Test/TestConstraintMiddlePointOnEllipticArc.py +++ b/src/SketchPlugin/Test/TestConstraintMiddlePointOnEllipticArc.py @@ -281,6 +281,59 @@ class TestMiddlePointOnEllipticArc(unittest.TestCase): # set flag False to avoid checking middle point constraint in tearDown() method self.myTestPassed = False + def test_middle_point_by_object(self): + """ Test 12. Set middle point constraint on elliptic arc + """ + + self.myArc = self.mySketch.addEllipticArc(26.13481199028052, 14.44743211950145, 27.10553481386106, 8.942189418241149, 30, 8.856406460551019, 22, 11, False) + [SketchPoint_1, SketchPoint_2, SketchPoint_3, SketchPoint_4, SketchPoint_5, SketchPoint_6, SketchPoint_7, SketchLine_4, SketchLine_5] = self.myArc.construction(center = "aux", firstFocus = "aux", secondFocus = "aux", majorAxisStart = "aux", majorAxisEnd = "aux", minorAxisStart = "aux", minorAxisEnd = "aux", majorAxis = "aux", minorAxis = "aux") + self.mySketch.setLength(SketchLine_5.result(), 10) + self.mySketch.setLength(SketchLine_4.result(), 15) + + ### Create SketchProjection + SketchProjection_1 = self.mySketch.addProjection(model.selection("EDGE", "PartSet/OX"), False) + SketchLine_6 = SketchProjection_1.createdFeature() + + ### Create SketchConstraintAngle + self.mySketch.setAngle(SketchLine_6.result(), SketchLine_5.result(), 10, type = "Direct") + + ### Create SketchProjection + SketchProjection_2 = self.mySketch.addProjection(model.selection("EDGE", "PartSet/OX"), False) + SketchLine_7 = SketchProjection_2.createdFeature() + + ### Create SketchLine + SketchLine_8 = self.mySketch.addLine(22, 11, 30, 8.856406460551019) + SketchLine_8.setAuxiliary(True) + self.mySketch.setCoincident(self.myArc.endPoint(), SketchLine_8.startPoint()) + self.mySketch.setCoincident(self.myArc.startPoint(), SketchLine_8.endPoint()) + + ### Create SketchConstraintAngle + self.mySketch.setAngle(SketchLine_7.result(), SketchLine_8.result(), 15, type = "Direct") + + ### Create SketchProjection + SketchProjection_3 = self.mySketch.addProjection(model.selection("VERTEX", "PartSet/Origin"), False) + SketchPoint_8 = SketchProjection_3.createdFeature() + self.mySketch.setHorizontalDistance(SketchAPI_Point(SketchPoint_8).coordinates(), SketchLine_8.startPoint(), 22) + + ### Create SketchProjection + SketchProjection_4 = self.mySketch.addProjection(model.selection("VERTEX", "PartSet/Origin"), False) + SketchPoint_9 = SketchProjection_4.createdFeature() + self.mySketch.setVerticalDistance(SketchAPI_Point(SketchPoint_9).coordinates(), SketchLine_8.startPoint(), 11) + + ### Create SketchProjection + SketchProjection_5 = self.mySketch.addProjection(model.selection("VERTEX", "PartSet/Origin"), False) + SketchPoint_10 = SketchProjection_5.createdFeature() + self.mySketch.setHorizontalDistance(SketchAPI_Point(SketchPoint_10).coordinates(), SketchLine_8.endPoint(), 30) + + # Create auxiliaire middle point + SketchPoint_03 = self.mySketch.setMiddlePoint(self.myArc.result()) + model.do() + + aPoint = SketchPoint_03.result().resultSubShapePair()[0].shape().vertex().point() + self.checkMiddlePoint(self.mySketch.to2D(aPoint), self.myArc) + + # set flag False to avoid checking middle point constraint in tearDown() method + self.myTestPassed = False if __name__ == "__main__": test_program = unittest.main(exit=False) diff --git a/src/SketchPlugin/doc/examples/middle.py b/src/SketchPlugin/doc/examples/middle.py index c6aa514e2..b37468fc1 100644 --- a/src/SketchPlugin/doc/examples/middle.py +++ b/src/SketchPlugin/doc/examples/middle.py @@ -8,5 +8,8 @@ Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY")) SketchCircle_1 = Sketch_1.addCircle(16, 54, 10) SketchLine_1 = Sketch_1.addLine(10, 10, 80, 80) SketchConstraintMiddle_1 = Sketch_1.setMiddlePoint(SketchCircle_1.center(), SketchLine_1.result()) + +SketchLine_2 = Sketch_1.addLine(20, 10, 90, 80) +SketchPoint_01 = Sketch_1.setMiddlePoint(SketchLine_2.result()) model.do() model.end() diff --git a/src/SketchPlugin/doc/images/MiddlePoint_obj.png b/src/SketchPlugin/doc/images/MiddlePoint_obj.png new file mode 100644 index 0000000000000000000000000000000000000000..af1252161e0d28dbd966b5dd5bee2f4a4fe33314 GIT binary patch literal 312 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 literal 0 HcmV?d00001 diff --git a/src/SketchPlugin/doc/images/Middlepoint_obj_point_panel.png b/src/SketchPlugin/doc/images/Middlepoint_obj_point_panel.png new file mode 100644 index 0000000000000000000000000000000000000000..762dd99814ce2fe3962564fc2afad8383230fff6 GIT binary patch literal 6698 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 b^n?FUb|6F2!q?mXJ9saYv>+vlmO=jp86wN{ literal 0 HcmV?d00001 diff --git a/src/SketchPlugin/doc/images/Middlepoint_res.png b/src/SketchPlugin/doc/images/Middlepoint_obj_point_res.png similarity index 100% rename from src/SketchPlugin/doc/images/Middlepoint_res.png rename to src/SketchPlugin/doc/images/Middlepoint_obj_point_res.png diff --git a/src/SketchPlugin/doc/images/Middlepoint_obj_res.png b/src/SketchPlugin/doc/images/Middlepoint_obj_res.png new file mode 100644 index 0000000000000000000000000000000000000000..d46c16d0a2c78a8b723e4d575301f52b86e3dedf GIT binary patch literal 8482 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 KRU%>J^FIJYL Middle point* item or #. click |middlepoint.icon| **Middle point** button in Sketch toolbar: +There are 2 algorithms for creation of a middle constraint: + +.. figure:: images/MiddlePoint.png + :align: left + :height: 24px + +**By object and point** create a middle constraint by object (segment or arc) and point + +.. figure:: images/MiddlePoint_obj.png + :align: left + :height: 24px + +**By object** create a middle point on the object (segment or arc) + +------------------------------------------------------------------------------------------- + +By object and point +"""""""""""""""""""""""""" Property panel: -.. figure:: images/Middlepoint_panel.png +.. figure:: images/Middlepoint_obj_point_panel.png :align: center Input fields: @@ -38,7 +56,38 @@ Result Created Middle point constraint appears in the view. -.. figure:: images/Middlepoint_res.png +.. figure:: images/Middlepoint_obj_point_res.png + :align: center + + Created middle point constraint + +By object +"""""""""""""""""""""""""" +Property panel: + +.. figure:: images/Middlepoint_obj_panel.png + :align: center + +Input fields: + +- **Object** is a line selected in the view. + +| After the object are selected, will be created auxiliary point on the middle of the line. +| The middle points are marked with a special sign. + +**TUI Command**: + +.. py:function:: SketchPoint_1 = Sketch_1.setMiddlePoint(Line) + + :param object: A line. + :return: Created middle point. + +Result +"""""" + +Created Middle point constraint appears in the view. + +.. figure:: images/Middlepoint_obj_res.png :align: center Created middle point constraint diff --git a/src/SketchPlugin/icons/middlepoint_obj.png b/src/SketchPlugin/icons/middlepoint_obj.png new file mode 100644 index 0000000000000000000000000000000000000000..af1252161e0d28dbd966b5dd5bee2f4a4fe33314 GIT binary patch literal 312 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4-%f*x^(K7$MC~J4lO;MKZ9J6(rl1yf>9JH?BTwMM^Ky7v8ZuSj1A}kYi**@m` zy!xf6!*-i*PwI^F8ImVH$aBaXj1b^VIv5l1`)GpFgi>k8lh>a8y;q=HFgayU6wAA( zIoXE;7mHTLeNEwcI=yiL=M43UlQr(;$4?er!o@blC!ye#{72rHUgOs2`>RUd$ZdNY z`QUw!7(=6agxat7tj$;4PaolMa(sTfLh@b(LyMC` - - - - - - - - - - + + + + + + + + + + + + + + + + diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.cpp index ab382114e..1f0fd0e7c 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.cpp @@ -527,7 +527,6 @@ bool PlaneGCSSolver_Tools::isAttributeApplicable(const std::string& theAttrName, theAttrName == SketchPlugin_BSplinePeriodic::MULTS_ID() || theAttrName == SketchPlugin_BSplinePeriodic::DEGREE_ID(); } - // suppose that all remaining features are points return theAttrName == SketchPlugin_Point::COORD_ID(); } -- 2.30.2