From f5f2457865bf513acd090a6254aca37ab18de0c9 Mon Sep 17 00:00:00 2001 From: mpv Date: Thu, 24 Jan 2019 11:26:31 +0300 Subject: [PATCH] Implementation and part of tests of High Level Objects History task for Common, Cut, Fuse, Smash --- src/CollectionPlugin/CMakeLists.txt | 1 + src/CollectionPlugin/Test/TestGroupMove4.py | 64 ++++++++++++++++++ .../FeaturesPlugin_BooleanCommon.cpp | 20 ++++-- .../FeaturesPlugin_BooleanCut.cpp | 12 +++- .../FeaturesPlugin_BooleanFuse.cpp | 7 +- .../FeaturesPlugin_BooleanSmash.cpp | 6 +- src/FeaturesPlugin/FeaturesPlugin_Tools.cpp | 20 +++--- src/FeaturesPlugin/FeaturesPlugin_Tools.h | 5 +- src/Model/Model_AttributeSelection.cpp | 17 ++++- src/Model/Model_ResultBody.cpp | 65 +++++++++++++------ 10 files changed, 163 insertions(+), 54 deletions(-) create mode 100644 src/CollectionPlugin/Test/TestGroupMove4.py diff --git a/src/CollectionPlugin/CMakeLists.txt b/src/CollectionPlugin/CMakeLists.txt index cd20d6185..711a8cc45 100644 --- a/src/CollectionPlugin/CMakeLists.txt +++ b/src/CollectionPlugin/CMakeLists.txt @@ -111,5 +111,6 @@ ADD_UNIT_TESTS( TestGroupMove.py TestGroupMove2.py TestGroupMove3.py + TestGroupMove4.py TestGroupShareTopology.py ) diff --git a/src/CollectionPlugin/Test/TestGroupMove4.py b/src/CollectionPlugin/Test/TestGroupMove4.py new file mode 100644 index 000000000..4755468a8 --- /dev/null +++ b/src/CollectionPlugin/Test/TestGroupMove4.py @@ -0,0 +1,64 @@ +## 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 +## + +# Test of deep nested results history. Cylinders divided to two by cut, then each divided to +# two by partition by plane, then resulting compsolids are collected in compound. +# Checking that group on initial extrusion moved to the end contains the corresponding +# results, but divided. + +from salome.shaper import model +from ModelAPI import * + +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(-4.602216748768477, 10.94581280788177, 9.660420057801511) +model.do() +Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2r")], model.selection(), 10, 0) +Group_1 = model.addGroup(Part_1_doc, [model.selection("FACE", "Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2")]) +Group_2 = model.addGroup(Part_1_doc, [model.selection("SOLID", "Extrusion_1_1")]) +Plane_4 = model.addPlane(Part_1_doc, model.selection("FACE", "PartSet/YOZ"), 1, True) +Sketch_2 = model.addSketch(Part_1_doc, model.standardPlane("XOY")) +SketchCircle_2 = Sketch_2.addCircle(-5.643073116097736, 11.91382008305256, 15.03576198961618) +model.do() +Extrusion_2 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchCircle_2_2r")], model.selection(), 2, -4) +Cut_1 = model.addCut(Part_1_doc, [model.selection("SOLID", "Extrusion_1_1")], [model.selection("SOLID", "Extrusion_2_1")]) +Partition_1 = model.addPartition(Part_1_doc, [model.selection("COMPOUND", "Cut_1_1"), model.selection("FACE", "Plane_1")]) +Compound_1 = model.addCompound(Part_1_doc, [model.selection("COMPSOLID", "Partition_1_1"), model.selection("COMPSOLID", "Partition_1_2")]) +model.do() +# move groups to the end +Part_1_doc.moveFeature(Group_1.feature(), Compound_1.feature()) +Part_1_doc.moveFeature(Group_2.feature(), Group_1.feature()) +model.end() + +aFactory = ModelAPI_Session.get().validators() +# check group 1: cylindical face is divided to 6 (because of seam edge) +selectionList = Group_1.feature().selectionList("group_list") +assert(selectionList.size() == 6) +assert(aFactory.validate(Group_1.feature())) + +# check group 2: solid is divided to 4 solids +selectionList = Group_2.feature().selectionList("group_list") +assert(selectionList.size() == 4) +assert(aFactory.validate(Group_2.feature())) + +assert(model.checkPythonDump()) diff --git a/src/FeaturesPlugin/FeaturesPlugin_BooleanCommon.cpp b/src/FeaturesPlugin/FeaturesPlugin_BooleanCommon.cpp index df16a3149..fcc48e084 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_BooleanCommon.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_BooleanCommon.cpp @@ -158,13 +158,14 @@ void FeaturesPlugin_BooleanCommon::execute() std::shared_ptr aResultBody = document()->createBody(data(), aResultIndex); - GeomShapePtr aBaseShape = anObjects.front(); - anObjects.pop_front(); + ListOfShape anEmptyTools; FeaturesPlugin_Tools::loadModifiedShapes(aResultBody, - aBaseShape, anObjects, + anEmptyTools, aMakeShapeList, aShape); + GeomShapePtr aBaseShape = anObjects.front(); + anObjects.pop_front(); setResult(aResultBody, aResultIndex); aResultIndex++; @@ -222,9 +223,10 @@ void FeaturesPlugin_BooleanCommon::execute() if (aShapeIt.more() || aResShape->shapeType() == GeomAPI_Shape::VERTEX) { std::shared_ptr aResultBody = document()->createBody(data(), aResultIndex); - + ListOfShape anObjectList; + anObjectList.push_back(anObject); FeaturesPlugin_Tools::loadModifiedShapes(aResultBody, - anObject, + anObjectList, aTools, aMakeShapeList, aResShape); @@ -304,8 +306,10 @@ void FeaturesPlugin_BooleanCommon::execute() std::shared_ptr aResultBody = document()->createBody(data(), aResultIndex); + ListOfShape aCompSolidList; + aCompSolidList.push_back(aCompSolid); FeaturesPlugin_Tools::loadModifiedShapes(aResultBody, - aCompSolid, + aCompSolidList, aTools, aMakeShapeList, aResultShape); @@ -388,8 +392,10 @@ void FeaturesPlugin_BooleanCommon::execute() std::shared_ptr aResultBody = document()->createBody(data(), aResultIndex); + ListOfShape aCompoundList; + aCompoundList.push_back(aCompound); FeaturesPlugin_Tools::loadModifiedShapes(aResultBody, - aCompound, + aCompoundList, aTools, aMakeShapeList, aResultShape); diff --git a/src/FeaturesPlugin/FeaturesPlugin_BooleanCut.cpp b/src/FeaturesPlugin/FeaturesPlugin_BooleanCut.cpp index bfe0fdc2c..a37a4a56c 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_BooleanCut.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_BooleanCut.cpp @@ -133,8 +133,10 @@ void FeaturesPlugin_BooleanCut::execute() std::shared_ptr aResultBody = document()->createBody(data(), aResultIndex); + ListOfShape anObjectList; + anObjectList.push_back(anObject); FeaturesPlugin_Tools::loadModifiedShapes(aResultBody, - anObject, + anObjectList, aTools, aMakeShapeList, aResShape); @@ -214,8 +216,10 @@ void FeaturesPlugin_BooleanCut::execute() std::shared_ptr aResultBody = document()->createBody(data(), aResultIndex); + ListOfShape anObjectList; + anObjectList.push_back(aCompSolid); FeaturesPlugin_Tools::loadModifiedShapes(aResultBody, - aCompSolid, + anObjectList, aTools, aMakeShapeList, aResultShape); @@ -296,8 +300,10 @@ void FeaturesPlugin_BooleanCut::execute() std::shared_ptr aResultBody = document()->createBody(data(), aResultIndex); + ListOfShape anObjectList; + anObjectList.push_back(aCompound); FeaturesPlugin_Tools::loadModifiedShapes(aResultBody, - aCompound, + anObjectList, aTools, aMakeShapeList, aResultShape); diff --git a/src/FeaturesPlugin/FeaturesPlugin_BooleanFuse.cpp b/src/FeaturesPlugin/FeaturesPlugin_BooleanFuse.cpp index f6e4599f7..b8bec11c1 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_BooleanFuse.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_BooleanFuse.cpp @@ -271,20 +271,19 @@ void FeaturesPlugin_BooleanFuse::execute() int aResultIndex = 0; - GeomShapePtr aBackShape = anOriginalShapes.back(); - anOriginalShapes.pop_back(); ResultBodyPtr aResultBody = document()->createBody(data(), aResultIndex); + ListOfShape anEmptyTools; FeaturesPlugin_Tools::loadModifiedShapes(aResultBody, - aBackShape, anOriginalShapes, + anEmptyTools, aMakeShapeList, aShape); setResult(aResultBody, aResultIndex); aResultIndex++; FeaturesPlugin_Tools::loadDeletedShapes(aResultBody, - aBackShape, + GeomShapePtr(), anOriginalShapes, aMakeShapeList, aShape); diff --git a/src/FeaturesPlugin/FeaturesPlugin_BooleanSmash.cpp b/src/FeaturesPlugin/FeaturesPlugin_BooleanSmash.cpp index ee6c3c785..2ec4468c4 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_BooleanSmash.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_BooleanSmash.cpp @@ -213,12 +213,10 @@ void FeaturesPlugin_BooleanSmash::execute() aMakeShapeList->appendAlgo(aFillerAlgo); } - std::shared_ptr aFrontShape = anOriginalShapes.front(); - anOriginalShapes.pop_front(); std::shared_ptr aResultBody = document()->createBody(data(), aResultIndex); FeaturesPlugin_Tools::loadModifiedShapes(aResultBody, - aFrontShape, + anOriginalShapes, anOriginalShapes, aMakeShapeList, aShape); @@ -227,7 +225,7 @@ void FeaturesPlugin_BooleanSmash::execute() aResultIndex++; FeaturesPlugin_Tools::loadDeletedShapes(aResultBody, - aFrontShape, + GeomShapePtr(), anOriginalShapes, aMakeShapeList, aShape); diff --git a/src/FeaturesPlugin/FeaturesPlugin_Tools.cpp b/src/FeaturesPlugin/FeaturesPlugin_Tools.cpp index efdee5801..c2444556d 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_Tools.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_Tools.cpp @@ -26,20 +26,17 @@ //================================================================================================== void FeaturesPlugin_Tools::loadModifiedShapes(ResultBodyPtr theResultBody, - const GeomShapePtr theBaseShape, + const ListOfShape& theBaseShapes, const ListOfShape& theTools, const GeomMakeShapePtr& theMakeShape, const GeomShapePtr theResultShape) { - if (theBaseShape->isEqual(theResultShape)) { - theResultBody->store(theResultShape, false); - return; - } - - theResultBody->storeModified(theBaseShape, theResultShape); + theResultBody->storeModified(theBaseShapes, theResultShape, theMakeShape); - ListOfShape aShapes = theTools; - aShapes.push_front(theBaseShape); + ListOfShape aShapes = theBaseShapes; + ListOfShape::const_iterator aToolIter = theTools.cbegin(); + for(; aToolIter != theTools.cend(); aToolIter++) + aShapes.push_back(*aToolIter); for (ListOfShape::const_iterator anIter = aShapes.begin(); anIter != aShapes.end(); ++anIter) { @@ -51,7 +48,7 @@ void FeaturesPlugin_Tools::loadModifiedShapes(ResultBodyPtr theResultBody, //================================================================================================== void FeaturesPlugin_Tools::loadModifiedShapes(ResultBodyPtr theResultBody, - const GeomShapePtr theBaseShape, + const GeomShapePtr& theBaseShape, const GeomMakeShapePtr& theMakeShape, const std::string theName) { @@ -98,7 +95,8 @@ void FeaturesPlugin_Tools::loadDeletedShapes(ResultBodyPtr theResultBody, const GeomShapePtr theResultShapesCompound) { ListOfShape aShapes = theTools; - aShapes.push_front(theBaseShape); + if (theBaseShape.get()) + aShapes.push_front(theBaseShape); for (ListOfShape::const_iterator anIter = aShapes.begin(); anIter != aShapes.end(); anIter++) { diff --git a/src/FeaturesPlugin/FeaturesPlugin_Tools.h b/src/FeaturesPlugin/FeaturesPlugin_Tools.h index 22b269b04..bda339111 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_Tools.h +++ b/src/FeaturesPlugin/FeaturesPlugin_Tools.h @@ -36,16 +36,15 @@ public: public: static void loadModifiedShapes(ResultBodyPtr theResultBody, - const GeomShapePtr theBaseShape, + const ListOfShape& theBaseShapes, const ListOfShape& theTools, const GeomMakeShapePtr& theMakeShape, const GeomShapePtr theResultShape); static void loadModifiedShapes(ResultBodyPtr theResultBody, - const GeomShapePtr theBaseShape, + const GeomShapePtr& theBaseShape, const GeomMakeShapePtr& theMakeShape, const std::string theName); - /// Stores deleted shapes. static void loadDeletedShapes(ResultBodyPtr theResultBody, const GeomShapePtr theBaseShape, diff --git a/src/Model/Model_AttributeSelection.cpp b/src/Model/Model_AttributeSelection.cpp index d4ce0fcd6..ce8a3b77f 100644 --- a/src/Model/Model_AttributeSelection.cpp +++ b/src/Model/Model_AttributeSelection.cpp @@ -1232,7 +1232,6 @@ bool Model_AttributeSelection::searchNewContext(std::shared_ptr std::list& theResults, TopTools_ListOfShape& theValShapes) { std::set aResults; // to avoid duplicates, new context, null if deleted - TopTools_ListOfShape aResContShapes; // iterate context and shape, but also if it is sub-shape of main shape, check also it TopTools_ListOfShape aContextList; aContextList.Append(theContShape); @@ -1269,7 +1268,6 @@ bool Model_AttributeSelection::searchNewContext(std::shared_ptr aModifIter.Label().FindAttribute(TNaming_NamedShape::GetID(), aNewNS); if (aNewNS->Evolution() == TNaming_MODIFY || aNewNS->Evolution() == TNaming_GENERATED) { aResults.insert(aModifierObj); - aResContShapes.Append(aModifierObj->shape()->impl()); } else if (aNewNS->Evolution() == TNaming_DELETE) { // a shape was deleted => result is empty aResults.insert(ResultPtr()); } else { // not-processed modification => don't support it @@ -1277,6 +1275,18 @@ bool Model_AttributeSelection::searchNewContext(std::shared_ptr } } } + // if there exist context composite and sub-result(s), leave only sub(s) + for(std::set::iterator aResIter = aResults.begin(); aResIter != aResults.end();) { + ResultPtr aParent = ModelAPI_Tools::bodyOwner(*aResIter); + for(; aParent.get(); aParent = ModelAPI_Tools::bodyOwner(aParent)) + if (aResults.count(aParent)) + break; + if (aParent.get()) { // erase from set, so, restart iteration + aResults.erase(aParent); + aResIter = aResults.begin(); + } else aResIter++; + } + if (aResults.empty()) return false; // no modifications found, must stay the same // iterate all results to find further modifications @@ -1420,7 +1430,8 @@ void Model_AttributeSelection::updateInHistory() setValue(*aNewCont, aValueShape); aFirst = false; } else if (myParent) { - myParent->append(*aNewCont, aValueShape); + if (!myParent->isInList(*aNewCont, aValueShape)) // avoid addition of duplicates + myParent->append(*aNewCont, aValueShape); } } if (aFirst) { // nothing was added, all results were deleted diff --git a/src/Model/Model_ResultBody.cpp b/src/Model/Model_ResultBody.cpp index 3d28be7c6..b6fb91da1 100644 --- a/src/Model/Model_ResultBody.cpp +++ b/src/Model/Model_ResultBody.cpp @@ -33,6 +33,7 @@ #include #include +#include #include // if this attribute exists, the shape is connected topology @@ -342,29 +343,55 @@ void Model_ResultBody::cleanCash() } } +// adds to the theSubSubs map all sub-shapes of theSub if it is compound of compsolid +static void collectSubs( + const GeomShapePtr theSub, TopTools_MapOfShape& theSubSubs, const bool theOneLevelMore) +{ + if (theSub->isNull()) + return; + if (theSubSubs.Add(theSub->impl())) { + bool aIsComp = theSub->isCompound() || theSub->isCompSolid(); + if (aIsComp || theOneLevelMore) { + for(GeomAPI_ShapeIterator anIter(theSub); anIter.more(); anIter.next()) { + collectSubs(anIter.current(), theSubSubs, aIsComp && theOneLevelMore); + } + } + } +} + void Model_ResultBody::computeOldForSub(const GeomShapePtr& theSub, const std::list& theAllOlds, std::list& theOldForSub) { + // the old can be also used for sub-shape of theSub; collect all subs of compound or compsolid + TopTools_MapOfShape aSubSubs; + collectSubs(theSub, aSubSubs, false); + std::list::const_iterator aRootOlds = theAllOlds.cbegin(); - for(; aRootOlds != theAllOlds.cend(); aRootOlds++) { - ListOfShape aNews; - myIsGenerated ? myAlgo->generated(*aRootOlds, aNews) : myAlgo->modified(*aRootOlds, aNews); - // MakeShape may return alone old shape if there is no history information for this input - if (aNews.size() == 1 && aNews.front()->isEqual(*aRootOlds)) - aNews.clear(); - if (aNews.empty()) { // try to iterate to sub-elements (for intersection of solids this is face) - std::list theAllSubOlds; - for(GeomAPI_ShapeIterator aSubOld(*aRootOlds); aSubOld.more(); aSubOld.next()) { - GeomShapePtr aSub = aSubOld.current(); - if (aSub.get() && !aSub->isNull()) - theAllSubOlds.push_back(aSub); - } - computeOldForSub(theSub, theAllSubOlds, theOldForSub); - } - for(ListOfShape::iterator aNewIter = aNews.begin(); aNewIter != aNews.end(); aNewIter++) { - if (theSub->isSame(*aNewIter)) { // found old that was used for new theSubShape creation - theOldForSub.push_back(*aRootOlds); - break; + for (; aRootOlds != theAllOlds.cend(); aRootOlds++) { + // use sub-shapes of olds too if they are compounds or compsolids + TopTools_MapOfShape anOldSubs; + // iterate one level more (for intersection of solids this is face) + collectSubs(*aRootOlds, anOldSubs, true); + for (TopTools_MapOfShape::Iterator anOldIter(anOldSubs); anOldIter.More(); anOldIter.Next()) { + GeomShapePtr anOldSub(new GeomAPI_Shape); + anOldSub->setImpl(new TopoDS_Shape(anOldIter.Value())); + ListOfShape aNews; + myIsGenerated ? myAlgo->generated(anOldSub, aNews) : myAlgo->modified(anOldSub, aNews); + // MakeShape may return alone old shape if there is no history information for this input + if (aNews.size() == 1 && aNews.front()->isEqual(anOldSub)) + aNews.clear(); + + for (ListOfShape::iterator aNewIter = aNews.begin(); aNewIter != aNews.end(); aNewIter++) { + if (aSubSubs.Contains((*aNewIter)->impl())) { + // check list already contains this sub + std::list::iterator aResIter = theOldForSub.begin(); + for(; aResIter != theOldForSub.end(); aResIter++) + if ((*aResIter)->isSame(anOldSub)) + break; + if (aResIter == theOldForSub.end()) + theOldForSub.push_back(anOldSub); // found old used for new theSubShape creation + break; + } } } } -- 2.39.2