From b10e938524bfb6bfeaacb049895041f22a179b0e Mon Sep 17 00:00:00 2001 From: azv Date: Tue, 11 Feb 2020 10:29:43 +0300 Subject: [PATCH] Extract ShapeHierarchy as a separate object --- .../FeaturesPlugin_BooleanCommon.cpp | 26 +- .../FeaturesPlugin_BooleanCut.cpp | 20 +- .../FeaturesPlugin_BooleanFill.cpp | 20 +- .../FeaturesPlugin_BooleanFuse.cpp | 16 +- .../FeaturesPlugin_BooleanSmash.cpp | 18 +- .../FeaturesPlugin_Partition.cpp | 26 +- src/FeaturesPlugin/FeaturesPlugin_Partition.h | 2 +- src/FeaturesPlugin/FeaturesPlugin_Union.cpp | 17 +- .../FeaturesPlugin_VersionedBoolean.cpp | 272 +----------------- .../FeaturesPlugin_VersionedBoolean.h | 99 +------ src/GeomAPI/CMakeLists.txt | 2 + src/GeomAPI/GeomAPI_ShapeHierarchy.cpp | 261 +++++++++++++++++ src/GeomAPI/GeomAPI_ShapeHierarchy.h | 121 ++++++++ src/ModelAPI/ModelAPI_Tools.cpp | 17 ++ src/ModelAPI/ModelAPI_Tools.h | 11 + 15 files changed, 504 insertions(+), 424 deletions(-) create mode 100644 src/GeomAPI/GeomAPI_ShapeHierarchy.cpp create mode 100644 src/GeomAPI/GeomAPI_ShapeHierarchy.h diff --git a/src/FeaturesPlugin/FeaturesPlugin_BooleanCommon.cpp b/src/FeaturesPlugin/FeaturesPlugin_BooleanCommon.cpp index be2c09a50..2a7b41efd 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_BooleanCommon.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_BooleanCommon.cpp @@ -59,7 +59,7 @@ void FeaturesPlugin_BooleanCommon::initAttributes() void FeaturesPlugin_BooleanCommon::execute() { ListOfShape aPlanes; - ObjectHierarchy anObjects, aTools; + GeomAPI_ShapeHierarchy anObjects, aTools; bool isSimpleMode = false; @@ -80,7 +80,7 @@ void FeaturesPlugin_BooleanCommon::execute() !processAttribute(TOOL_LIST_ID(), aTools, aPlanes)) return; - if (anObjects.IsEmpty() || (!isSimpleMode && aTools.IsEmpty() && aPlanes.empty())) { + if (anObjects.empty() || (!isSimpleMode && aTools.empty() && aPlanes.empty())) { std::string aFeatureError = "Error: Not enough objects for boolean operation."; setError(aFeatureError); return; @@ -98,9 +98,9 @@ void FeaturesPlugin_BooleanCommon::execute() ListOfShape aResultShapesList; if (isSimpleMode) { - ObjectHierarchy::Iterator anObjectsIt = anObjects.Begin(); + GeomAPI_ShapeHierarchy::iterator anObjectsIt = anObjects.begin(); GeomShapePtr aShape = *anObjectsIt; - for (++anObjectsIt; anObjectsIt != anObjects.End(); ++anObjectsIt) { + for (++anObjectsIt; anObjectsIt != anObjects.end(); ++anObjectsIt) { std::shared_ptr aCommonAlgo( new GeomAlgoAPI_Boolean(aShape, *anObjectsIt, @@ -126,7 +126,7 @@ void FeaturesPlugin_BooleanCommon::execute() std::shared_ptr aResultBody = document()->createBody(data(), aResultIndex); - ListOfShape anObjectList = anObjects.Objects(); + ListOfShape anObjectList = anObjects.objects(); ListOfShape aToolsList; FeaturesPlugin_Tools::loadModifiedShapes(aResultBody, anObjectList, @@ -154,39 +154,39 @@ void FeaturesPlugin_BooleanCommon::execute() } bool isOk = true; - for (ObjectHierarchy::Iterator anObjectsIt = anObjects.Begin(); - anObjectsIt != anObjects.End() && isOk; + for (GeomAPI_ShapeHierarchy::iterator anObjectsIt = anObjects.begin(); + anObjectsIt != anObjects.end() && isOk; ++anObjectsIt) { GeomShapePtr anObject = *anObjectsIt; - GeomShapePtr aParent = anObjects.Parent(anObject); + GeomShapePtr aParent = anObjects.parent(anObject); if (aParent) { GeomAPI_Shape::ShapeType aShapeType = aParent->shapeType(); if (aShapeType == GeomAPI_Shape::COMPOUND) { // Compound handling isOk = processCompound(GeomAlgoAPI_Tools::BOOL_COMMON, - anObjects, aParent, aTools.Objects(), + anObjects, aParent, aTools.objects(), aResultIndex, aResultBaseAlgoList, aResultShapesList, aResultCompound); } else if (aShapeType == GeomAPI_Shape::COMPSOLID) { // Compsolid handling isOk = processCompsolid(GeomAlgoAPI_Tools::BOOL_COMMON, - anObjects, aParent, aTools.Objects(), ListOfShape(), + anObjects, aParent, aTools.objects(), ListOfShape(), aResultIndex, aResultBaseAlgoList, aResultShapesList, aResultCompound); } } else { // process object as is isOk = processObject(GeomAlgoAPI_Tools::BOOL_COMMON, - anObject, aTools.Objects(), aPlanes, + anObject, aTools.objects(), aPlanes, aResultIndex, aResultBaseAlgoList, aResultShapesList, aResultCompound); } } - storeResult(anObjects.Objects(), aTools.Objects(), aResultCompound, aResultIndex, + storeResult(anObjects.objects(), aTools.objects(), aResultCompound, aResultIndex, aMakeShapeList, aResultBaseAlgoList); } @@ -195,7 +195,7 @@ void FeaturesPlugin_BooleanCommon::execute() if (!aResultCompound) aResultCompound = GeomAlgoAPI_CompoundBuilder::compound(aResultShapesList); FeaturesPlugin_Tools::loadDeletedShapes(aResultBaseAlgoList, - aTools.Objects(), + aTools.objects(), aResultCompound); // remove the rest results if there were produced in the previous pass diff --git a/src/FeaturesPlugin/FeaturesPlugin_BooleanCut.cpp b/src/FeaturesPlugin/FeaturesPlugin_BooleanCut.cpp index bc67a28e1..e00e3e9ff 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_BooleanCut.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_BooleanCut.cpp @@ -51,7 +51,7 @@ void FeaturesPlugin_BooleanCut::initAttributes() //================================================================================================== void FeaturesPlugin_BooleanCut::execute() { - ObjectHierarchy anObjects, aTools; + GeomAPI_ShapeHierarchy anObjects, aTools; ListOfShape aPlanes; // Getting objects and tools @@ -61,7 +61,7 @@ void FeaturesPlugin_BooleanCut::execute() int aResultIndex = 0; - if(anObjects.IsEmpty() || aTools.IsEmpty()) { + if(anObjects.empty() || aTools.empty()) { std::string aFeatureError = "Error: Not enough objects for boolean operation."; setError(aFeatureError); return; @@ -82,38 +82,38 @@ void FeaturesPlugin_BooleanCut::execute() // For solids cut each object with all tools. bool isOk = true; - for (ObjectHierarchy::Iterator anObjectsIt = anObjects.Begin(); - anObjectsIt != anObjects.End() && isOk; + for (GeomAPI_ShapeHierarchy::iterator anObjectsIt = anObjects.begin(); + anObjectsIt != anObjects.end() && isOk; ++anObjectsIt) { GeomShapePtr anObject = *anObjectsIt; - GeomShapePtr aParent = anObjects.Parent(anObject); + GeomShapePtr aParent = anObjects.parent(anObject); if (aParent) { GeomAPI_Shape::ShapeType aShapeType = aParent->shapeType(); if (aShapeType == GeomAPI_Shape::COMPOUND) { // Compound handling isOk = processCompound(GeomAlgoAPI_Tools::BOOL_CUT, - anObjects, aParent, aTools.Objects(), + anObjects, aParent, aTools.objects(), aResultIndex, aResultBaseAlgoList, aResultShapesList, aResultCompound); } else if (aShapeType == GeomAPI_Shape::COMPSOLID) { // Compsolid handling isOk = processCompsolid(GeomAlgoAPI_Tools::BOOL_CUT, - anObjects, aParent, aTools.Objects(), ListOfShape(), + anObjects, aParent, aTools.objects(), ListOfShape(), aResultIndex, aResultBaseAlgoList, aResultShapesList, aResultCompound); } } else { // process object as is isOk = processObject(GeomAlgoAPI_Tools::BOOL_CUT, - anObject, aTools.Objects(), aPlanes, + anObject, aTools.objects(), aPlanes, aResultIndex, aResultBaseAlgoList, aResultShapesList, aResultCompound); } } - storeResult(anObjects.Objects(), aTools.Objects(), aResultCompound, aResultIndex, + storeResult(anObjects.objects(), aTools.objects(), aResultCompound, aResultIndex, aMakeShapeList, aResultBaseAlgoList); // Store deleted shapes after all results has been proceeded. This is to avoid issue when in one @@ -121,7 +121,7 @@ void FeaturesPlugin_BooleanCut::execute() if (!aResultCompound) aResultCompound = GeomAlgoAPI_CompoundBuilder::compound(aResultShapesList); FeaturesPlugin_Tools::loadDeletedShapes(aResultBaseAlgoList, - aTools.Objects(), + aTools.objects(), aResultCompound); // remove the rest results if there were produced in the previous pass diff --git a/src/FeaturesPlugin/FeaturesPlugin_BooleanFill.cpp b/src/FeaturesPlugin/FeaturesPlugin_BooleanFill.cpp index 3f6dd4cc0..cb039b01a 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_BooleanFill.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_BooleanFill.cpp @@ -57,7 +57,7 @@ void FeaturesPlugin_BooleanFill::initAttributes() void FeaturesPlugin_BooleanFill::execute() { std::string anError; - ObjectHierarchy anObjects, aTools; + GeomAPI_ShapeHierarchy anObjects, aTools; ListOfShape aPlanes; // Getting objects. @@ -72,7 +72,7 @@ void FeaturesPlugin_BooleanFill::execute() int aResultIndex = 0; - if (anObjects.IsEmpty() || (aTools.IsEmpty() && aPlanes.empty())) { + if (anObjects.empty() || (aTools.empty() && aPlanes.empty())) { std::string aFeatureError = "Error: Not enough objects for boolean operation."; setError(aFeatureError); return; @@ -92,30 +92,30 @@ void FeaturesPlugin_BooleanFill::execute() // For solids cut each object with all tools. bool isOk = true; - for (ObjectHierarchy::Iterator anObjectsIt = anObjects.Begin(); - anObjectsIt != anObjects.End() && isOk; + for (GeomAPI_ShapeHierarchy::iterator anObjectsIt = anObjects.begin(); + anObjectsIt != anObjects.end() && isOk; ++anObjectsIt) { GeomShapePtr anObject = *anObjectsIt; - GeomShapePtr aParent = anObjects.Parent(anObject, false); + GeomShapePtr aParent = anObjects.parent(anObject, false); if (aParent && aParent->shapeType() == GeomAPI_Shape::COMPSOLID) { // get parent once again to mark it and the subs as processed - aParent = anObjects.Parent(anObject); + aParent = anObjects.parent(anObject); // compsolid handling isOk = processCompsolid(GeomAlgoAPI_Tools::BOOL_PARTITION, - anObjects, aParent, aTools.Objects(), aPlanes, + anObjects, aParent, aTools.objects(), aPlanes, aResultIndex, aResultBaseAlgoList, aResultShapesList, aResultCompound); } else { // process object as is isOk = processObject(GeomAlgoAPI_Tools::BOOL_PARTITION, - anObject, aTools.Objects(), aPlanes, + anObject, aTools.objects(), aPlanes, aResultIndex, aResultBaseAlgoList, aResultShapesList, aResultCompound); } } - storeResult(anObjects.Objects(), aTools.Objects(), aResultCompound, aResultIndex, + storeResult(anObjects.objects(), aTools.objects(), aResultCompound, aResultIndex, aMakeShapeList, aResultBaseAlgoList); // Store deleted shapes after all results has been proceeded. This is to avoid issue when in one @@ -123,7 +123,7 @@ void FeaturesPlugin_BooleanFill::execute() if (!aResultCompound) aResultCompound = GeomAlgoAPI_CompoundBuilder::compound(aResultShapesList); FeaturesPlugin_Tools::loadDeletedShapes(aResultBaseAlgoList, - aTools.Objects(), + aTools.objects(), aResultCompound); // remove the rest results if there were produced in the previous pass diff --git a/src/FeaturesPlugin/FeaturesPlugin_BooleanFuse.cpp b/src/FeaturesPlugin/FeaturesPlugin_BooleanFuse.cpp index a7a1b0cc1..77d5bcefd 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_BooleanFuse.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_BooleanFuse.cpp @@ -67,7 +67,7 @@ void FeaturesPlugin_BooleanFuse::initAttributes() void FeaturesPlugin_BooleanFuse::execute() { std::string anError; - ObjectHierarchy anObjectsHierarchy, aToolsHierarchy; + GeomAPI_ShapeHierarchy anObjectsHierarchy, aToolsHierarchy; ListOfShape aPlanes; bool isSimpleCreation = false; @@ -90,9 +90,9 @@ void FeaturesPlugin_BooleanFuse::execute() ListOfShape anObjects, aTools, anEdgesAndFaces; // all objects except edges and faces - anObjectsHierarchy.ObjectsByType(anEdgesAndFaces, anObjects, + anObjectsHierarchy.objectsByType(anEdgesAndFaces, anObjects, GeomAPI_Shape::FACE, GeomAPI_Shape::EDGE); - aToolsHierarchy.ObjectsByType(anEdgesAndFaces, aTools, + aToolsHierarchy.objectsByType(anEdgesAndFaces, aTools, GeomAPI_Shape::FACE, GeomAPI_Shape::EDGE); if ((anObjects.size() + aTools.size() + anEdgesAndFaces.size()) < 2) { @@ -113,18 +113,18 @@ void FeaturesPlugin_BooleanFuse::execute() // in boolean operation and will be added to result. bool isProcessCompsolid = !isSimpleCreation || !aFuseVersion.empty(); ListOfShape aShapesToAdd; - for (ObjectHierarchy::Iterator anObjectsIt = anObjectsHierarchy.Begin(); - isProcessCompsolid && anObjectsIt != anObjectsHierarchy.End(); + for (GeomAPI_ShapeHierarchy::iterator anObjectsIt = anObjectsHierarchy.begin(); + isProcessCompsolid && anObjectsIt != anObjectsHierarchy.end(); ++anObjectsIt) { GeomShapePtr anObject = *anObjectsIt; - GeomShapePtr aParent = anObjectsHierarchy.Parent(anObject, false); + GeomShapePtr aParent = anObjectsHierarchy.parent(anObject, false); if (aParent && aParent->shapeType() == GeomAPI_Shape::COMPSOLID) { // mark all subs of this parent as precessed to avoid handling twice - aParent = anObjectsHierarchy.Parent(anObject); + aParent = anObjectsHierarchy.parent(anObject); ListOfShape aUsed, aNotUsed; - anObjectsHierarchy.SplitCompound(aParent, aUsed, aNotUsed); + anObjectsHierarchy.splitCompound(aParent, aUsed, aNotUsed); aShapesToAdd.insert(aShapesToAdd.end(), aNotUsed.begin(), aNotUsed.end()); } } diff --git a/src/FeaturesPlugin/FeaturesPlugin_BooleanSmash.cpp b/src/FeaturesPlugin/FeaturesPlugin_BooleanSmash.cpp index 9d053f0e9..0fde78876 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_BooleanSmash.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_BooleanSmash.cpp @@ -54,7 +54,7 @@ void FeaturesPlugin_BooleanSmash::initAttributes() void FeaturesPlugin_BooleanSmash::execute() { std::string anError; - ObjectHierarchy anObjectsHistory, aToolsHistory; + GeomAPI_ShapeHierarchy anObjectsHistory, aToolsHistory; ListOfShape aPlanes; // Getting objects and tools. @@ -64,41 +64,41 @@ void FeaturesPlugin_BooleanSmash::execute() int aResultIndex = 0; - if (anObjectsHistory.IsEmpty() || aToolsHistory.IsEmpty()) { + if (anObjectsHistory.empty() || aToolsHistory.empty()) { std::string aFeatureError = "Error: Not enough objects for boolean operation."; setError(aFeatureError); return; } // Collecting all shapes which will be smashed. - ListOfShape aShapesToSmash = anObjectsHistory.Objects(); + ListOfShape aShapesToSmash = anObjectsHistory.objects(); // List of original shapes for naming. ListOfShape anOriginalShapes; anOriginalShapes.insert(anOriginalShapes.end(), aShapesToSmash.begin(), aShapesToSmash.end()); - ListOfShape aTools = aToolsHistory.Objects(); + ListOfShape aTools = aToolsHistory.objects(); anOriginalShapes.insert(anOriginalShapes.end(), aTools.begin(), aTools.end()); // Collecting solids from compsolids which will not be modified in // boolean operation and will be added to result. ListOfShape aShapesToAdd; - for (ObjectHierarchy::Iterator anIt = anObjectsHistory.Begin(); - anIt != anObjectsHistory.End(); + for (GeomAPI_ShapeHierarchy::iterator anIt = anObjectsHistory.begin(); + anIt != anObjectsHistory.end(); ++anIt) { - GeomShapePtr aParent = anObjectsHistory.Parent(*anIt, false); + GeomShapePtr aParent = anObjectsHistory.parent(*anIt, false); if (aParent) { anOriginalShapes.push_back(aParent); ListOfShape aUsed, aNotUsed; - anObjectsHistory.SplitCompound(aParent, aUsed, aNotUsed); + anObjectsHistory.splitCompound(aParent, aUsed, aNotUsed); aShapesToAdd.insert(aShapesToAdd.end(), aNotUsed.begin(), aNotUsed.end()); // add unused shapes of compounds/compsolids to the history, // to avoid treating them as unused later when constructing a compound containing // the result of Smash and all unused sub-shapes of multi-level compounds for (ListOfShape::iterator anIt = aNotUsed.begin(); anIt != aNotUsed.end(); ++anIt) - anObjectsHistory.AddObject(*anIt); + anObjectsHistory.addObject(*anIt); } } diff --git a/src/FeaturesPlugin/FeaturesPlugin_Partition.cpp b/src/FeaturesPlugin/FeaturesPlugin_Partition.cpp index 58b3784e9..9c348199b 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_Partition.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_Partition.cpp @@ -64,23 +64,23 @@ void FeaturesPlugin_Partition::initAttributes() //================================================================================================= void FeaturesPlugin_Partition::execute() { - ObjectHierarchy anObjects; + GeomAPI_ShapeHierarchy anObjects; ListOfShape aPlanes; // Getting objects. processAttribute(BASE_OBJECTS_ID(), anObjects, aPlanes); - if(anObjects.IsEmpty()) { + if(anObjects.empty()) { static const std::string aFeatureError = "Error: No objects for partition."; setError(aFeatureError); return; } - ListOfShape aBaseObjects = anObjects.Objects(); + ListOfShape aBaseObjects = anObjects.objects(); aBaseObjects.insert(aBaseObjects.end(), aPlanes.begin(), aPlanes.end()); // resize planes to the bounding box of operated shapes std::shared_ptr aMakeShapeList(new GeomAlgoAPI_MakeShapeList()); - resizePlanes(anObjects.Objects(), aPlanes, aMakeShapeList); + resizePlanes(anObjects.objects(), aPlanes, aMakeShapeList); // cut unused solids of composolids from the objects of partition ListOfShape aTargetObjects, anUnusedSubs; @@ -147,7 +147,7 @@ void FeaturesPlugin_Partition::execute() } GeomShapePtr aResultCompound = - keepUnusedSubsOfCompound(aFirstShape, anObjects, ObjectHierarchy(), aMakeShapeList); + keepUnusedSubsOfCompound(aFirstShape, anObjects, GeomAPI_ShapeHierarchy(), aMakeShapeList); if (anIt.more()) { if (aResultCompound->shapeType() != GeomAPI_Shape::COMPOUND) { @@ -234,7 +234,7 @@ static bool cutSubs(ListOfShape& theSubsToCut, } bool FeaturesPlugin_Partition::cutSubs( - FeaturesPlugin_Partition::ObjectHierarchy& theHierarchy, + GeomAPI_ShapeHierarchy& theHierarchy, ListOfShape& theUsed, ListOfShape& theNotUsed, std::shared_ptr& theMakeShapeList, @@ -243,14 +243,14 @@ bool FeaturesPlugin_Partition::cutSubs( theUsed.clear(); theNotUsed.clear(); - ObjectHierarchy::Iterator anIt = theHierarchy.Begin(); + GeomAPI_ShapeHierarchy::iterator anIt = theHierarchy.begin(); // compose a set of tools for the CUT operation: // find the list of unused subs of the first argument or use itself ListOfShape aToolsForUsed, aToolsForUnused; - GeomShapePtr aFirstArgument = theHierarchy.Parent(*anIt, false); + GeomShapePtr aFirstArgument = theHierarchy.parent(*anIt, false); if (aFirstArgument && aFirstArgument->shapeType() == GeomAPI_Shape::COMPSOLID) { - theHierarchy.SplitCompound(aFirstArgument, theUsed, aToolsForUsed); + theHierarchy.splitCompound(aFirstArgument, theUsed, aToolsForUsed); theNotUsed = aToolsForUsed; } else { @@ -261,13 +261,13 @@ bool FeaturesPlugin_Partition::cutSubs( // cut subs bool isOk = true; - for (++anIt; anIt != theHierarchy.End() && isOk; ++anIt) { + for (++anIt; anIt != theHierarchy.end() && isOk; ++anIt) { ListOfShape aUsed, aNotUsed; - GeomShapePtr aParent = theHierarchy.Parent(*anIt, false); + GeomShapePtr aParent = theHierarchy.parent(*anIt, false); if (aParent && aParent->shapeType() == GeomAPI_Shape::COMPSOLID) { - aParent = theHierarchy.Parent(*anIt); // get parent once again to mark its subs as processed - theHierarchy.SplitCompound(aParent, aUsed, aNotUsed); + aParent = theHierarchy.parent(*anIt); // get parent once again to mark its subs as processed + theHierarchy.splitCompound(aParent, aUsed, aNotUsed); } else aUsed.push_back(*anIt); diff --git a/src/FeaturesPlugin/FeaturesPlugin_Partition.h b/src/FeaturesPlugin/FeaturesPlugin_Partition.h index b358831d0..5c15c5285 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_Partition.h +++ b/src/FeaturesPlugin/FeaturesPlugin_Partition.h @@ -73,7 +73,7 @@ private: /// Cut all of unused subs of compsolids by the full compsolid of the first selected object, /// and vice versa, cut all objects of Partition by not used subs of the first selected object. /// Store results of operation to the separated lists of shapes. - bool cutSubs(ObjectHierarchy& theHierarchy, + bool cutSubs(GeomAPI_ShapeHierarchy& theHierarchy, ListOfShape& theUsed, ListOfShape& theNotUsed, std::shared_ptr& theMakeShapeList, diff --git a/src/FeaturesPlugin/FeaturesPlugin_Union.cpp b/src/FeaturesPlugin/FeaturesPlugin_Union.cpp index 0a3107b76..2c658cd90 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_Union.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_Union.cpp @@ -48,14 +48,14 @@ void FeaturesPlugin_Union::initAttributes() //================================================================================================= void FeaturesPlugin_Union::execute() { - ObjectHierarchy anObjects; + GeomAPI_ShapeHierarchy anObjects; ListOfShape anEmptyList; // Getting objects. if (!processAttribute(BASE_OBJECTS_ID(), anObjects, anEmptyList)) return; - if(anObjects.Objects().size() < 2) { + if(anObjects.objects().size() < 2) { setError("Error: Not enough objects for operation. Should be at least 2."); return; } @@ -69,15 +69,15 @@ void FeaturesPlugin_Union::execute() // Fuse objects. bool isOk = true; - for (ObjectHierarchy::Iterator anObjectsIt = anObjects.Begin(); - anObjectsIt != anObjects.End() && isOk; + for (GeomAPI_ShapeHierarchy::iterator anObjectsIt = anObjects.begin(); + anObjectsIt != anObjects.end() && isOk; ++anObjectsIt) { GeomShapePtr anObject = *anObjectsIt; - GeomShapePtr aParent = anObjects.Parent(anObject, false); + GeomShapePtr aParent = anObjects.parent(anObject, false); if (aParent && aParent->shapeType() <= GeomAPI_Shape::COMPSOLID) { // get parent once again to mark it and the subs as processed - aParent = anObjects.Parent(anObject); + aParent = anObjects.parent(anObject); // compsolid handling isOk = processCompsolid(GeomAlgoAPI_Tools::BOOL_FUSE, anObjects, aParent, anEmptyList, anEmptyList, @@ -111,7 +111,8 @@ void FeaturesPlugin_Union::execute() } else { // merge hierarchies of compounds containing objects and tools - aShape = keepUnusedSubsOfCompound(aCIt.current(), anObjects, ObjectHierarchy(), aMakeShapeList); + aShape = keepUnusedSubsOfCompound(aCIt.current(), anObjects, GeomAPI_ShapeHierarchy(), + aMakeShapeList); for (aCIt.next(); aCIt.more(); aCIt.next()) { std::shared_ptr aBuilder(new GeomAlgoAPI_ShapeBuilder); aBuilder->add(aShape, aCIt.current()); @@ -121,7 +122,7 @@ void FeaturesPlugin_Union::execute() // Store result and naming. std::shared_ptr aResultBody = document()->createBody(data()); - ListOfShape anObjectsList = anObjects.Objects(); + ListOfShape anObjectsList = anObjects.objects(); aResultBody->storeModified(anObjectsList.front(), aShape); for(ListOfShape::const_iterator anIter = anObjectsList.begin(); diff --git a/src/FeaturesPlugin/FeaturesPlugin_VersionedBoolean.cpp b/src/FeaturesPlugin/FeaturesPlugin_VersionedBoolean.cpp index bba9645aa..34a459fd7 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_VersionedBoolean.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_VersionedBoolean.cpp @@ -89,22 +89,8 @@ void FeaturesPlugin_VersionedBoolean::initVersion(const std::string& theVersion, } //================================================================================================= -void FeaturesPlugin_VersionedBoolean::parentForShape(const GeomShapePtr& theShape, - const ResultPtr& theContext, - ObjectHierarchy& theShapesHierarchy) -{ - ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(theContext); - if (aResCompSolidPtr.get()) { - std::shared_ptr aContextShape = aResCompSolidPtr->shape(); - if (aContextShape->shapeType() <= GeomAPI_Shape::COMPSOLID) { - theShapesHierarchy.AddParent(theShape, aContextShape); - parentForShape(aContextShape, aResCompSolidPtr, theShapesHierarchy); - } - } -} - bool FeaturesPlugin_VersionedBoolean::processAttribute(const std::string& theAttributeName, - ObjectHierarchy& theObjects, + GeomAPI_ShapeHierarchy& theObjects, ListOfShape& thePlanesList) { AttributeSelectionListPtr anObjectsSelList = selectionList(theAttributeName); @@ -122,10 +108,10 @@ bool FeaturesPlugin_VersionedBoolean::processAttribute(const std::string& theAtt return false; } - theObjects.AddObject(anObject); + theObjects.addObject(anObject); ResultPtr aContext = anObjectAttr->context(); - parentForShape(anObject, aContext, theObjects); + ModelAPI_Tools::fillShapeHierarchy(anObject, aContext, theObjects); } return true; } @@ -224,7 +210,7 @@ bool FeaturesPlugin_VersionedBoolean::processObject( //================================================================================================= bool FeaturesPlugin_VersionedBoolean::processCompsolid( const GeomAlgoAPI_Tools::BOPType theBooleanType, - ObjectHierarchy& theCompsolidHierarchy, + GeomAPI_ShapeHierarchy& theCompsolidHierarchy, const GeomShapePtr& theCompsolid, const ListOfShape& theTools, const ListOfShape& thePlanes, @@ -235,7 +221,7 @@ bool FeaturesPlugin_VersionedBoolean::processCompsolid( { ListOfShape aUsedInOperationSolids; ListOfShape aNotUsedSolids; - theCompsolidHierarchy.SplitCompound(theCompsolid, aUsedInOperationSolids, aNotUsedSolids); + theCompsolidHierarchy.splitCompound(theCompsolid, aUsedInOperationSolids, aNotUsedSolids); std::shared_ptr aMakeShapeList(new GeomAlgoAPI_MakeShapeList()); @@ -260,7 +246,7 @@ bool FeaturesPlugin_VersionedBoolean::processCompsolid( // Add result to not used solids from compsolid. if (!aNotUsedSolids.empty()) { - theCompsolidHierarchy.MarkProcessed(aNotUsedSolids); + theCompsolidHierarchy.markProcessed(aNotUsedSolids); ListOfShape aShapesToAdd = aNotUsedSolids; aShapesToAdd.push_back(aBoolAlgo->shape()); @@ -319,7 +305,7 @@ bool FeaturesPlugin_VersionedBoolean::processCompsolid( //================================================================================================= bool FeaturesPlugin_VersionedBoolean::processCompound( const GeomAlgoAPI_Tools::BOPType theBooleanType, - ObjectHierarchy& theCompoundHierarchy, + GeomAPI_ShapeHierarchy& theCompoundHierarchy, const GeomShapePtr& theCompound, const ListOfShape& theTools, int& theResultIndex, @@ -329,7 +315,7 @@ bool FeaturesPlugin_VersionedBoolean::processCompound( { ListOfShape aUsedInOperationShapes; ListOfShape aNotUsedShapes; - theCompoundHierarchy.SplitCompound(theCompound, aUsedInOperationShapes, aNotUsedShapes); + theCompoundHierarchy.splitCompound(theCompound, aUsedInOperationShapes, aNotUsedShapes); if (theResultCompound) { // Not necessary to keep all subs of the current compound, // all unused solids are already stored in the result compound. @@ -352,7 +338,7 @@ bool FeaturesPlugin_VersionedBoolean::processCompound( // Add result to not used shape from compound. if (!aNotUsedShapes.empty()) { - theCompoundHierarchy.MarkProcessed(aNotUsedShapes); + theCompoundHierarchy.markProcessed(aNotUsedShapes); ListOfShape aShapesForResult = aNotUsedShapes; if (aResultShape->shapeType() == GeomAPI_Shape::COMPOUND) { @@ -408,13 +394,13 @@ bool FeaturesPlugin_VersionedBoolean::processCompound( //================================================================================================== GeomShapePtr FeaturesPlugin_VersionedBoolean::keepUnusedSubsOfCompound( const GeomShapePtr& theResult, - const ObjectHierarchy& theObjectsHierarchy, - const ObjectHierarchy& theToolsHierarchy, + const GeomAPI_ShapeHierarchy& theObjectsHierarchy, + const GeomAPI_ShapeHierarchy& theToolsHierarchy, std::shared_ptr theMakeShapeList) { ListOfShape aCompounds; - theObjectsHierarchy.CompoundsOfUnusedObjects(aCompounds); - theToolsHierarchy.CompoundsOfUnusedObjects(aCompounds); + theObjectsHierarchy.compoundsOfUnusedObjects(aCompounds); + theToolsHierarchy.compoundsOfUnusedObjects(aCompounds); GeomShapePtr aResultShape = theResult; if (!aCompounds.empty()) { @@ -450,235 +436,3 @@ void FeaturesPlugin_VersionedBoolean::resizePlanes( *anIt = aTool; } } - -//================================================================================================= - -void FeaturesPlugin_VersionedBoolean::ObjectHierarchy::AddObject(const GeomShapePtr& theObject) -{ - myObjects.push_back(theObject); -} - -void FeaturesPlugin_VersionedBoolean::ObjectHierarchy::AddParent(const GeomShapePtr& theShape, - const GeomShapePtr& theParent) -{ - myParent[theShape] = theParent; - - MapShapeToIndex::iterator aFound = myParentIndices.find(theParent); - size_t anIndex = myParentIndices.size(); - if (aFound == myParentIndices.end()) { - myParentIndices[theParent] = anIndex; - mySubshapes.push_back(ShapeAndSubshapes(theParent, ListOfShape())); - } else - anIndex = aFound->second; - - mySubshapes[anIndex].second.push_back(theShape); -} - -GeomShapePtr FeaturesPlugin_VersionedBoolean::ObjectHierarchy::Parent(const GeomShapePtr& theShape, - bool theMarkProcessed) -{ - MapShapeToParent::const_iterator aFound = myParent.find(theShape); - GeomShapePtr aParent; - if (aFound != myParent.end()) { - aParent = aFound->second; - if (theMarkProcessed) { - // mark the parent and all its subs as processed by Boolean algorithm - myProcessedObjects.insert(aParent); - const ListOfShape& aSubs = mySubshapes[myParentIndices[aParent]].second; - for (ListOfShape::const_iterator anIt = aSubs.begin(); anIt != aSubs.end(); ++anIt) - myProcessedObjects.insert(*anIt); - } - } - return aParent; -} - -void FeaturesPlugin_VersionedBoolean::ObjectHierarchy::MarkProcessed(const GeomShapePtr& theShape) -{ - myProcessedObjects.insert(theShape); -} - -void FeaturesPlugin_VersionedBoolean::ObjectHierarchy::MarkProcessed(const ListOfShape& theShapes) -{ - for (ListOfShape::const_iterator anIt = theShapes.begin(); anIt != theShapes.end(); ++anIt) - MarkProcessed(*anIt); -} - -void FeaturesPlugin_VersionedBoolean::ObjectHierarchy::ObjectsByType( - ListOfShape& theShapesByType, - ListOfShape& theOtherShapes, - const GeomAPI_Shape::ShapeType theMinType, - const GeomAPI_Shape::ShapeType theMaxType) const -{ - if (theMinType > theMaxType) - return ObjectsByType(theShapesByType, theOtherShapes, theMaxType, theMinType); - - // no need to select objects if whole range is specified - if (theMinType == GeomAPI_Shape::COMPOUND && theMaxType == GeomAPI_Shape::SHAPE) { - theShapesByType.insert(theShapesByType.end(), myObjects.begin(), myObjects.end()); - return; - } - - for (ListOfShape::const_iterator anIt = myObjects.begin(); anIt != myObjects.end(); ++anIt) { - GeomAPI_Shape::ShapeType aType = (*anIt)->shapeType(); - if (aType >= theMinType && aType <= theMaxType) - theShapesByType.push_back(*anIt); - else - theOtherShapes.push_back(*anIt); - } -} - - -void FeaturesPlugin_VersionedBoolean::ObjectHierarchy::SplitCompound( - const GeomShapePtr& theCompShape, - ListOfShape& theUsed, - ListOfShape& theNotUsed) const -{ - theUsed.clear(); - theNotUsed.clear(); - - MapShapeToIndex::const_iterator aFoundIndex = myParentIndices.find(theCompShape); - if (aFoundIndex == myParentIndices.end()) - return; // no such shape - - theUsed = mySubshapes[aFoundIndex->second].second; - SetOfShape aSubsSet; - aSubsSet.insert(theUsed.begin(), theUsed.end()); - - for (GeomAPI_ShapeIterator anExp(theCompShape); anExp.more(); anExp.next()) { - GeomShapePtr aCurrent = anExp.current(); - if (aSubsSet.find(aCurrent) == aSubsSet.end()) - theNotUsed.push_back(aCurrent); - } -} - -bool FeaturesPlugin_VersionedBoolean::ObjectHierarchy::IsEmpty() const -{ - return myObjects.empty(); -} - -void FeaturesPlugin_VersionedBoolean::ObjectHierarchy::CompoundsOfUnusedObjects( - ListOfShape& theDestination) const -{ - SetOfShape aUsedObjects = myProcessedObjects; - aUsedObjects.insert(myObjects.begin(), myObjects.end()); - - for (std::vector::const_iterator anIt = mySubshapes.begin(); - anIt != mySubshapes.end(); ++anIt) { - MapShapeToParent::const_iterator aParent = myParent.find(anIt->first); - if ((aParent == myParent.end() || !aParent->second) && - anIt->first->shapeType() == GeomAPI_Shape::COMPOUND) { - // this is a top-level compound - GeomShapePtr aCompound = collectUnusedSubs(anIt->first, aUsedObjects); - // add to destination non-empty compounds only - if (aCompound) - theDestination.push_back(aCompound); - } - } -} - -GeomShapePtr FeaturesPlugin_VersionedBoolean::ObjectHierarchy::collectUnusedSubs( - GeomShapePtr theTopLevelCompound, - const SetOfShape& theUsed) const -{ - GeomShapePtr aResult = theTopLevelCompound->emptyCopied(); - bool isResultEmpty = true; - - for (GeomAPI_ShapeIterator aSub(theTopLevelCompound); aSub.more(); aSub.next()) { - GeomShapePtr aCurrent = aSub.current(); - if (theUsed.find(aCurrent) != theUsed.end()) - continue; // already used - - MapShapeToIndex::const_iterator aFoundIndex = myParentIndices.find(aCurrent); - if (aCurrent->shapeType() > GeomAPI_Shape::COMPOUND || - aFoundIndex == myParentIndices.end()) { - bool isAddShape = true; - // check compsolid is fully unused in the Boolean operation - if (aCurrent->shapeType() == GeomAPI_Shape::COMPSOLID) { - for (GeomAPI_ShapeIterator anIt(aCurrent); isAddShape && anIt.more(); anIt.next()) - isAddShape = theUsed.find(anIt.current()) == theUsed.end(); - } - - if (isAddShape) { // low-level shape, add it - GeomAlgoAPI_ShapeBuilder::add(aResult, aCurrent); - isResultEmpty = false; - } - } else { - GeomShapePtr aCompound = collectUnusedSubs(aCurrent, theUsed); - if (aCompound) { - GeomAlgoAPI_ShapeBuilder::add(aResult, aCompound); - isResultEmpty = false; - } - } - } - return isResultEmpty ? GeomShapePtr() : aResult; -} - - -FeaturesPlugin_VersionedBoolean::ObjectHierarchy::Iterator -FeaturesPlugin_VersionedBoolean::ObjectHierarchy::Begin() -{ - return Iterator(this); -} - -FeaturesPlugin_VersionedBoolean::ObjectHierarchy::Iterator -FeaturesPlugin_VersionedBoolean::ObjectHierarchy::End() -{ - return Iterator(this, false); -} - -FeaturesPlugin_VersionedBoolean::ObjectHierarchy::Iterator::Iterator( - FeaturesPlugin_VersionedBoolean::ObjectHierarchy* theHierarchy, bool isBegin) - : myHierarchy(theHierarchy) -{ - if (isBegin) { - myObject = myHierarchy->myObjects.begin(); - SkipAlreadyProcessed(); - } else - myObject = myHierarchy->myObjects.end(); -} - -void FeaturesPlugin_VersionedBoolean::ObjectHierarchy::Iterator::SkipAlreadyProcessed() -{ - while (myObject != myHierarchy->myObjects.end() && - myHierarchy->myProcessedObjects.find(*myObject) != myHierarchy->myProcessedObjects.end()) - ++myObject; -} - -bool FeaturesPlugin_VersionedBoolean::ObjectHierarchy::Iterator::operator==( - const Iterator& theOther) const -{ - return myObject == theOther.myObject; -} - -bool FeaturesPlugin_VersionedBoolean::ObjectHierarchy::Iterator::operator!=( - const Iterator& theOther) const -{ - return !operator==(theOther); -} - -FeaturesPlugin_VersionedBoolean::ObjectHierarchy::Iterator& -FeaturesPlugin_VersionedBoolean::ObjectHierarchy::Iterator::operator++() -{ - ++myObject; - SkipAlreadyProcessed(); - return *this; -} - -FeaturesPlugin_VersionedBoolean::ObjectHierarchy::Iterator -FeaturesPlugin_VersionedBoolean::ObjectHierarchy::Iterator::operator++(int) -{ - Iterator aCurrent; - aCurrent.myHierarchy = myHierarchy; - aCurrent.myObject = myObject; - - // increase iterator - operator++(); - - return aCurrent; -} - -GeomShapePtr FeaturesPlugin_VersionedBoolean::ObjectHierarchy::Iterator::operator*() const -{ - myHierarchy->myProcessedObjects.insert(*myObject); - return *myObject; -} diff --git a/src/FeaturesPlugin/FeaturesPlugin_VersionedBoolean.h b/src/FeaturesPlugin/FeaturesPlugin_VersionedBoolean.h index 098509c3c..074a59bce 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_VersionedBoolean.h +++ b/src/FeaturesPlugin/FeaturesPlugin_VersionedBoolean.h @@ -23,6 +23,7 @@ #include "FeaturesPlugin.h" #include "FeaturesPlugin_Tools.h" +#include #include #include @@ -55,92 +56,9 @@ protected: const std::shared_ptr theToolsAttr = std::shared_ptr()); - /// Auxiliary class to store hierarchy of Boolean operation objects/tools - /// and their parent shapes (compounds or compsolids) - class ObjectHierarchy { - typedef std::pair ShapeAndSubshapes; - typedef std::map MapShapeToParent; - typedef std::map MapShapeToIndex; - typedef std::set SetOfShape; - - ListOfShape myObjects; ///< list of objects/tools of Boolean operation - MapShapeToParent myParent; ///< refer a shape to compound/compsolid containing it - /// indices of compounds/compsolids to keep the order of parent shapes - /// corresponding to the order of objects - MapShapeToIndex myParentIndices; - /// list of shape and its subshapes stored according to the index of parent shape - std::vector mySubshapes; - - SetOfShape myProcessedObjects; - - public: - /// Add object of Boolean opration - void AddObject(const GeomShapePtr& theObject); - - /// Maps shape and its parent - void AddParent(const GeomShapePtr& theShape, const GeomShapePtr& theParent); - - /// Return parent shape for the given, or empty if it is a high-level shape. - /// By default, the parent and all its subshapes are marked as processed for further skip. - GeomShapePtr Parent(const GeomShapePtr& theShape, bool theMarkProcessed = true); - - /// Marke the shape as already processed - void MarkProcessed(const GeomShapePtr& theShape); - /// Marke list ofshapes as already processed - void MarkProcessed(const ListOfShape& theShapes); - - /// Split compound/compsolid shape for subshapes selected for Boolean operation and the other. - void SplitCompound(const GeomShapePtr& theCompShape, - ListOfShape& theUsed, - ListOfShape& theNotUsed) const; - - /// Generates the list of top-level compounds, which contain the objects of Boolean operation. - /// The generated list will contain only shapes unused during the Boolean operation. - void CompoundsOfUnusedObjects(ListOfShape& theDestination) const; - - /// Return \c true if there is no object in hierarchy - bool IsEmpty() const; - - /// Return list of objects - const ListOfShape& Objects() const { return myObjects; } - /// Separate objects of the given range of types and all other objects - void ObjectsByType(ListOfShape& theShapesByType, ListOfShape& theOtherShapes, - const GeomAPI_Shape::ShapeType theMinType = GeomAPI_Shape::COMPOUND, - const GeomAPI_Shape::ShapeType theMaxType = GeomAPI_Shape::SHAPE) const; - - private: - GeomShapePtr collectUnusedSubs(const GeomShapePtr theTopLevelCompound, - const SetOfShape& theUsed) const; - - public: - class Iterator { - friend class ObjectHierarchy; - - ObjectHierarchy* myHierarchy; - ListOfShape::iterator myObject; - - Iterator() {} - Iterator(ObjectHierarchy* theHierarchy, bool isBegin = true); - - void SkipAlreadyProcessed(); - - public: - bool operator==(const Iterator&) const; - bool operator!=(const Iterator&) const; - - Iterator& operator++(); - Iterator operator++(int); - - GeomShapePtr operator*() const; - }; - - Iterator Begin(); - Iterator End(); - }; - /// Process SelectionList attribute and fill the objects hierarchy. bool processAttribute(const std::string& theAttributeName, - ObjectHierarchy& theObjects, + GeomAPI_ShapeHierarchy& theObjects, ListOfShape& thePlanesList); /// Perform Boolean operation of the object with the tools. @@ -161,7 +79,7 @@ protected: /// is added to this compound, and corresponding ResultBody is not generated. /// \return \c false if something went wrong bool processCompsolid(const GeomAlgoAPI_Tools::BOPType theBooleanType, - ObjectHierarchy& theCompsolidHierarchy, + GeomAPI_ShapeHierarchy& theCompsolidHierarchy, const GeomShapePtr& theCompsolid, const ListOfShape& theTools, const ListOfShape& thePlanes, @@ -175,7 +93,7 @@ protected: /// is added to this compound, and corresponding ResultBody is not generated. /// \return \c false if something went wrong bool processCompound(const GeomAlgoAPI_Tools::BOPType theBooleanType, - ObjectHierarchy& theCompoundHierarchy, + GeomAPI_ShapeHierarchy& theCompoundHierarchy, const GeomShapePtr& theCompound, const ListOfShape& theTools, int& theResultIndex, @@ -193,14 +111,9 @@ protected: /// into a single compound and add the result of the FUSE operation. GeomShapePtr keepUnusedSubsOfCompound( const GeomShapePtr& theResult, - const ObjectHierarchy& theObjectsHierarchy, - const ObjectHierarchy& theToolsHierarchy, + const GeomAPI_ShapeHierarchy& theObjectsHierarchy, + const GeomAPI_ShapeHierarchy& theToolsHierarchy, std::shared_ptr theMakeShapeList); - -private: - void parentForShape(const GeomShapePtr& theShape, - const std::shared_ptr& theContext, - ObjectHierarchy& theShapesHierarchy); }; #endif diff --git a/src/GeomAPI/CMakeLists.txt b/src/GeomAPI/CMakeLists.txt index 267c703a9..4b3c816da 100644 --- a/src/GeomAPI/CMakeLists.txt +++ b/src/GeomAPI/CMakeLists.txt @@ -70,6 +70,7 @@ SET(PROJECT_HEADERS GeomAPI_Torus.h GeomAPI_Box.h GeomAPI_WireExplorer.h + GeomAPI_ShapeHierarchy.h ) SET(PROJECT_SOURCES @@ -118,6 +119,7 @@ SET(PROJECT_SOURCES GeomAPI_Torus.cpp GeomAPI_Box.cpp GeomAPI_WireExplorer.cpp + GeomAPI_ShapeHierarchy.cpp ) SET(PROJECT_LIBRARIES diff --git a/src/GeomAPI/GeomAPI_ShapeHierarchy.cpp b/src/GeomAPI/GeomAPI_ShapeHierarchy.cpp new file mode 100644 index 000000000..87d5c3127 --- /dev/null +++ b/src/GeomAPI/GeomAPI_ShapeHierarchy.cpp @@ -0,0 +1,261 @@ +// Copyright (C) 2014-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 +// + +#include "GeomAPI_ShapeHierarchy.h" + +#include "GeomAPI_ShapeIterator.h" + +#include +#include + +void GeomAPI_ShapeHierarchy::addObject(const GeomShapePtr& theObject) +{ + myObjects.push_back(theObject); +} + +void GeomAPI_ShapeHierarchy::addParent(const GeomShapePtr& theShape, + const GeomShapePtr& theParent) +{ + myParent[theShape] = theParent; + + MapShapeToIndex::iterator aFound = myParentIndices.find(theParent); + size_t anIndex = myParentIndices.size(); + if (aFound == myParentIndices.end()) { + myParentIndices[theParent] = anIndex; + mySubshapes.push_back(ShapeAndSubshapes(theParent, ListOfShape())); + } else + anIndex = aFound->second; + + mySubshapes[anIndex].second.push_back(theShape); +} + +GeomShapePtr GeomAPI_ShapeHierarchy::parent(const GeomShapePtr& theShape, + bool theMarkProcessed) +{ + MapShapeToParent::const_iterator aFound = myParent.find(theShape); + GeomShapePtr aParent; + if (aFound != myParent.end()) { + aParent = aFound->second; + if (theMarkProcessed) { + // mark the parent and all its subs as processed by Boolean algorithm + markProcessed(aParent); + const ListOfShape& aSubs = mySubshapes[myParentIndices[aParent]].second; + for (ListOfShape::const_iterator anIt = aSubs.begin(); anIt != aSubs.end(); ++anIt) + markProcessed(*anIt); + } + } + return aParent; +} + +void GeomAPI_ShapeHierarchy::markProcessed(const GeomShapePtr& theShape) +{ + myProcessedObjects.insert(theShape); +} + +void GeomAPI_ShapeHierarchy::markProcessed(const ListOfShape& theShapes) +{ + for (ListOfShape::const_iterator anIt = theShapes.begin(); anIt != theShapes.end(); ++anIt) + markProcessed(*anIt); +} + +void GeomAPI_ShapeHierarchy::objectsByType( + ListOfShape& theShapesByType, + ListOfShape& theOtherShapes, + const GeomAPI_Shape::ShapeType theMinType, + const GeomAPI_Shape::ShapeType theMaxType) const +{ + if (theMinType > theMaxType) + return objectsByType(theShapesByType, theOtherShapes, theMaxType, theMinType); + + // no need to select objects if whole range is specified + if (theMinType == GeomAPI_Shape::COMPOUND && theMaxType == GeomAPI_Shape::SHAPE) { + theShapesByType.insert(theShapesByType.end(), myObjects.begin(), myObjects.end()); + return; + } + + for (ListOfShape::const_iterator anIt = myObjects.begin(); anIt != myObjects.end(); ++anIt) { + GeomAPI_Shape::ShapeType aType = (*anIt)->shapeType(); + if (aType >= theMinType && aType <= theMaxType) + theShapesByType.push_back(*anIt); + else + theOtherShapes.push_back(*anIt); + } +} + + +void GeomAPI_ShapeHierarchy::splitCompound( + const GeomShapePtr& theCompShape, + ListOfShape& theUsed, + ListOfShape& theNotUsed) const +{ + theUsed.clear(); + theNotUsed.clear(); + + MapShapeToIndex::const_iterator aFoundIndex = myParentIndices.find(theCompShape); + if (aFoundIndex == myParentIndices.end()) + return; // no such shape + + theUsed = mySubshapes[aFoundIndex->second].second; + SetOfShape aSubsSet; + aSubsSet.insert(theUsed.begin(), theUsed.end()); + + for (GeomAPI_ShapeIterator anExp(theCompShape); anExp.more(); anExp.next()) { + GeomShapePtr aCurrent = anExp.current(); + if (aSubsSet.find(aCurrent) == aSubsSet.end()) + theNotUsed.push_back(aCurrent); + } +} + +bool GeomAPI_ShapeHierarchy::empty() const +{ + return myObjects.empty(); +} + +void GeomAPI_ShapeHierarchy::compoundsOfUnusedObjects( + ListOfShape& theDestination) const +{ + SetOfShape aUsedObjects = myProcessedObjects; + aUsedObjects.insert(myObjects.begin(), myObjects.end()); + + for (std::vector::const_iterator anIt = mySubshapes.begin(); + anIt != mySubshapes.end(); ++anIt) { + MapShapeToParent::const_iterator aParent = myParent.find(anIt->first); + if ((aParent == myParent.end() || !aParent->second) && + anIt->first->shapeType() == GeomAPI_Shape::COMPOUND) { + // this is a top-level compound + GeomShapePtr aCompound = collectUnusedSubs(anIt->first, aUsedObjects); + // add to destination non-empty compounds only + if (aCompound) + theDestination.push_back(aCompound); + } + } +} + +static void addSubShape(GeomShapePtr theTarget, GeomShapePtr theSub) +{ + if (!theTarget.get() || !theSub.get()) + return; + + TopoDS_Shape* aShape = theTarget->implPtr(); + const TopoDS_Shape& aShapeToAdd = theSub->impl(); + + static BRep_Builder aBuilder; + aBuilder.Add(*aShape, aShapeToAdd); +} + +GeomShapePtr GeomAPI_ShapeHierarchy::collectUnusedSubs( + GeomShapePtr theTopLevelCompound, + const SetOfShape& theUsed) const +{ + GeomShapePtr aResult = theTopLevelCompound->emptyCopied(); + bool isResultEmpty = true; + + for (GeomAPI_ShapeIterator aSub(theTopLevelCompound); aSub.more(); aSub.next()) { + GeomShapePtr aCurrent = aSub.current(); + if (theUsed.find(aCurrent) != theUsed.end()) + continue; // already used + + MapShapeToIndex::const_iterator aFoundIndex = myParentIndices.find(aCurrent); + if (aCurrent->shapeType() > GeomAPI_Shape::COMPOUND || + aFoundIndex == myParentIndices.end()) { + bool isAddShape = true; + // check compsolid is fully unused in the Boolean operation + if (aCurrent->shapeType() == GeomAPI_Shape::COMPSOLID) { + for (GeomAPI_ShapeIterator anIt(aCurrent); isAddShape && anIt.more(); anIt.next()) + isAddShape = theUsed.find(anIt.current()) == theUsed.end(); + } + + if (isAddShape) { // low-level shape, add it + addSubShape(aResult, aCurrent); + isResultEmpty = false; + } + } else { + GeomShapePtr aCompound = collectUnusedSubs(aCurrent, theUsed); + if (aCompound) { + addSubShape(aResult, aCompound); + isResultEmpty = false; + } + } + } + return isResultEmpty ? GeomShapePtr() : aResult; +} + + +GeomAPI_ShapeHierarchy::iterator GeomAPI_ShapeHierarchy::begin() +{ + return iterator(this); +} + +GeomAPI_ShapeHierarchy::iterator GeomAPI_ShapeHierarchy::end() +{ + return iterator(this, false); +} + +GeomAPI_ShapeHierarchy::iterator::iterator( + GeomAPI_ShapeHierarchy* theHierarchy, bool isBegin) + : myHierarchy(theHierarchy) +{ + if (isBegin) { + myObject = myHierarchy->myObjects.begin(); + skipAlreadyProcessed(); + } else + myObject = myHierarchy->myObjects.end(); +} + +void GeomAPI_ShapeHierarchy::iterator::skipAlreadyProcessed() +{ + while (myObject != myHierarchy->myObjects.end() && + myHierarchy->myProcessedObjects.find(*myObject) != myHierarchy->myProcessedObjects.end()) + ++myObject; +} + +bool GeomAPI_ShapeHierarchy::iterator::operator==(const iterator& theOther) const +{ + return myObject == theOther.myObject; +} + +bool GeomAPI_ShapeHierarchy::iterator::operator!=(const iterator& theOther) const +{ + return !operator==(theOther); +} + +GeomAPI_ShapeHierarchy::iterator& GeomAPI_ShapeHierarchy::iterator::operator++() +{ + ++myObject; + skipAlreadyProcessed(); + return *this; +} + +GeomAPI_ShapeHierarchy::iterator GeomAPI_ShapeHierarchy::iterator::operator++(int) +{ + iterator aCurrent; + aCurrent.myHierarchy = myHierarchy; + aCurrent.myObject = myObject; + + // increase iterator + operator++(); + + return aCurrent; +} + +GeomShapePtr GeomAPI_ShapeHierarchy::iterator::operator*() const +{ + myHierarchy->markProcessed(*myObject); + return *myObject; +} diff --git a/src/GeomAPI/GeomAPI_ShapeHierarchy.h b/src/GeomAPI/GeomAPI_ShapeHierarchy.h new file mode 100644 index 000000000..538b826af --- /dev/null +++ b/src/GeomAPI/GeomAPI_ShapeHierarchy.h @@ -0,0 +1,121 @@ +// Copyright (C) 2014-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 +// + +#ifndef GeomAPI_ShapeHierarchy_H_ +#define GeomAPI_ShapeHierarchy_H_ + +#include "GeomAPI.h" +#include "GeomAPI_Shape.h" + +#include +#include +#include + +/// \class GeomAPI_ShapeHierarchy +/// \ingroup Plugins +/// \brief Storage for the hierarchy of shapes and their parents (compounds or compsolids) +class GeomAPI_ShapeHierarchy +{ + typedef std::pair ShapeAndSubshapes; + typedef std::map MapShapeToParent; + typedef std::map MapShapeToIndex; + typedef std::set SetOfShape; + + ListOfShape myObjects; ///< list of objects of some operation + MapShapeToParent myParent; ///< refer a shape to compound/compsolid containing it + /// indices of compounds/compsolids to keep the order of parent shapes + /// corresponding to the order of objects + MapShapeToIndex myParentIndices; + /// list of shape and its subshapes stored according to the index of parent shape + std::vector mySubshapes; + + SetOfShape myProcessedObjects; + +public: + /// Add an object of the operation (low-level shape in the hierarchy) + GEOMAPI_EXPORT void addObject(const GeomShapePtr& theObject); + + /// Store link between shape and its parent. + /// Has to be called by high-level algorithm, because the parent compound/compsolid + /// is usually stored as a top-level result + GEOMAPI_EXPORT void addParent(const GeomShapePtr& theShape, const GeomShapePtr& theParent); + + /// Return parent shape for the given, or empty if it is a high-level shape. + /// By default, the parent and all its subshapes are marked as processed for further skip. + GEOMAPI_EXPORT GeomShapePtr parent(const GeomShapePtr& theShape, bool theMarkProcessed = true); + + /// Mark the shape as already processed + GEOMAPI_EXPORT void markProcessed(const GeomShapePtr& theShape); + /// Mark list ofshapes as already processed + GEOMAPI_EXPORT void markProcessed(const ListOfShape& theShapes); + + /// Split compound/compsolid shape for subshapes selected for operation and the others. + GEOMAPI_EXPORT void splitCompound(const GeomShapePtr& theCompShape, + ListOfShape& theUsed, + ListOfShape& theNotUsed) const; + + /// Generates the list of top-level compounds, which exclude the objects of operation. + GEOMAPI_EXPORT void compoundsOfUnusedObjects(ListOfShape& theDestination) const; + + /// Return \c true if there is no object in hierarchy + GEOMAPI_EXPORT bool empty() const; + + /// Return list of objects + const ListOfShape& objects() const { return myObjects; } + /// Separate objects of the given range of types and all other objects + GEOMAPI_EXPORT void objectsByType(ListOfShape& theShapesByType, ListOfShape& theOtherShapes, + const GeomAPI_Shape::ShapeType theMinType = GeomAPI_Shape::COMPOUND, + const GeomAPI_Shape::ShapeType theMaxType = GeomAPI_Shape::SHAPE) const; + +private: + GeomShapePtr collectUnusedSubs(const GeomShapePtr theTopLevelCompound, + const SetOfShape& theUsed) const; + +public: + class iterator : public std::iterator + { + public: + GEOMAPI_EXPORT iterator() {} + + protected: + iterator(GeomAPI_ShapeHierarchy* theHierarchy, bool isBegin = true); + + void skipAlreadyProcessed(); + + public: + GEOMAPI_EXPORT bool operator==(const iterator&) const; + GEOMAPI_EXPORT bool operator!=(const iterator&) const; + + GEOMAPI_EXPORT iterator& operator++(); + GEOMAPI_EXPORT iterator operator++(int); + + GEOMAPI_EXPORT GeomShapePtr operator*() const; + + private: + GeomAPI_ShapeHierarchy* myHierarchy; + ListOfShape::iterator myObject; + + friend class GeomAPI_ShapeHierarchy; + }; + + GEOMAPI_EXPORT iterator begin(); + GEOMAPI_EXPORT iterator end(); +}; + +#endif diff --git a/src/ModelAPI/ModelAPI_Tools.cpp b/src/ModelAPI/ModelAPI_Tools.cpp index 413f52c4c..f77e99951 100644 --- a/src/ModelAPI/ModelAPI_Tools.cpp +++ b/src/ModelAPI/ModelAPI_Tools.cpp @@ -38,6 +38,8 @@ #include #include +#include + #define RECURSE_TOP_LEVEL 50 //#define DEBUG_REMOVE_FEATURES @@ -762,6 +764,21 @@ std::set getParents(const FeaturePtr& theFeature) return aParents; } +void fillShapeHierarchy(const GeomShapePtr& theShape, + const ResultPtr& theContext, + GeomAPI_ShapeHierarchy& theHierarchy) +{ + ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(theContext); + if (aResCompSolidPtr.get()) { + std::shared_ptr aContextShape = aResCompSolidPtr->shape(); + if (aContextShape->shapeType() <= GeomAPI_Shape::COMPSOLID) { + theHierarchy.addParent(theShape, aContextShape); + fillShapeHierarchy(aContextShape, aResCompSolidPtr, theHierarchy); + } + } +} + + void removeResults(const std::list& theResults) { // collect all documents where the results must be removed diff --git a/src/ModelAPI/ModelAPI_Tools.h b/src/ModelAPI/ModelAPI_Tools.h index b0af5520b..57cdea0c9 100644 --- a/src/ModelAPI/ModelAPI_Tools.h +++ b/src/ModelAPI/ModelAPI_Tools.h @@ -30,6 +30,7 @@ class ModelAPI_ResultParameter; class ModelAPI_ResultBody; class GeomAPI_Shape; +class GeomAPI_ShapeHierarchy; #include #include @@ -206,6 +207,16 @@ MODELAPI_EXPORT std::pair getDefaultName( MODELAPI_EXPORT std::set > getParents(const std::shared_ptr& theFeature); +/*! Store shape and its parent shape to the hierarchy data structure + * \param[in] theShape the shape to store + * \param[in] theContext the result (parent shape) for the given shape + * \param[out] theHierarchy container for shape hierarchy + */ +MODELAPI_EXPORT void fillShapeHierarchy( + const std::shared_ptr& theShape, + const std::shared_ptr& theContext, + GeomAPI_ShapeHierarchy& theHierarchy); + /*! Creates a remove result features with the given results */ MODELAPI_EXPORT void removeResults(const std::list >& theResults); -- 2.39.2