From e7936a7615b6be5d69d4428088e6249f541480b8 Mon Sep 17 00:00:00 2001 From: mpv Date: Thu, 19 Oct 2017 13:52:36 +0300 Subject: [PATCH] Fix for the issue #2276: selecting the center of a circle crashes SHAPER --- src/Model/Model_AttributeSelection.cpp | 37 +++++++++++++++---- src/Model/Model_AttributeSelection.h | 7 +++- src/ModelAPI/CMakeLists.txt | 1 + src/ModelAPI/ModelAPI_AttributeSelection.h | 7 +++- src/ModelAPI/Test/Test2276.py | 38 ++++++++++++++++++++ src/SketchPlugin/SketchPlugin_Projection.cpp | 2 +- 6 files changed, 82 insertions(+), 10 deletions(-) create mode 100644 src/ModelAPI/Test/Test2276.py diff --git a/src/Model/Model_AttributeSelection.cpp b/src/Model/Model_AttributeSelection.cpp index 6d97b417e..95af31053 100644 --- a/src/Model/Model_AttributeSelection.cpp +++ b/src/Model/Model_AttributeSelection.cpp @@ -90,25 +90,26 @@ Standard_GUID kELLIPSE_CENTER2("1395ae73-8e02-4cf8-b204-06ff35873a32"); // TDataStd_IntPackedMap - indexes of edges in composite element (for construction) // TDataStd_Integer - type of the selected shape (for construction) // TDF_Reference - from ReferenceAttribute, the context -void Model_AttributeSelection::setValue(const ResultPtr& theContext, +bool Model_AttributeSelection::setValue(const ResultPtr& theContext, const std::shared_ptr& theSubShape, const bool theTemporarily) { if (theTemporarily) { // just keep the stored without DF update myTmpContext = theContext; myTmpSubShape = theSubShape; owner()->data()->sendAttributeUpdated(this); - return; + return true; } else { myTmpContext.reset(); myTmpSubShape.reset(); myTmpCenterType = NOT_CENTER; } - const std::shared_ptr& anOldShape = value(); + CenterType aType; + const std::shared_ptr& anOldShape = internalValue(aType); bool isOldContext = theContext == myRef.value(); bool isOldShape = isOldContext && (theSubShape == anOldShape || (theSubShape && anOldShape && theSubShape->isEqual(anOldShape))); - if (isOldShape) return; // shape is the same, so context is also unchanged + if (isOldShape) return false; // shape is the same, so context is also unchanged // update the referenced object if needed if (!isOldContext) { myRef.setValue(theContext); @@ -134,7 +135,7 @@ void Model_AttributeSelection::setValue(const ResultPtr& theContext, TDF_Label aRefLab = myRef.myRef->Label(); aSelLab.ForgetAllAttributes(true); myRef.myRef = TDF_Reference::Set(aSelLab.Father(), aSelLab.Father()); - return; + return false; } if (theContext->groupName() == ModelAPI_ResultBody::group()) { // do not select the whole shape for body:it is already must be in the data framework @@ -168,32 +169,54 @@ void Model_AttributeSelection::setValue(const ResultPtr& theContext, } owner()->data()->sendAttributeUpdated(this); + return true; } void Model_AttributeSelection::setValueCenter( const ResultPtr& theContext, const std::shared_ptr& theEdge, const CenterType theCenterType, const bool theTemporarily) { - setValue(theContext, theEdge, theTemporarily); + bool anUpdated = setValue(theContext, theEdge, theTemporarily); if (theTemporarily) { myTmpCenterType = theCenterType; } else { // store in the data structure TDF_Label aSelLab = selectionLabel(); switch(theCenterType) { case CIRCLE_CENTER: + if (!anUpdated) + anUpdated = !aSelLab.IsAttribute(kCIRCLE_CENTER); TDataStd_UAttribute::Set(aSelLab, kCIRCLE_CENTER); break; case ELLIPSE_FIRST_FOCUS: + if (!anUpdated) + anUpdated = !aSelLab.IsAttribute(kELLIPSE_CENTER1); TDataStd_UAttribute::Set(aSelLab, kELLIPSE_CENTER1); break; case ELLIPSE_SECOND_FOCUS: + if (!anUpdated) + anUpdated = !aSelLab.IsAttribute(kELLIPSE_CENTER2); TDataStd_UAttribute::Set(aSelLab, kELLIPSE_CENTER2); break; } - owner()->data()->sendAttributeUpdated(this); + if (anUpdated) + owner()->data()->sendAttributeUpdated(this); } } +void Model_AttributeSelection::selectValue( + const std::shared_ptr& theSource) +{ + CenterType aType; + std::shared_ptr aValue = + std::dynamic_pointer_cast(theSource)->internalValue(aType); + if (!aValue.get() || aType == NOT_CENTER) { + setValue(theSource->context(), aValue); + } else { + std::shared_ptr anEdge(new GeomAPI_Edge); + anEdge->setImpl(new TopoDS_Shape(aValue->impl())); + setValueCenter(theSource->context(), anEdge, aType); + } +} void Model_AttributeSelection::removeTemporaryValues() { diff --git a/src/Model/Model_AttributeSelection.h b/src/Model/Model_AttributeSelection.h index 5011bdce4..5306aa68d 100644 --- a/src/Model/Model_AttributeSelection.h +++ b/src/Model/Model_AttributeSelection.h @@ -53,7 +53,8 @@ public: /// \param theSubShape selected sub-shape (if null, the whole context is selected) /// \param theTemporarily if it is true, do not store and name the added in the data framework /// (used to remove immideately, without the following updates) - MODEL_EXPORT virtual void setValue( + /// \returns true if attribute was updated + MODEL_EXPORT virtual bool setValue( const ResultPtr& theContext, const std::shared_ptr& theSubShape, const bool theTemporarily = false); @@ -64,6 +65,10 @@ public: const CenterType theCenterType, const bool theTemporarily = false); + /// Makes this selection attribute selects the same as in theSource selection + MODEL_EXPORT virtual void selectValue( + const std::shared_ptr& theSource); + /// Reset temporary stored values virtual void removeTemporaryValues(); diff --git a/src/ModelAPI/CMakeLists.txt b/src/ModelAPI/CMakeLists.txt index bdd120bff..e043a23a2 100644 --- a/src/ModelAPI/CMakeLists.txt +++ b/src/ModelAPI/CMakeLists.txt @@ -171,4 +171,5 @@ ADD_UNIT_TESTS(TestConstants.py Test2228.py Test2241.py Test2252.py + Test2276.py ) diff --git a/src/ModelAPI/ModelAPI_AttributeSelection.h b/src/ModelAPI/ModelAPI_AttributeSelection.h index 44eace64f..904711ea2 100644 --- a/src/ModelAPI/ModelAPI_AttributeSelection.h +++ b/src/ModelAPI/ModelAPI_AttributeSelection.h @@ -47,7 +47,8 @@ class ModelAPI_AttributeSelection : public ModelAPI_Attribute /// \param theSubShape selected sub-shape (if null, the whole context is selected) /// \param theTemporarily if it is true, do not store and name the added in the data framework /// (used to remove immideately, without the following updates) - virtual void setValue( + /// \returns true if attribute was updated + virtual bool setValue( const ResultPtr& theContext, const std::shared_ptr& theSubShape, const bool theTemporarily = false) = 0; @@ -58,6 +59,10 @@ class ModelAPI_AttributeSelection : public ModelAPI_Attribute const CenterType theCenterType, const bool theTemporarily = false) = 0; + /// Makes this selection attribute selects the same as in theSource selection + virtual void selectValue( + const std::shared_ptr& theSource) = 0; + /// Reset temporary stored values virtual void removeTemporaryValues() = 0; diff --git a/src/ModelAPI/Test/Test2276.py b/src/ModelAPI/Test/Test2276.py new file mode 100644 index 000000000..8697b5d15 --- /dev/null +++ b/src/ModelAPI/Test/Test2276.py @@ -0,0 +1,38 @@ +## Copyright (C) 2014-2017 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 +## + +from salome.shaper import model + +model.begin() +partSet = model.moduleDocument() +Part_1 = model.addPart(partSet) +Part_1_doc = Part_1.document() +Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY")) +SketchCircle_1 = Sketch_1.addCircle(-9.954190485756755, -75.16051465706819, 60.31858435553394) +model.do() +Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection(), 10, 0) +Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face_1")) +SketchProjection_1 = Sketch_2.addProjection(model.selection("VERTEX", "Extrusion_1_1/Generated_Face_1&Extrusion_1_1/To_Face_1__cc"), False) +SketchPoint_1 = SketchProjection_1.createdFeature() +SketchCircle_2 = Sketch_2.addCircle(-9.954190485756755, -75.16051465706819, 33.11263086848982) +SketchConstraintCoincidence_1 = Sketch_2.setCoincident(SketchPoint_1.result(), SketchCircle_2.center()) +model.end() + +assert(model.checkPythonDump()) diff --git a/src/SketchPlugin/SketchPlugin_Projection.cpp b/src/SketchPlugin/SketchPlugin_Projection.cpp index a0d8090c8..254ccafc9 100644 --- a/src/SketchPlugin/SketchPlugin_Projection.cpp +++ b/src/SketchPlugin/SketchPlugin_Projection.cpp @@ -253,7 +253,7 @@ void SketchPlugin_Projection::computeProjection(const std::string& theID) aRefAttr->setObject(aProjection); if (theID == EXTERNAL_FEATURE_ID()) { - selection(EXTERNAL_ID())->setValue(aExtFeature->context(), aExtFeature->value()); + selection(EXTERNAL_ID())->selectValue(aExtFeature); if (aResult) { aResult->setShape(aProjection->lastResult()->shape()); -- 2.39.2