From: Artem Zhidkov Date: Thu, 2 Jul 2020 11:06:46 +0000 (+0300) Subject: Task #3235: Projection without link to source shape X-Git-Tag: V9_6_0a1~63 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=f0ff622da83f8272bd5d8ef3dcc00116fd2573dd;p=modules%2Fshaper.git Task #3235: Projection without link to source shape * Improve the Projection feature by an option to break the link with the original shape. * Update unit-tests for ellipse's projection, because of solved OCCT issue #31016. --- diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_Projection.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_Projection.cpp index 94c22465a..f0c836ac2 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_Projection.cpp +++ b/src/GeomAlgoAPI/GeomAlgoAPI_Projection.cpp @@ -42,7 +42,8 @@ GeomCurvePtr GeomAlgoAPI_Projection::project(const GeomCurvePtr& theCurve) Handle(Geom_Curve) aCurve = theCurve->impl(); Handle(Geom_Plane) aPlane = new Geom_Plane(myPlane->impl()); - Handle(Geom_Curve) aProj = GeomProjLib::Project(aCurve, aPlane); + Handle(Geom_Curve) aProj = + GeomProjLib::ProjectOnPlane(aCurve, aPlane, aPlane->Axis().Direction(), false); GeomCurvePtr aProjCurve(new GeomAPI_Curve); aProjCurve->setImpl(new Handle_Geom_Curve(aProj)); diff --git a/src/ModuleBase/ModuleBase_PagedContainer.cpp b/src/ModuleBase/ModuleBase_PagedContainer.cpp index 267d2d4cf..f821c793f 100644 --- a/src/ModuleBase/ModuleBase_PagedContainer.cpp +++ b/src/ModuleBase/ModuleBase_PagedContainer.cpp @@ -107,7 +107,8 @@ bool ModuleBase_PagedContainer::restoreValueCustom() aCaseId = QString::fromStdString(aStringAttr->value()); else aCaseId = QString::fromStdString(aDefVal.empty() ? aStringAttr->value() : aDefVal); - myIsFirst = false; + if (myIsFirst) + storeValueCustom(); int idx = myCaseIds.indexOf(aCaseId); if (idx == -1) idx = currentPageIndex(); diff --git a/src/ModuleBase/ModuleBase_WidgetRadiobox.cpp b/src/ModuleBase/ModuleBase_WidgetRadiobox.cpp index 5c6da8797..aa76b42ec 100644 --- a/src/ModuleBase/ModuleBase_WidgetRadiobox.cpp +++ b/src/ModuleBase/ModuleBase_WidgetRadiobox.cpp @@ -20,12 +20,13 @@ #include #include +#include + #include #include #include #include - ModuleBase_WidgetRadiobox::ModuleBase_WidgetRadiobox(QWidget* theParent, const Config_WidgetAPI* theData) : ModuleBase_PagedContainer(theParent, theData) @@ -35,6 +36,8 @@ ModuleBase_WidgetRadiobox::ModuleBase_WidgetRadiobox(QWidget* theParent, myGroup = new QButtonGroup(this); myGroup->setExclusive(true); + myVerticalAlignment = theData->getProperty("align_subs").find("vert") == 0; + connect(myGroup, SIGNAL(buttonToggled(int, bool)), SLOT(onPageChanged())); } @@ -68,7 +71,11 @@ int ModuleBase_WidgetRadiobox::addPage(ModuleBase_PageBase* thePage, //QFrame* aFrame = dynamic_cast(thePage); QWidget* aPage = thePage->pageWidget(); - myLayout->addRow(aWgt, aPage); + if (myVerticalAlignment) { + myLayout->addRow(aWgt); + myLayout->addRow(aPage); + } else + myLayout->addRow(aWgt, aPage); myGroup->addButton(aButton, myGroup->buttons().count()); bool isDefault = theCaseId.toStdString() == getDefaultValue(); diff --git a/src/ModuleBase/ModuleBase_WidgetRadiobox.h b/src/ModuleBase/ModuleBase_WidgetRadiobox.h index ef35a0f96..cffb45a21 100644 --- a/src/ModuleBase/ModuleBase_WidgetRadiobox.h +++ b/src/ModuleBase/ModuleBase_WidgetRadiobox.h @@ -59,6 +59,7 @@ protected: private: QFormLayout* myLayout; QButtonGroup* myGroup; + bool myVerticalAlignment; }; #endif \ No newline at end of file diff --git a/src/PartSet/PartSet_SketcherMgr.cpp b/src/PartSet/PartSet_SketcherMgr.cpp index 4aadcdd97..b52154da9 100644 --- a/src/PartSet/PartSet_SketcherMgr.cpp +++ b/src/PartSet/PartSet_SketcherMgr.cpp @@ -2266,7 +2266,7 @@ bool isIncludeToResult(const ObjectPtr& theObject) for (aIt = aRefsToMe.cbegin(); aIt != aRefsToMe.cend(); ++aIt) { if ((*aIt)->id() == SketchPlugin_Projection::PROJECTED_FEATURE_ID()) { FeaturePtr aFeature = std::dynamic_pointer_cast((*aIt)->owner()); - if (aFeature.get()) { + if (aFeature.get() && !aFeature->isMacro()) { anAttr = aFeature->data()->boolean(SketchPlugin_Projection::INCLUDE_INTO_RESULT()); if (anAttr.get()) return anAttr->value(); diff --git a/src/SketchAPI/SketchAPI.i b/src/SketchAPI/SketchAPI.i index 98bc2c6ab..66b07c3cc 100644 --- a/src/SketchAPI/SketchAPI.i +++ b/src/SketchAPI/SketchAPI.i @@ -50,9 +50,10 @@ %feature("kwargs") SketchAPI_BSpline::controlPolygon; %feature("kwargs") SketchAPI_Ellipse::construction; %feature("kwargs") SketchAPI_EllipticArc::construction; -%feature("kwargs") SketchAPI_Sketch::addSpline; -%feature("kwargs") SketchAPI_Sketch::addInterpolation; %feature("kwargs") SketchAPI_Sketch::addApproximation; +%feature("kwargs") SketchAPI_Sketch::addInterpolation; +%feature("kwargs") SketchAPI_Sketch::addProjection; +%feature("kwargs") SketchAPI_Sketch::addSpline; %feature("kwargs") SketchAPI_Sketch::setAngle; // shared pointers diff --git a/src/SketchAPI/SketchAPI_Projection.cpp b/src/SketchAPI/SketchAPI_Projection.cpp index 225188378..bee330063 100644 --- a/src/SketchAPI/SketchAPI_Projection.cpp +++ b/src/SketchAPI/SketchAPI_Projection.cpp @@ -56,16 +56,6 @@ SketchAPI_Projection::SketchAPI_Projection( } } -SketchAPI_Projection::SketchAPI_Projection( - const std::shared_ptr & theFeature, - const std::string & theExternalName) -: SketchAPI_SketchEntity(theFeature) -{ - if (initialize()) { - setByExternalName(theExternalName); - } -} - SketchAPI_Projection::~SketchAPI_Projection() { @@ -79,14 +69,18 @@ void SketchAPI_Projection::setExternalFeature(const ModelHighAPI_Selection & the execute(true); } -void SketchAPI_Projection::setByExternalName(const std::string& theExternalName) +void SketchAPI_Projection::setIncludeToResult(bool theKeepResult) { - setExternalFeature(ModelHighAPI_Selection("EDGE", theExternalName)); + fillAttribute(theKeepResult, includeToResult()); + execute(true); } -void SketchAPI_Projection::setIncludeToResult(bool theKeepResult) +void SketchAPI_Projection::setKeepReferenceToOriginal(bool theKeepRefToOriginal) { - fillAttribute(theKeepResult, includeToResult()); + // the Fixed constraint should be assigned explicitly + fillAttribute(false, feature()->boolean(SketchPlugin_Projection::MAKE_FIXED())); + fillAttribute(theKeepRefToOriginal ? "true" : "false", + feature()->string(SketchPlugin_Projection::KEEP_REFERENCE_ID())); execute(true); } diff --git a/src/SketchAPI/SketchAPI_Projection.h b/src/SketchAPI/SketchAPI_Projection.h index d064f170d..cfa3af1ac 100644 --- a/src/SketchAPI/SketchAPI_Projection.h +++ b/src/SketchAPI/SketchAPI_Projection.h @@ -43,10 +43,6 @@ public: SKETCHAPI_EXPORT SketchAPI_Projection(const std::shared_ptr & theFeature, const ModelHighAPI_Selection & theExternalFeature); - /// Constructor with values - SKETCHAPI_EXPORT - SketchAPI_Projection(const std::shared_ptr & theFeature, - const std::string & theExternalName); /// Destructor SKETCHAPI_EXPORT virtual ~SketchAPI_Projection(); @@ -66,14 +62,14 @@ public: SKETCHAPI_EXPORT void setExternalFeature(const ModelHighAPI_Selection & theExternalLine); - /// Set by external name - SKETCHAPI_EXPORT - void setByExternalName(const std::string & theExternalName); - /// Set flag to include projection to result or not SKETCHAPI_EXPORT void setIncludeToResult(bool theKeepResult); + /// Set flag to keep the reference to the original shape + SKETCHAPI_EXPORT + void setKeepReferenceToOriginal(bool theKeepRefToOriginal); + /// Returns created feature SKETCHAPI_EXPORT std::shared_ptr createdFeature() const; diff --git a/src/SketchAPI/SketchAPI_Sketch.cpp b/src/SketchAPI/SketchAPI_Sketch.cpp index 2f6ffcdfa..e76cfb3a2 100644 --- a/src/SketchAPI/SketchAPI_Sketch.cpp +++ b/src/SketchAPI/SketchAPI_Sketch.cpp @@ -861,23 +861,15 @@ std::shared_ptr SketchAPI_Sketch::addApproximation( //-------------------------------------------------------------------------------------- std::shared_ptr SketchAPI_Sketch::addProjection( const ModelHighAPI_Selection & theExternalFeature, - bool theKeepResult) -{ - std::shared_ptr aFeature = - compositeFeature()->addFeature(SketchPlugin_Projection::ID()); - ProjectionPtr aProjection(new SketchAPI_Projection(aFeature, theExternalFeature)); - aProjection->setIncludeToResult(theKeepResult); - return aProjection; -} - -std::shared_ptr SketchAPI_Sketch::addProjection( - const std::string & theExternalName, - bool theKeepResult) + bool keepResult, + bool keepRefToOriginal) { std::shared_ptr aFeature = compositeFeature()->addFeature(SketchPlugin_Projection::ID()); - ProjectionPtr aProjection(new SketchAPI_Projection(aFeature, theExternalName)); - aProjection->setIncludeToResult(theKeepResult); + ProjectionPtr aProjection(new SketchAPI_Projection(aFeature)); + aProjection->setIncludeToResult(keepResult); + aProjection->setKeepReferenceToOriginal(keepRefToOriginal); + aProjection->setExternalFeature(theExternalFeature); return aProjection; } diff --git a/src/SketchAPI/SketchAPI_Sketch.h b/src/SketchAPI/SketchAPI_Sketch.h index 3911015de..2bdf2a570 100644 --- a/src/SketchAPI/SketchAPI_Sketch.h +++ b/src/SketchAPI/SketchAPI_Sketch.h @@ -358,12 +358,8 @@ public: SKETCHAPI_EXPORT std::shared_ptr addProjection( const ModelHighAPI_Selection & theExternalFeature, - bool theKeepResult = false); - - /// Add projection - SKETCHAPI_EXPORT - std::shared_ptr addProjection(const std::string & theExternalName, - bool theKeepResult = false); + bool keepResult = false, + bool keepRefToOriginal = true); /// Add mirror SKETCHAPI_EXPORT diff --git a/src/SketchAPI/Test/TestSketch.py b/src/SketchAPI/Test/TestSketch.py index b12543d8b..ea656e939 100644 --- a/src/SketchAPI/Test/TestSketch.py +++ b/src/SketchAPI/Test/TestSketch.py @@ -173,7 +173,7 @@ class SketchTestCase(unittest.TestCase): def test_arc_by_projection(self): """ Test 10. Create arc by projection of external feature """ - self.sketch.addProjection("[Cylinder_2_1/Face_1][Cylinder_2_1/Face_3]") + self.sketch.addProjection(model.selection("EDGE", "[Cylinder_2_1/Face_1][Cylinder_2_1/Face_3]")) model.do() anArc = SketchAPI.SketchAPI_Arc(model.lastSubFeature(self.sketch, "SketchArc")) diff --git a/src/SketchPlugin/CMakeLists.txt b/src/SketchPlugin/CMakeLists.txt index aa51871dc..8093a9062 100644 --- a/src/SketchPlugin/CMakeLists.txt +++ b/src/SketchPlugin/CMakeLists.txt @@ -336,6 +336,7 @@ ADD_UNIT_TESTS( TestProjectionEllipticArc.py TestProjectionIntoResult.py TestProjectionUpdate.py + TestProjectionWithoutReference.py TestRectangle.py TestRemainingDoF.py TestRemoveBSpline.py diff --git a/src/SketchPlugin/SketchPlugin_Ellipse.cpp b/src/SketchPlugin/SketchPlugin_Ellipse.cpp index f5ca95176..6ff0a3021 100644 --- a/src/SketchPlugin/SketchPlugin_Ellipse.cpp +++ b/src/SketchPlugin/SketchPlugin_Ellipse.cpp @@ -134,7 +134,7 @@ bool SketchPlugin_Ellipse::fillCharacteristicPoints() return false; } - data()->blockSendAttributeUpdated(true); + bool aWasBlocked = data()->blockSendAttributeUpdated(true); GeomPnt2dPtr aCenter2d = aCenterAttr->pnt(); GeomPnt2dPtr aFocus2d = aFocusAttr->pnt(); GeomDir2dPtr aMajorDir2d(new GeomAPI_Dir2d(aFocus2d->x() - aCenter2d->x(), @@ -144,7 +144,9 @@ bool SketchPlugin_Ellipse::fillCharacteristicPoints() AttributeDoublePtr aMajorRadiusAttr = real(MAJOR_RADIUS_ID()); double aFocalDist = aCenter2d->distance(aFocus2d); double aMajorRadius = sqrt(aFocalDist * aFocalDist + aMinorRadius * aMinorRadius); - aMajorRadiusAttr->setValue(aMajorRadius); + if (!aMajorRadiusAttr->isInitialized() || + fabs(aMajorRadiusAttr->value() - aMajorRadius) > tolerance) + aMajorRadiusAttr->setValue(aMajorRadius); std::dynamic_pointer_cast(attribute(SECOND_FOCUS_ID())) ->setValue(2.0 * aCenter2d->x() - aFocus2d->x(), 2.0 * aCenter2d->y() - aFocus2d->y()); @@ -160,7 +162,7 @@ bool SketchPlugin_Ellipse::fillCharacteristicPoints() std::dynamic_pointer_cast(attribute(MINOR_AXIS_END_ID())) ->setValue(aCenter2d->x() + aMinorDir2d->x() * aMinorRadius, aCenter2d->y() + aMinorDir2d->y() * aMinorRadius); - data()->blockSendAttributeUpdated(false); + data()->blockSendAttributeUpdated(aWasBlocked); return true; } diff --git a/src/SketchPlugin/SketchPlugin_Projection.cpp b/src/SketchPlugin/SketchPlugin_Projection.cpp index e0e6222bc..9133b197d 100644 --- a/src/SketchPlugin/SketchPlugin_Projection.cpp +++ b/src/SketchPlugin/SketchPlugin_Projection.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -59,6 +60,12 @@ #include static const double tolerance = 1.e-7; +static const std::string THE_KEEP_REF("true"); + +static bool isKeepReference(AttributeStringPtr theAttr) +{ + return !theAttr || !theAttr->isInitialized() || theAttr->value() == THE_KEEP_REF; +} SketchPlugin_Projection::SketchPlugin_Projection() @@ -71,6 +78,7 @@ void SketchPlugin_Projection::initDerivedClassAttributes() { data()->addAttribute(EXTERNAL_FEATURE_ID(), ModelAPI_AttributeSelection::typeId()); data()->addAttribute(PROJECTED_FEATURE_ID(), ModelAPI_AttributeRefAttr::typeId()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PROJECTED_FEATURE_ID()); data()->attribute(PROJECTED_FEATURE_ID())->setIsArgument(false); data()->addAttribute(EXTERNAL_ID(), ModelAPI_AttributeSelection::typeId()); @@ -81,6 +89,22 @@ void SketchPlugin_Projection::initDerivedClassAttributes() ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), AUXILIARY_ID()); } +void SketchPlugin_Projection::initDerivedClassAttributes2() +{ + AttributePtr aKeepRefAttr = + data()->addAttribute(KEEP_REFERENCE_ID(), ModelAPI_AttributeString::typeId()); + if (!aKeepRefAttr->isInitialized()) { + std::dynamic_pointer_cast(aKeepRefAttr)->setValue(THE_KEEP_REF); + } + + data()->addAttribute(MAKE_FIXED(), ModelAPI_AttributeBoolean::typeId()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), MAKE_FIXED()); + + data()->addAttribute(FIXED_CONSTRAINT_ID(), ModelAPI_AttributeReference::typeId()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), FIXED_CONSTRAINT_ID()); + data()->attribute(FIXED_CONSTRAINT_ID())->setIsArgument(false); +} + void SketchPlugin_Projection::execute() { AttributeRefAttrPtr aRefAttr = data()->refattr(PROJECTED_FEATURE_ID()); @@ -88,7 +112,7 @@ void SketchPlugin_Projection::execute() return; FeaturePtr aProjection = ModelAPI_Feature::feature(aRefAttr->object()); - if (!lastResult().get()) { + if (isKeepReference(string(KEEP_REFERENCE_ID())) && !lastResult().get()) { bool hasProjResult = aProjection->lastResult().get() != NULL; ResultConstructionPtr aConstr = document()->createConstruction(data()); if (hasProjResult) @@ -106,6 +130,16 @@ void SketchPlugin_Projection::execute() computeProjection(EXTERNAL_FEATURE_ID()); } +bool SketchPlugin_Projection::isMacro() const +{ + if (!data() || !data()->isValid()) + return false; + + AttributeStringPtr aKeepRefAttr = + const_cast(this)->string(KEEP_REFERENCE_ID()); + return !isKeepReference(aKeepRefAttr); +} + void SketchPlugin_Projection::attributeChanged(const std::string& theID) { if ((theID == EXTERNAL_FEATURE_ID() || theID == EXTERNAL_ID()) && !myIsComputing) { @@ -233,25 +267,52 @@ void SketchPlugin_Projection::computeProjection(const std::string& theID) if (!isProjected) return; // projection is not computed, stop processing - aProjection->boolean(COPY_ID())->setValue(true); + bool keepBackRef = isKeepReference(string(KEEP_REFERENCE_ID())); + + aProjection->boolean(COPY_ID())->setValue(keepBackRef); aProjection->execute(); aRefAttr->setObject(aProjection); restoreCurrentFeature(); - if (theID == EXTERNAL_FEATURE_ID()) { - selection(EXTERNAL_ID())->selectValue(aExtFeature); + AttributeBooleanPtr aMakeFixedAttr = boolean(MAKE_FIXED()); + bool isMakeFixed = aMakeFixedAttr && aMakeFixedAttr->isInitialized() && aMakeFixedAttr->value(); + + AttributeReferencePtr aFixedConstrAttr = reference(FIXED_CONSTRAINT_ID()); + FeaturePtr aFixedConstraint; + if (aFixedConstrAttr && aFixedConstrAttr->isInitialized()) + aFixedConstraint = ModelAPI_Feature::feature(aFixedConstrAttr->value()); - if (aResult) { - aResult->setShape(aProjection->lastResult()->shape()); - setResult(aResult); - GeomShapePtr anEmptyVal; - aProjection->selection(EXTERNAL_ID())->setValue(lastResult(), anEmptyVal); + if (keepBackRef) { + if (theID == EXTERNAL_FEATURE_ID()) { + selection(EXTERNAL_ID())->selectValue(aExtFeature); - static const Events_ID anEvent = Events_Loop::eventByName(EVENT_VISUAL_ATTRIBUTES); - ModelAPI_EventCreator::get()->sendUpdated(aProjection, anEvent, false); + if (aResult) { + aResult->setShape(aProjection->lastResult()->shape()); + setResult(aResult); + GeomShapePtr anEmptyVal; + aProjection->selection(EXTERNAL_ID())->setValue(lastResult(), anEmptyVal); + } } } + else if (isMakeFixed) { + // fix the projected entity with the Fixed constraint + if (!aFixedConstraint) + aFixedConstraint = sketch()->addFeature(SketchPlugin_ConstraintRigid::ID()); + aFixedConstraint->refattr(SketchPlugin_Constraint::ENTITY_A())->setObject( + aProjection->lastResult()); + } + + + // remove Fixed constraint in case of redundance + if (aFixedConstraint && (keepBackRef || !isMakeFixed)) { + document()->removeFeature(aFixedConstraint); + aFixedConstraint = FeaturePtr(); + } + aFixedConstrAttr->setValue(aFixedConstraint); + + static const Events_ID anEvent = Events_Loop::eventByName(EVENT_VISUAL_ATTRIBUTES); + ModelAPI_EventCreator::get()->sendUpdated(aProjection, anEvent, false); } bool SketchPlugin_Projection::rebuildProjectedFeature( diff --git a/src/SketchPlugin/SketchPlugin_Projection.h b/src/SketchPlugin/SketchPlugin_Projection.h index 64f7844b7..aea956bc5 100644 --- a/src/SketchPlugin/SketchPlugin_Projection.h +++ b/src/SketchPlugin/SketchPlugin_Projection.h @@ -62,6 +62,24 @@ public: return MY_INCLUDE; } + static const std::string& KEEP_REFERENCE_ID() + { + static std::string ID("keep_reference"); + return ID; + } + + static const std::string& MAKE_FIXED() + { + static std::string ID("make_fixed"); + return ID; + } + + static const std::string& FIXED_CONSTRAINT_ID() + { + static std::string ID("fixed_constraint"); + return ID; + } + /// Returns true because projected feature is always external virtual bool isFixed() { return true; } @@ -79,6 +97,11 @@ public: /// Called on change of any argument-attribute of this object: for external point SKETCHPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID); + /// Returns true if this feature is used as macro: creates other features and then removed. + /// This feature may change its macro-state according to selected item. + /// \returns false by default + SKETCHPLUGIN_EXPORT virtual bool isMacro() const; + /// Use plugin manager for features creation SketchPlugin_Projection(); @@ -86,6 +109,9 @@ protected: /// \brief Initializes attributes of derived class. virtual void initDerivedClassAttributes(); + /// \brief Initializes attributes of keeping the reference to the original shape. + virtual void initDerivedClassAttributes2(); + private: /// \brief Find projection of a feature onto sketch plane void computeProjection(const std::string& theID); diff --git a/src/SketchPlugin/SketchPlugin_SketchEntity.cpp b/src/SketchPlugin/SketchPlugin_SketchEntity.cpp index fb64f079c..e44941948 100644 --- a/src/SketchPlugin/SketchPlugin_SketchEntity.cpp +++ b/src/SketchPlugin/SketchPlugin_SketchEntity.cpp @@ -43,4 +43,7 @@ void SketchPlugin_SketchEntity::initAttributes() anAttr = data()->addAttribute(PARENT_ID(), ModelAPI_AttributeReference::typeId()); anAttr->setIsArgument(false); ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PARENT_ID()); + + // initialize the rest of attributes + initDerivedClassAttributes2(); } diff --git a/src/SketchPlugin/SketchPlugin_SketchEntity.h b/src/SketchPlugin/SketchPlugin_SketchEntity.h index c9a3e29a1..0fabd0bbb 100644 --- a/src/SketchPlugin/SketchPlugin_SketchEntity.h +++ b/src/SketchPlugin/SketchPlugin_SketchEntity.h @@ -227,6 +227,9 @@ protected: /// \brief Initializes attributes of derived class. virtual void initDerivedClassAttributes(){}; + /// \brief Initializes attributes of derived class which were added recently. + virtual void initDerivedClassAttributes2(){}; + }; #endif diff --git a/src/SketchPlugin/SketchPlugin_Validators.cpp b/src/SketchPlugin/SketchPlugin_Validators.cpp index feaec5c66..14920c109 100644 --- a/src/SketchPlugin/SketchPlugin_Validators.cpp +++ b/src/SketchPlugin/SketchPlugin_Validators.cpp @@ -1259,7 +1259,7 @@ bool SketchPlugin_ProjectionValidator::isValid(const AttributePtr& theAttribute, std::shared_ptr anEllipse = anEdge->ellipse(); std::shared_ptr anEllipseNormal = anEllipse->normal(); double aDot = fabs(aNormal->dot(anEllipseNormal)); - aValid = fabs(aDot - 1.0) <= tolerance * tolerance; + aValid = aDot >= tolerance * tolerance; if (!aValid) theError.arg(anEdge->isClosed() ? "Error: Ellipse is orthogonal to the sketch plane." : "Error: Elliptic Arc is orthogonal to the sketch plane."); diff --git a/src/SketchPlugin/SketchPlugin_msg_en.ts b/src/SketchPlugin/SketchPlugin_msg_en.ts index aad453f54..6ee4690a4 100644 --- a/src/SketchPlugin/SketchPlugin_msg_en.ts +++ b/src/SketchPlugin/SketchPlugin_msg_en.ts @@ -2220,7 +2220,66 @@ Edges in selected point has tangent constraint - + + + SketchProjection + + Project feature onto sketch plane + Project feature onto sketch plane + + + Projection + Projection + + + + SketchProjection:ExternalFeature + + Attribute "%1" is not initialized. + Select external edge or vertex. + + + Object + Object + + + Select external edge or vertex. + Select external edge or vertex. + + + + SketchProjection:IncludeToResult + + Include into the sketch result + Include into the sketch result + + + Include projected feature into the sketch result + Include projected feature into the sketch result + + + + SketchProjection:keep_reference + + A sketch entity will be created without connection to the selected shape. + A sketch entity will be created without connection to the selected shape. + + + The reference to the original curve is stored. So it can be changed later. + The reference to the original curve is stored. So it can be changed later. + + + + SketchProjection:make_fixed + + Assign the Fixed constraint to the result of projection + Assign the Fixed constraint to the result of projection + + + Make projected curve fixed + Make projected curve fixed + + SketchProjection:ExternalFeature:SketchPlugin_ProjectionValidator @@ -2264,13 +2323,6 @@ Error: Selected object is not supported for projection. - - SketchProjection:Model_FeatureValidator - - Attribute "%1" is not initialized. - - - diff --git a/src/SketchPlugin/SketchPlugin_msg_fr.ts b/src/SketchPlugin/SketchPlugin_msg_fr.ts index d509191c4..74e559170 100644 --- a/src/SketchPlugin/SketchPlugin_msg_fr.ts +++ b/src/SketchPlugin/SketchPlugin_msg_fr.ts @@ -2118,76 +2118,6 @@ - - SketchProjection:ExternalFeature:SketchPlugin_ProjectionValidator - - The attribute with the %1 type is not processed - Un argument de type %1 de la fonctionnalité de projection n'est pas pris en charge - - - The attribute %1 should be an edge - L'attribut %1 doit être une arête - - - There is no sketch referring to the current feature - La fonction de projection n'a pas d'esquisse - - - The attribute %1 should be an edge or vertex - L'élément projeté doit être une arête ou un sommet - - - Unable to project feature from the same sketch - Les fonctions de l'esquisse en cours ne peuvent pas être projetées - - - Error: Line is orthogonal to the sketch plane. - Erreur: La ligne est orthogonale au plan d'esquisse. - - - Error: Circle is orthogonal to the sketch plane. - Erreur: Le cercle est orthogonal au plan d'esquisse. - - - Error: Arc is orthogonal to the sketch plane. - Erreur: L'arc est orthogonal au plan d'esquisse. - - - Error: Ellipse is orthogonal to the sketch plane. - Erreur: L'ellipse est orthogonale au plan d'esquisse. - - - Error: Elliptic Arc is orthogonal to the sketch plane. - Erreur: L'arc d'ellipse est orthogonal au plan d'esquisse. - - - Error: Selected object is not supported for projection. - Erreur: L'objet sélectionné n'est pas pris en charge pour la projection. - - - - SketchProjection:Model_FeatureValidator - - Attribute "%1" is not initialized. - L'attribut "%1" n'est pas initialisé. - - - - SketchProjection:ExternalFeature - - Attribute "%1" is not initialized. - L'attribut "%1" n'est pas initialisé. - - - Object - Objet - - - Select external edge or vertex. - Sélectionnez une arête externe ou un sommet. - - - Sketch @@ -3989,6 +3919,97 @@ Inclure la fonctionnalité projetée dans le résultat de l'esquisse + + SketchProjection:keep_reference + + A sketch entity will be created without connection to the selected shape. + Une entité d'esquisse sera créée sans connexion à la forme sélectionnée. + + + The reference to the original curve is stored. So it can be changed later. + La référence à la courbe d'origine est stockée. Elle peut donc être modifiée ultérieurement. + + + + SketchProjection:make_fixed + + Assign the Fixed constraint to the result of projection + Affectez la contrainte Fixe au résultat de la projection + + + Make projected curve fixed + Fixer la courbe projetée + + + + SketchProjection:ExternalFeature:SketchPlugin_ProjectionValidator + + The attribute with the %1 type is not processed + Un argument de type %1 de la fonctionnalité de projection n'est pas pris en charge + + + The attribute %1 should be an edge + L'attribut %1 doit être une arête + + + There is no sketch referring to the current feature + La fonction de projection n'a pas d'esquisse + + + The attribute %1 should be an edge or vertex + L'élément projeté doit être une arête ou un sommet + + + Unable to project feature from the same sketch + Les fonctions de l'esquisse en cours ne peuvent pas être projetées + + + Error: Line is orthogonal to the sketch plane. + Erreur: La ligne est orthogonale au plan d'esquisse. + + + Error: Circle is orthogonal to the sketch plane. + Erreur: Le cercle est orthogonal au plan d'esquisse. + + + Error: Arc is orthogonal to the sketch plane. + Erreur: L'arc est orthogonal au plan d'esquisse. + + + Error: Ellipse is orthogonal to the sketch plane. + Erreur: L'ellipse est orthogonale au plan d'esquisse. + + + Error: Elliptic Arc is orthogonal to the sketch plane. + Erreur: L'arc d'ellipse est orthogonal au plan d'esquisse. + + + Error: Selected object is not supported for projection. + Erreur: L'objet sélectionné n'est pas pris en charge pour la projection. + + + + SketchProjection:Model_FeatureValidator + + Attribute "%1" is not initialized. + L'attribut "%1" n'est pas initialisé. + + + + SketchProjection:ExternalFeature + + Attribute "%1" is not initialized. + Sélectionnez une arête externe ou un sommet. + + + Object + Objet + + + Select external edge or vertex. + Sélectionnez une arête externe ou un sommet. + + SketchRectangle diff --git a/src/SketchPlugin/Test/TestProjectionEllipse.py b/src/SketchPlugin/Test/TestProjectionEllipse.py index 713d690f2..8d1985613 100644 --- a/src/SketchPlugin/Test/TestProjectionEllipse.py +++ b/src/SketchPlugin/Test/TestProjectionEllipse.py @@ -49,12 +49,11 @@ model.end() from GeomAPI import * +circle = SketchCircle_2.results()[-1].resultSubShapePair()[0].shape() +assert(circle.isEdge() and circle.edge().isCircle()) ellipse1 = SketchEllipse_1.results()[-1].resultSubShapePair()[0].shape() assert(ellipse1.isEdge() and ellipse1.edge().isEllipse()) ellipse2 = SketchEllipse_2.results()[-1].resultSubShapePair()[0].shape() assert(ellipse2.isEdge() and ellipse2.edge().isEllipse()) -# TODO [limitation]: projection of an ellipse to non-parallel plane is forbiden (OCCT issue #31016) -assert(Sketch_2.feature().error() != "") - assert(model.checkPythonDump()) diff --git a/src/SketchPlugin/Test/TestProjectionWithoutReference.py b/src/SketchPlugin/Test/TestProjectionWithoutReference.py new file mode 100644 index 000000000..82e5f5424 --- /dev/null +++ b/src/SketchPlugin/Test/TestProjectionWithoutReference.py @@ -0,0 +1,146 @@ +# Copyright (C) 2020 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 +# + +""" + Test projection without the reference to the source geometry. +""" + +import unittest + +from salome.shaper import model +from GeomAPI import * +from ModelAPI import * + +__updated__ = "2020-07-07" + +CURVES = [] +PLANE = None + +class TestProjectionWithoutRef(unittest.TestCase): + def setUp(self): + model.begin() + self.myDocument = model.moduleDocument() + self.mySketch = model.addSketch(partSet, model.selection("FACE", PLANE.name())) + self.myDOF = 0 + self.myNbPoints = 1 + self.myNbLines = 1 + self.myNbCircles = 0 + self.myNbArcs = 0 + self.myNbEllipses = 2 + self.myNbEllipticArcs = 2 + self.myNbSplines = 1 + self.myNbPeriodicSplines = 1 + self.myNbProjections = 0 + self.myNbFixedConstraints = 0 + self.myNbEdgesInSketch = 0 + + def tearDown(self): + self.checkDOF() + model.end() + model.testNbSubFeatures(self.mySketch, "SketchPoint", self.myNbPoints) + model.testNbSubFeatures(self.mySketch, "SketchLine", self.myNbLines) + model.testNbSubFeatures(self.mySketch, "SketchCircle", self.myNbCircles) + model.testNbSubFeatures(self.mySketch, "SketchArc", self.myNbArcs) + model.testNbSubFeatures(self.mySketch, "SketchEllipse", self.myNbEllipses) + model.testNbSubFeatures(self.mySketch, "SketchEllipticArc", self.myNbEllipticArcs) + model.testNbSubFeatures(self.mySketch, "SketchBSpline", self.myNbSplines) + model.testNbSubFeatures(self.mySketch, "SketchBSplinePeriodic", self.myNbPeriodicSplines) + model.testNbSubFeatures(self.mySketch, "SketchProjection", self.myNbProjections) + model.testNbSubFeatures(self.mySketch, "SketchConstraintRigid", self.myNbFixedConstraints) + nbEdges = 0 + exp = GeomAPI_ShapeExplorer(self.mySketch.defaultResult().shape(), GeomAPI_Shape.EDGE) + while exp.more(): nbEdges += 1; exp.next() + self.assertEqual(self.myNbEdgesInSketch, nbEdges) + + def checkDOF(self): + self.assertEqual(model.dof(self.mySketch), self.myDOF) + + + def test_projection_withref_includeintoresult(self): + """ Test 1. Projection with the reference to the original shapes. Projected curves are composed into the sketch result. + """ + for c in CURVES: + self.mySketch.addProjection(c, keepResult = True) + self.myNbProjections = len(CURVES) + self.myNbEdgesInSketch = len(CURVES) - 1 + + def test_projection_withref_notincludeintoresult(self): + """ Test 2. Projection with the reference to the original shapes. Projected curves are NOT included into the sketch result. + """ + for c in CURVES: + self.mySketch.addProjection(c, keepResult = False) + self.myNbProjections = len(CURVES) + + def test_projection_withoutref_noconstraints(self): + """ Test 3. Projection without the reference to the original shapes. No additional constraints applied. + """ + for c in CURVES: + self.mySketch.addProjection(c, keepRefToOriginal = False) + model.do() + self.myNbEdgesInSketch = len(CURVES) - 1 + self.myDOF += 2 + 4 + 5 + 7 + 5 + 7 + 6 * 2 + 6 * 2 + + def test_projection_withoutref_fixed(self): + """ Test 4. Projection without the reference to the original shapes. Additionally, Fixed constraints applied. + """ + model.end() + # use the low-level API to access the necessary attributes + session = ModelAPI_Session.get() + for c in CURVES: + session.startOperation() + proj = featureToCompositeFeature(self.mySketch.feature()).addFeature("SketchProjection") + proj.boolean("IncludeToResult").setValue(False) + proj.string("keep_reference").setValue("False") + proj.boolean("make_fixed").setValue(True) + c.fillAttribute(proj.selection("ExternalFeature")) + session.finishOperation() + self.myNbEdgesInSketch = len(CURVES) - 1 + self.myNbFixedConstraints = len(CURVES) + model.begin() + + +if __name__ == "__main__": + model.begin() + partSet = model.moduleDocument() + Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY")) + SketchPoint_1 = Sketch_1.addPoint(35, -40) + CURVES.append(model.selection("VERTEX", Sketch_1.name() + "/" + SketchPoint_1.name())) + SketchLine_1 = Sketch_1.addLine(20, -15, 40, 15) + CURVES.append(model.selection("EDGE", Sketch_1.name() + "/" + SketchLine_1.name())) + SketchCircle_1 = Sketch_1.addCircle(65, -30, 20) + CURVES.append(model.selection("EDGE", Sketch_1.name() + "/" + SketchCircle_1.defaultResult().data().name())) + SketchArc_1 = Sketch_1.addArc(60, 15, 80, 0, 50, 33, False) + CURVES.append(model.selection("EDGE", Sketch_1.name() + "/" + SketchArc_1.defaultResult().data().name())) + SketchEllipse_1 = Sketch_1.addEllipse(25, 30, 40, 30, 10) + CURVES.append(model.selection("EDGE", Sketch_1.name() + "/" + SketchEllipse_1.defaultResult().data().name())) + SketchEllipticArc_1 = Sketch_1.addEllipticArc(40, 70, 55, 70, 45, 50, 25, 56, False) + CURVES.append(model.selection("EDGE", Sketch_1.name() + "/" + SketchEllipticArc_1.defaultResult().data().name())) + SketchBSpline_1_poles = [(95, -50), (130, -10), (100, 10), (125, 45), (90, 70), (55, 45)] + SketchBSpline_1 = Sketch_1.addSpline(poles = SketchBSpline_1_poles) + CURVES.append(model.selection("EDGE", Sketch_1.name() + "/" + SketchBSpline_1.name())) + SketchBSplinePeriodic_1_poles = [(95, 80), (135, 90), (145, 55), (130, 30), (125, 70), (105, 60)] + SketchBSplinePeriodic_1 = Sketch_1.addSpline(poles = SketchBSplinePeriodic_1_poles, periodic = True) + CURVES.append(model.selection("EDGE", Sketch_1.name() + "/" + SketchBSplinePeriodic_1.name())) + model.do() + PLANE = model.addPlane(partSet, model.selection("FACE", "XOY"), model.selection("EDGE", "OY"), 45) + model.end() + + test_program = unittest.main(exit=False) + assert test_program.result.wasSuccessful(), "Test failed" + assert model.checkPythonDump() diff --git a/src/SketchPlugin/plugin-Sketch.xml b/src/SketchPlugin/plugin-Sketch.xml index ef62acfca..f5f6f3f31 100644 --- a/src/SketchPlugin/plugin-Sketch.xml +++ b/src/SketchPlugin/plugin-Sketch.xml @@ -813,8 +813,26 @@ use_sketch_plane="false"> - + + + + + + + + diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp index 0ecc2291a..6d6d5beab 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp @@ -114,7 +114,7 @@ static bool hasReference(std::shared_ptr theFeature, for (std::set::const_iterator aRefIt = aRefs.begin(); aRefIt != aRefs.end(); ++aRefIt) { FeaturePtr anOwner = ModelAPI_Feature::feature((*aRefIt)->owner()); - if (anOwner && anOwner->getKind() == theFeatureKind) + if (anOwner && !anOwner->isMacro() && anOwner->getKind() == theFeatureKind) return true; } return false;