From: vsr Date: Wed, 10 Apr 2019 13:43:22 +0000 (+0300) Subject: Merge branch 'master' into V9_3_BR X-Git-Tag: V9_3_0rc1^0 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=0b9db0adf25cae21024828888563fff1a47492f2;hp=d9d68ad55d070600eac1027ac23575616edbe69c;p=modules%2Fshaper.git Merge branch 'master' into V9_3_BR --- diff --git a/src/BuildPlugin/Test/TestCompSolid.py b/src/BuildPlugin/Test/TestCompSolid.py index 077834374..3ebbd9121 100644 --- a/src/BuildPlugin/Test/TestCompSolid.py +++ b/src/BuildPlugin/Test/TestCompSolid.py @@ -147,6 +147,12 @@ CompSolid_1 = createCompSolidStepByStep(boundaries1, expectType1) model.checkResult(CompSolid_1, model, 1, [2], [2], [13], [54], [108]) model.testHaveNamingSubshapes(CompSolid_1, model, Part_1_doc) +# to reuse all results, undo the solid and 3 groups creation +model.undo() +model.undo() +model.undo() +model.undo() + # ============================================================================= # Test 2. Build compsolid containing 3 solids # ============================================================================= diff --git a/src/BuildPlugin/Test/TestFace.py b/src/BuildPlugin/Test/TestFace.py index 47091eeb7..4ad935ab0 100644 --- a/src/BuildPlugin/Test/TestFace.py +++ b/src/BuildPlugin/Test/TestFace.py @@ -113,11 +113,21 @@ assert (len(aFaceFeature2.results()) > 0) # ============================================================================= # Test 3. Create face from face of solid # ============================================================================= +aSession.startOperation() +aCylinder = aPart.addFeature("Cylinder") +aCylinder.string("CreationMethod").setValue("Cylinder") +aCylinder.selection("base_point").selectSubShape("VERTEX", "PartSet/Origin") +aCylinder.selection("axis").selectSubShape("EDGE", "PartSet/OZ") +aCylinder.real("radius").setValue(5) +aCylinder.real("height").setValue(10) +aSession.finishOperation() +aCylinderResult = aCylinder.firstResult() +aCylinderShape = aCylinderResult.shape() aSession.startOperation() aFaceFeature3 = aPart.addFeature("Face") aBaseObjectsList = aFaceFeature3.selectionList("base_objects") -aBaseObjectsList.append("Cylinder_1_1/Face_1", "FACE") +aBaseObjectsList.append("Cylinder_2_1/Face_1", "FACE") aSession.finishOperation() assert (len(aFaceFeature3.results()) > 0) @@ -125,6 +135,17 @@ assert (len(aFaceFeature3.results()) > 0) # Test 4. Verify error is reported if selection of face feature is mixed (edges and face) # ============================================================================= +aSession.startOperation() +aCylinder = aPart.addFeature("Cylinder") +aCylinder.string("CreationMethod").setValue("Cylinder") +aCylinder.selection("base_point").selectSubShape("VERTEX", "PartSet/Origin") +aCylinder.selection("axis").selectSubShape("EDGE", "PartSet/OZ") +aCylinder.real("radius").setValue(5) +aCylinder.real("height").setValue(10) +aSession.finishOperation() +aCylinderResult = aCylinder.firstResult() +aCylinderShape = aCylinderResult.shape() + aSession.startOperation() aFaceFeature4 = aPart.addFeature("Face") aBaseObjectsList = aFaceFeature4.selectionList("base_objects") @@ -132,7 +153,7 @@ aShapeExplorer = GeomAPI_ShapeExplorer(aSketchShape, GeomAPI_Shape.EDGE) while aShapeExplorer.more(): aBaseObjectsList.append(aSketchResult, aShapeExplorer.current()) aShapeExplorer.next() -aBaseObjectsList.append("Cylinder_1_1/Face_3", "FACE") +aBaseObjectsList.append("Cylinder_3_1/Face_3", "FACE") aSession.finishOperation() assert (len(aFaceFeature4.results()) == 0) # remove failed feature diff --git a/src/BuildPlugin/doc/faceFeature.rst b/src/BuildPlugin/doc/faceFeature.rst index 21fa07c55..aee91f3a1 100644 --- a/src/BuildPlugin/doc/faceFeature.rst +++ b/src/BuildPlugin/doc/faceFeature.rst @@ -24,7 +24,7 @@ The following property panel will be opened: .. centered:: Create a face -Select one or several faces in viewer. +Select one or several faces in viewer. Additionally, a face can be build by a closed wire or a set of edges composing a closed wire. **Apply** button creates faces. diff --git a/src/BuildPlugin/face_widget.xml b/src/BuildPlugin/face_widget.xml index 80aa05a46..a23c7cf07 100644 --- a/src/BuildPlugin/face_widget.xml +++ b/src/BuildPlugin/face_widget.xml @@ -1,7 +1,7 @@ diff --git a/src/BuildPlugin/plugin-Build.xml b/src/BuildPlugin/plugin-Build.xml index 86725380f..b46aa51b1 100644 --- a/src/BuildPlugin/plugin-Build.xml +++ b/src/BuildPlugin/plugin-Build.xml @@ -21,7 +21,7 @@ helpfile="polylineFeature.html"> - diff --git a/src/FeaturesPlugin/Test/TestFusionFaces.py b/src/FeaturesPlugin/Test/TestFusionFaces.py index 848175745..b0adb7f32 100644 --- a/src/FeaturesPlugin/Test/TestFusionFaces.py +++ b/src/FeaturesPlugin/Test/TestFusionFaces.py @@ -32,16 +32,21 @@ Box_1 = model.addBox(Part_1_doc, 10, 10, 10) Box_2 = model.addBox(Part_1_doc, 10, 10, 10) Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_2_1")], model.selection("EDGE", "PartSet/OX"), 10) +model.do() Shell_1 = model.addShell(Part_1_doc, [model.selection("FACE", "Box_1_1/Top"), model.selection("FACE", "Translation_1_1/MF:Translated&Box_2_1/Top")]) model.do() model.checkResult(Shell_1, model, 1, [0], [0], [2], [8], [16]) FusionFaces_1 = model.addFusionFaces(Part_1_doc, model.selection("SHELL", "Shell_1_1")) -model.do() +model.end() model.checkResult(FusionFaces_1, model, 1, [0], [0], [1], [4], [8]) +model.undo() # to reuse Box_1_1 and Translation_1_1 +model.undo() +model.begin() + # ============================================================================= # Test 2. Fusion faces for solid of 2 adjacent boxes # ============================================================================= @@ -63,7 +68,7 @@ Shell_2 = model.addShell(Part_1_doc, [model.selection("FACE", "Cylinder_1_1/Face Point_1 = model.addPoint(Part_1_doc, 0, 0, 5) Plane_1 = model.addPlane(Part_1_doc, model.selection("EDGE", "PartSet/OZ"), model.selection("VERTEX", "Point_1"), True) -Partition_1 = model.addPartition(Part_1_doc, [model.selection("SHELL", "Shell_2_1"), model.selection("FACE", "Plane_1")]) +Partition_1 = model.addPartition(Part_1_doc, [model.selection("SHELL", "Shell_1_1"), model.selection("FACE", "Plane_1")]) model.do() model.checkResult(Partition_1, model, 1, [0], [0], [2], [8], [16]) diff --git a/src/FeaturesPlugin/Test/TestFusionFaces2697.py b/src/FeaturesPlugin/Test/TestFusionFaces2697.py index e3e84ed52..ff2147790 100644 --- a/src/FeaturesPlugin/Test/TestFusionFaces2697.py +++ b/src/FeaturesPlugin/Test/TestFusionFaces2697.py @@ -256,7 +256,9 @@ Symmetry_1.results()[1].subResult(1).setName("Symmetry_1_2_2") Cut_1 = model.addCut(Part_1_doc, [model.selection("SOLID", "Revolution_1_1")], [model.selection("COMPOUND", "Cut_tool")]) Fuse_1 = model.addFuse(Part_1_doc, [model.selection("SOLID", "Cut_1_1"), model.selection("COMPOUND", "Fuse_tool")]) FusionFaces_1 = model.addFusionFaces(Part_1_doc, model.selection("SOLID", "Fuse_1_1")) -model.end() +model.do() # check the faces are fused model.checkResult(FusionFaces_1, model, 1, [0], [1], [16], [76], [152]) + +model.end() \ No newline at end of file diff --git a/src/FeaturesPlugin/Test/TestRecover.py b/src/FeaturesPlugin/Test/TestRecover.py index 392d85ae7..88cdb0cdc 100644 --- a/src/FeaturesPlugin/Test/TestRecover.py +++ b/src/FeaturesPlugin/Test/TestRecover.py @@ -75,7 +75,8 @@ c3 = sk3.addCircle(0, 0, 90) model.do() big2 = model.addExtrusion(mypart, sk3.selectFace(), 110) -cut2 = model.addCut(mypart, big2.results(), smallcyl.results()) +smallcyl2 = model.addExtrusion(mypart, sk2.selectFace(), 150) +cut2 = model.addCut(mypart, big2.results(), smallcyl2.results()) model.end() diff --git a/src/FeaturesPlugin/Test/TestRemoveSubShapes3.py b/src/FeaturesPlugin/Test/TestRemoveSubShapes3.py index 87dc9185b..c159dbe56 100644 --- a/src/FeaturesPlugin/Test/TestRemoveSubShapes3.py +++ b/src/FeaturesPlugin/Test/TestRemoveSubShapes3.py @@ -30,7 +30,8 @@ Part_1_doc = Part_1.document() Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10) Face_1 = model.addFace(Part_1_doc, [model.selection("FACE", "Cylinder_1_1/Face_1")]) -Face_2 = model.addFace(Part_1_doc, [model.selection("FACE", "Cylinder_1_1/Face_1")]) +Cylinder_2 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10) +Face_2 = model.addFace(Part_1_doc, [model.selection("FACE", "Cylinder_2_1/Face_1")]) Translation_1 = model.addTranslation(Part_1_doc, [model.selection("FACE", "Face_2_1")], model.selection("EDGE", "PartSet/OZ"), 10) Shell_1 = model.addShell(Part_1_doc, [model.selection("FACE", "Translation_1_1"), model.selection("FACE", "Face_1_1")]) diff --git a/src/GeomAPI/Test/TestCone.py b/src/GeomAPI/Test/TestCone.py index a7c2d72ed..556c9bd85 100644 --- a/src/GeomAPI/Test/TestCone.py +++ b/src/GeomAPI/Test/TestCone.py @@ -259,14 +259,21 @@ checkConeSolid(Part_1_doc, Solid_1_objects, anApex, anAxis, aSemiAngle, ParamR1. Cone_2 = model.addCone(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 10, 5, 10) Cone_3 = model.addCone(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10, 20) Fuse_1 = model.addFuse(Part_1_doc, [model.selection("SOLID", "Cone_2_1"), model.selection("SOLID", "Cone_3_1")], True) + +model.do() Solid_2_objects = [model.selection("FACE", "Fuse_1_1/Modified_Face&Cone_2_1/Face_3&Cone_3_1/Face_3"), model.selection("FACE", "Fuse_1_1/Modified_Face&Cone_2_1/Face_1"), model.selection("FACE", "Fuse_1_1/Modified_Face&Cone_3_1/Face_1"), model.selection("FACE", "Cone_3_1/Face_2")] Solid_2 = model.addSolid(Part_1_doc, Solid_2_objects) checkNonCone(Solid_2) +model.end() + +# in order to use study objects once again, undo Test7 actions +model.undo() # Test 8. Check non-conical shell +model.begin() Shell_1_objects = [model.selection("FACE", "Rotation_1_1/MF:Rotated&Cone_1_1/Face_3"), model.selection("FACE", "Partition_1_1_1/Modified_Face&Cone_1_1/Face_1"), model.selection("FACE", "Partition_1_1_2/Modified_Face&Cone_1_1/Face_1"), @@ -276,13 +283,23 @@ checkNonConeShell(Shell_1) Shell_2 = model.addShell(Part_1_doc, [model.selection("FACE", "Fuse_1_1/Modified_Face&Cone_2_1/Face_1"), model.selection("FACE", "Fuse_1_1/Modified_Face&Cone_3_1/Face_1")]) checkNonConeShell(Shell_2) +model.end() + +# in order to use study objects once again, undo Test8 actions +model.undo() # Test 9. Check error on conversion to wrong type of curve +model.begin() anEdge = model.addEdge(Part_1_doc, [model.selection("EDGE", "[Partition_1_1_2/Modified_Face&Cone_1_1/Face_1][Rotation_1_1/MF:Rotated&Cone_1_1/Face_2]")]) aShape = anEdge.result().resultSubShapePair()[0].shape() assert(aShape.isEdge()) assert(aShape.edge().ellipse() is None) assert(aShape.edge().line() is None) +model.end() + +model.undo() + +model.begin() anEdge = model.addEdge(Part_1_doc, [model.selection("EDGE", "[Partition_1_1_2/Modified_Face&Cone_1_1/Face_1][weak_name_2]")]) aShape = anEdge.result().resultSubShapePair()[0].shape() @@ -301,6 +318,4 @@ radius = 5 cone = GeomAPI_Cone(apex, dir, semiAngle, radius) assert(cone.location().distance(apex) < TOLERANCE) - - model.end() diff --git a/src/Model/Model_AttributeSelection.cpp b/src/Model/Model_AttributeSelection.cpp index e540e3e66..3d325a688 100644 --- a/src/Model/Model_AttributeSelection.cpp +++ b/src/Model/Model_AttributeSelection.cpp @@ -1443,7 +1443,12 @@ void Model_AttributeSelection::updateInHistory(bool& theRemove) continue; FeaturePtr aRefFeat = std::dynamic_pointer_cast((*aRef)->owner()); + if (aRefFeat.get() && aRefFeat != owner() && aRefFeat->firstResult().get()) { + // check the reference is concealed: #2900 + ModelAPI_ValidatorsFactory* aValidators = ModelAPI_Session::get()->validators(); + if (!aValidators->isConcealed(aRefFeat->getKind(), (*aRef)->id())) + continue; FeaturePtr aThisFeature = std::dynamic_pointer_cast(owner()); if (!aDoc->isLaterByDep(aRefFeat, aThisFeature)) { // found better feature aFoundNewContext = true; diff --git a/src/Model/Model_AttributeValidator.cpp b/src/Model/Model_AttributeValidator.cpp index cef720290..ee59e6e58 100644 --- a/src/Model/Model_AttributeValidator.cpp +++ b/src/Model/Model_AttributeValidator.cpp @@ -23,6 +23,10 @@ #include #include +#include +#include +#include +#include #include #include @@ -82,6 +86,90 @@ bool Model_AttributeValidator::isValid(const AttributePtr& theAttribute, theError.arg(anErrorMessage); return false; } + } else { // #2903 : check that concealed attribute refers to already concealed result + FeaturePtr aFeat = std::dynamic_pointer_cast(theAttribute->owner()); + + std::set alreadyProcessed; // optimization + if (aFeat.get() && + ModelAPI_Session::get()->validators()->isConcealed(aFeat->getKind(), theAttribute->id())) { + std::list > > allRefs; + aFeat->data()->referencesToObjects(allRefs); + std::list > >::iterator anIter = allRefs.begin(); + for(; anIter != allRefs.end(); anIter++) { + if (anIter->first == theAttribute->id()) { + const std::list& aReferencedList = anIter->second; + std::list::const_iterator aRefIter = aReferencedList.cbegin(); + for(; aRefIter != aReferencedList.cend(); aRefIter++) { + const ObjectPtr& aReferenced = *aRefIter; + if (!aReferenced.get()) + continue; + // get all results and feature that is referenced to see all references to them + FeaturePtr aReferencedFeature; + if (aReferenced->groupName() == ModelAPI_Feature::group()) { + aReferencedFeature = std::dynamic_pointer_cast(aReferenced); + } else { + aReferencedFeature = aReferenced->document()->feature( + std::dynamic_pointer_cast(aReferenced)); + } + if (alreadyProcessed.count(aReferencedFeature)) + continue; + alreadyProcessed.insert(aReferencedFeature); + /* it takes all results, not only concealed + std::list aReferencedResults; + ModelAPI_Tools::allResults(aReferencedFeature, aReferencedResults); + */ + std::list aReferencedResults; + ResultBodyPtr aRefBody = std::dynamic_pointer_cast(aReferenced); + if (aRefBody.get()) { // take only sub-results of this result or sub-result + ResultBodyPtr aRoot = ModelAPI_Tools::bodyOwner(aRefBody, true); + if (aRoot.get()) { + ModelAPI_Tools::allSubs(aRoot, aReferencedResults, false); + aReferencedResults.push_back(aRoot); + } else + aReferencedResults.push_back(aRefBody); + } + + std::list::iterator aRefRes = aReferencedResults.begin(); + bool aCheckFeature = true; // the last iteration to check the feature + while(aRefRes != aReferencedResults.end() || aCheckFeature) { + ObjectPtr aRefd; + if (aRefRes == aReferencedResults.end()) { + aRefd = aReferencedFeature; + aCheckFeature = false; + if (!aReferencedFeature->results().empty() && + aReferencedFeature->firstResult()->groupName() != ModelAPI_ResultBody::group()) + break; + } else { + aRefd = *aRefRes; + if (aRefd->groupName() != ModelAPI_ResultBody::group()) + break; + } + if (!aRefd->data().get() || !aRefd->data()->isValid()) + continue; + const std::set& aRefsToRef = aRefd->data()->refsToMe(); + std::set::const_iterator aRR = aRefsToRef.cbegin(); + for(; aRR != aRefsToRef.cend(); aRR++) { + FeaturePtr aRefFeat = std::dynamic_pointer_cast((*aRR)->owner()); + if (!aRefFeat.get() || aRefFeat == aFeat) + continue; + if (ModelAPI_Session::get()->validators()->isConcealed( + aRefFeat->getKind(), (*aRR)->id())) { + // check this feature is later than another referenced to make unit tests working + //because of Test1757 and others: allow to move selection context of this to next + if (aFeat->document()->isLater(aFeat, aRefFeat)) { + theError = "Reference to concealed object %1"; + theError.arg(aRefd->data()->name()); + return false; + } + } + } + if (aCheckFeature) + aRefRes++; + } + } + } + } + } } return true; } diff --git a/src/ModelAPI/CMakeLists.txt b/src/ModelAPI/CMakeLists.txt index dbb19965c..27bf50712 100644 --- a/src/ModelAPI/CMakeLists.txt +++ b/src/ModelAPI/CMakeLists.txt @@ -245,4 +245,5 @@ ADD_UNIT_TESTS(TestConstants.py Test2859.py Test2873.py Test2901.py + Test2903.py ) diff --git a/src/ModelAPI/Test/Test2903.py b/src/ModelAPI/Test/Test2903.py new file mode 100644 index 000000000..b868a4fcc --- /dev/null +++ b/src/ModelAPI/Test/Test2903.py @@ -0,0 +1,41 @@ +# Copyright (C) 2014-2019 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 +from ModelAPI import * + +model.begin() +partSet = model.moduleDocument() +Part_1 = model.addPart(partSet) +Part_1_doc = Part_1.document() +Box_1 = model.addBox(Part_1_doc, 10, 10, 10) +Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10) +Sphere_1 = model.addSphere(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), 10) +Fuse_1 = model.addFuse(Part_1_doc, [model.selection("COMPOUND", "all-in-Box_1"), model.selection("COMPOUND", "all-in-Cylinder_1")], True) +Partition_1 = model.addPartition(Part_1_doc, [model.selection("COMPOUND", "all-in-Fuse_1"), model.selection("COMPOUND", "all-in-Sphere_1")]) +model.do() +aFactory = ModelAPI_Session.get().validators() +assert(aFactory.validate(Fuse_1.feature())) +assert(aFactory.validate(Partition_1.feature())) +# Modify Fuse to add sphere thatwas used in Partition +Fuse_1.setMainObjects([model.selection("COMPOUND", "all-in-Box_1"), model.selection("COMPOUND", "all-in-Cylinder_1"), model.selection("COMPOUND", "all-in-Sphere_1")]) +model.end() +# partition must become invalid because it refers to the same object as fuse +assert(aFactory.validate(Fuse_1.feature())) +assert(not aFactory.validate(Partition_1.feature()))