X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FFeaturesPlugin%2FFeaturesPlugin_BooleanCut.cpp;h=9a9750d8273c964d26769b81fbebd9e8515693e5;hb=fc72d43b677baa05ae7fd317346fd8b723b799ed;hp=04b9020ba0858e837393e6d29b78b4487b60a4ad;hpb=6e421e939851e0de46554ae45a3ca0e1f67cd91d;p=modules%2Fshaper.git diff --git a/src/FeaturesPlugin/FeaturesPlugin_BooleanCut.cpp b/src/FeaturesPlugin/FeaturesPlugin_BooleanCut.cpp index 04b9020ba..9a9750d82 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_BooleanCut.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_BooleanCut.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2019 CEA/DEN, EDF R&D +// Copyright (C) 2014-2023 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 @@ -19,9 +19,9 @@ #include "FeaturesPlugin_BooleanCut.h" -#include "FeaturesPlugin_Tools.h" - #include +#include +#include #include #include @@ -35,6 +35,26 @@ #include #include + +static const ListOfShape ExplodeCompounds(const ListOfShape &aList) +{ + ListOfShape subShapes; + for (auto shp = aList.cbegin(); shp != aList.cend(); ++shp) + { + if ((*shp).get() && (*shp)->isCompound()) { + // Use all sub shapes of the compound + for (GeomAPI_ShapeIterator anExp(*shp); anExp.more(); anExp.next()) { + GeomShapePtr aCurrent = anExp.current(); + subShapes.push_back(aCurrent); + } + } + else + subShapes.push_back(*shp); + } + + return subShapes; +} + //================================================================================================== FeaturesPlugin_BooleanCut::FeaturesPlugin_BooleanCut() : FeaturesPlugin_Boolean(FeaturesPlugin_Boolean::BOOL_CUT) @@ -42,286 +62,99 @@ FeaturesPlugin_BooleanCut::FeaturesPlugin_BooleanCut() } //================================================================================================== -void FeaturesPlugin_BooleanCut::execute() +void FeaturesPlugin_BooleanCut::initAttributes() { - ListOfShape anObjects, aTools; - std::map, ListOfShape> aCompSolidsObjects; - std::map, ListOfShape> aCompoundObjects; - - // Getting objects. - AttributeSelectionListPtr anObjectsSelList = selectionList(OBJECT_LIST_ID()); - for(int anObjectsIndex = 0; anObjectsIndex < anObjectsSelList->size(); anObjectsIndex++) { - AttributeSelectionPtr anObjectAttr = anObjectsSelList->value(anObjectsIndex); - std::shared_ptr anObject = anObjectAttr->value(); - if(!anObject.get()) { - return; - } - ResultPtr aContext = anObjectAttr->context(); - ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext); - if (aResCompSolidPtr.get()) - { - std::shared_ptr aContextShape = aResCompSolidPtr->shape(); - GeomAPI_Shape::ShapeType aShapeType = aResCompSolidPtr->shape()->shapeType(); - std::map, ListOfShape>& aMap = - aShapeType == GeomAPI_Shape::COMPSOLID ? aCompSolidsObjects : aCompoundObjects; - - std::map, ListOfShape>::iterator - anIt = aMap.begin(); - for (; anIt != aMap.end(); anIt++) { - if (anIt->first->isEqual(aContextShape)) { - aMap[anIt->first].push_back(anObject); - break; - } - } - if (anIt == aMap.end()) { - aMap[aContextShape].push_back(anObject); - } + FeaturesPlugin_Boolean::initAttributes(); + initVersion(BOP_VERSION_9_4(), selectionList(OBJECT_LIST_ID()), selectionList(TOOL_LIST_ID())); +} - } else { - anObjects.push_back(anObject); - } - } +//================================================================================================== +void FeaturesPlugin_BooleanCut::execute() +{ + GeomAPI_ShapeHierarchy anObjects, aTools; + ListOfShape aPlanes; - // Getting tools. - AttributeSelectionListPtr aToolsSelList = selectionList(TOOL_LIST_ID()); - for(int aToolsIndex = 0; aToolsIndex < aToolsSelList->size(); aToolsIndex++) { - AttributeSelectionPtr aToolAttr = aToolsSelList->value(aToolsIndex); - GeomShapePtr aTool = aToolAttr->value(); - if(!aTool.get()) { - return; - } - aTools.push_back(aTool); - } + // Getting objects and tools + if (!processAttribute(OBJECT_LIST_ID(), anObjects, aPlanes) || + !processAttribute(TOOL_LIST_ID(), aTools, aPlanes)) + return; int aResultIndex = 0; - if((anObjects.empty() && aCompSolidsObjects.empty() && aCompoundObjects.empty()) - || aTools.empty()) { + if(anObjects.empty() || aTools.empty()) { std::string aFeatureError = "Error: Not enough objects for boolean operation."; setError(aFeatureError); return; } - std::vector aResultBaseAlgoList; + std::vector aResultBaseAlgoList; ListOfShape aResultShapesList; std::string anError; - // For solids cut each object with all tools. - for(ListOfShape::iterator anObjectsIt = anObjects.begin(); - anObjectsIt != anObjects.end(); - ++anObjectsIt) { - std::shared_ptr anObject = *anObjectsIt; - std::shared_ptr aMakeShapeList(new GeomAlgoAPI_MakeShapeList()); - std::shared_ptr aCutAlgo( - new GeomAlgoAPI_Boolean(anObject, - aTools, - GeomAlgoAPI_Boolean::BOOL_CUT)); - GeomShapePtr aResShape = aCutAlgo->shape(); - - // Checking that the algorithm worked properly. - if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aCutAlgo, getKind(), anError)) { - setError(anError); - return; - } - - aMakeShapeList->appendAlgo(aCutAlgo); - - GeomAPI_ShapeIterator aShapeIt(aResShape); - 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, - anObjectList, - aTools, - aMakeShapeList, - aResShape); - setResult(aResultBody, aResultIndex); - aResultIndex++; - - FeaturesPlugin_Tools::ResultBaseAlgo aRBA; - aRBA.resultBody = aResultBody; - aRBA.baseShape = anObject; - aRBA.makeShape = aMakeShapeList; - aResultBaseAlgoList.push_back(aRBA); - aResultShapesList.push_back(aResShape); - } - } - - // Compsolids handling - for (std::map, ListOfShape>::iterator - anIt = aCompSolidsObjects.begin(); - anIt != aCompSolidsObjects.end(); - ++anIt) - { - std::shared_ptr aCompSolid = anIt->first; - ListOfShape& aUsedInOperationSolids = anIt->second; - - // Collecting solids from compsolids which will not be modified in boolean operation. - ListOfShape aNotUsedSolids; - for(GeomAPI_ShapeExplorer anExp(aCompSolid, GeomAPI_Shape::SOLID); - anExp.more(); - anExp.next()) - { - std::shared_ptr aSolidInCompSolid = anExp.current(); - ListOfShape::iterator aUsedIt = aUsedInOperationSolids.begin(); - for (; aUsedIt != aUsedInOperationSolids.end(); aUsedIt++) { - if (aSolidInCompSolid->isEqual(*aUsedIt)) { - break; - } - } - if (aUsedIt == aUsedInOperationSolids.end()) { - aNotUsedSolids.push_back(aSolidInCompSolid); - } - } - - std::shared_ptr aMakeShapeList(new GeomAlgoAPI_MakeShapeList()); - std::shared_ptr aCutAlgo( - new GeomAlgoAPI_Boolean(aUsedInOperationSolids, - aTools, - GeomAlgoAPI_Boolean::BOOL_CUT)); - - // Checking that the algorithm worked properly. - if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aCutAlgo, getKind(), anError)) { - setError(anError); - return; - } + std::shared_ptr aMakeShapeList(new GeomAlgoAPI_MakeShapeList()); - aMakeShapeList->appendAlgo(aCutAlgo); - GeomShapePtr aResultShape = aCutAlgo->shape(); - - // Add result to not used solids from compsolid. - if(!aNotUsedSolids.empty()) { - ListOfShape aShapesToAdd = aNotUsedSolids; - aShapesToAdd.push_back(aCutAlgo->shape()); - std::shared_ptr aFillerAlgo( - new GeomAlgoAPI_PaveFiller(aShapesToAdd, true)); - if(!aFillerAlgo->isDone()) { - std::string aFeatureError = "Error: PaveFiller algorithm failed."; - setError(aFeatureError); - return; - } - - aMakeShapeList->appendAlgo(aFillerAlgo); - aResultShape = aFillerAlgo->shape(); - } - - GeomAPI_ShapeIterator aShapeIt(aResultShape); - if (aShapeIt.more() || aResultShape->shapeType() == GeomAPI_Shape::VERTEX) - { - std::shared_ptr aResultBody = - document()->createBody(data(), aResultIndex); - - ListOfShape anObjectList; - anObjectList.push_back(aCompSolid); - FeaturesPlugin_Tools::loadModifiedShapes(aResultBody, - anObjectList, - aTools, - aMakeShapeList, - aResultShape); - setResult(aResultBody, aResultIndex); - aResultIndex++; - - FeaturesPlugin_Tools::ResultBaseAlgo aRBA; - aRBA.resultBody = aResultBody; - aRBA.baseShape = aCompSolid; - aRBA.makeShape = aMakeShapeList; - aResultBaseAlgoList.push_back(aRBA); - aResultShapesList.push_back(aResultShape); - } + GeomShapePtr aResultCompound; + if (data()->version() == BOP_VERSION_9_4()) { + // merge hierarchies of compounds containing objects and tools + aResultCompound = + keepUnusedSubsOfCompound(GeomShapePtr(), anObjects, aTools, aMakeShapeList); } - // Compounds handling - for (std::map, ListOfShape>::iterator - anIt = aCompoundObjects.begin(); - anIt != aCompoundObjects.end(); - ++anIt) - { - std::shared_ptr aCompound = anIt->first; - ListOfShape& aUsedInOperationShapes = anIt->second; - - // Collecting shapes from compound which will not be modified in boolean operation. - ListOfShape aNotUsedShapes; - for (GeomAPI_ShapeIterator aCompIt(aCompound); - aCompIt.more(); - aCompIt.next()) - { - std::shared_ptr aShapeInCompound = aCompIt.current(); - ListOfShape::iterator aUsedIt = aUsedInOperationShapes.begin(); - for (; aUsedIt != aUsedInOperationShapes.end(); aUsedIt++) { - if (aShapeInCompound->isEqual(*aUsedIt)) { - break; - } - } - if (aUsedIt == aUsedInOperationShapes.end()) { - aNotUsedShapes.push_back(aShapeInCompound); - } - } - - std::shared_ptr aMakeShapeList(new GeomAlgoAPI_MakeShapeList()); - std::shared_ptr aCutAlgo( - new GeomAlgoAPI_Boolean(aUsedInOperationShapes, - aTools, - GeomAlgoAPI_Boolean::BOOL_CUT)); - - // Checking that the algorithm worked properly. - if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aCutAlgo, getKind(), anError)) { - setError(anError); - return; - } + // Getting fuzzy parameter. + // Used as additional tolerance to eliminate tiny results. + // Using -1 as fuzzy value in the GeomAlgoAPI means to ignore it during the boolean operation! + bool aUseFuzzy = boolean(USE_FUZZY_ID())->value(); + double aFuzzy = (aUseFuzzy ? real(FUZZY_PARAM_ID())->value() : -1); - aMakeShapeList->appendAlgo(aCutAlgo); - GeomShapePtr aResultShape = aCutAlgo->shape(); + // When selecting a compound tool object, use its exploded subshapes as tool object instead. + const ListOfShape aToolList = ExplodeCompounds(aTools.objects()); - // Add result to not used shape from compound. - if (!aNotUsedShapes.empty()) { - ListOfShape aShapesForResult = aNotUsedShapes; - if (aResultShape->shapeType() == GeomAPI_Shape::COMPOUND) { - for (GeomAPI_ShapeIterator aResultIt(aResultShape); aResultIt.more(); aResultIt.next()) { - aShapesForResult.push_back(aResultIt.current()); - } - } else { - aShapesForResult.push_back(aResultShape); + // For solids cut each object with all tools. + bool isOk = true; + for (GeomAPI_ShapeHierarchy::iterator anObjectsIt = anObjects.begin(); + anObjectsIt != anObjects.end() && isOk; + ++anObjectsIt) { + GeomShapePtr anObject = *anObjectsIt; + 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, aToolList, + aFuzzy, + aResultIndex, aResultBaseAlgoList, aResultShapesList, + aResultCompound); } - - if (aShapesForResult.size() == 1) { - aResultShape = aShapesForResult.front(); - } else { - aResultShape = GeomAlgoAPI_CompoundBuilder::compound(aShapesForResult); + else if (aShapeType == GeomAPI_Shape::COMPSOLID) { + // Compsolid handling + isOk = processCompsolid(GeomAlgoAPI_Tools::BOOL_CUT, + anObjects, aParent, aToolList, ListOfShape(), + aFuzzy, + aResultIndex, aResultBaseAlgoList, aResultShapesList, + aResultCompound); } - } - - GeomAPI_ShapeIterator aShapeIt(aResultShape); - if (aShapeIt.more() || aResultShape->shapeType() == GeomAPI_Shape::VERTEX) { - std::shared_ptr aResultBody = - document()->createBody(data(), aResultIndex); - - ListOfShape anObjectList; - anObjectList.push_back(aCompound); - FeaturesPlugin_Tools::loadModifiedShapes(aResultBody, - anObjectList, - aTools, - aMakeShapeList, - aResultShape); - setResult(aResultBody, aResultIndex); - aResultIndex++; - - FeaturesPlugin_Tools::ResultBaseAlgo aRBA; - aRBA.resultBody = aResultBody; - aRBA.baseShape = aCompound; - aRBA.makeShape = aMakeShapeList; - aResultBaseAlgoList.push_back(aRBA); - aResultShapesList.push_back(aResultShape); + } else { + // process object as is + isOk = processObject(GeomAlgoAPI_Tools::BOOL_CUT, + anObject, aToolList, aPlanes, + aFuzzy, + aResultIndex, aResultBaseAlgoList, aResultShapesList, + aResultCompound); } } + storeResult(anObjects.objects(), aToolList, aResultCompound, aResultIndex, + aMakeShapeList, aResultBaseAlgoList); + // Store deleted shapes after all results has been proceeded. This is to avoid issue when in one // result shape has been deleted, but in another it was modified or stayed. - GeomShapePtr aResultShapesCompound = GeomAlgoAPI_CompoundBuilder::compound(aResultShapesList); - FeaturesPlugin_Tools::loadDeletedShapes(aResultBaseAlgoList, aTools, aResultShapesCompound); + if (!aResultCompound) + aResultCompound = GeomAlgoAPI_CompoundBuilder::compound(aResultShapesList); + ModelAPI_Tools::loadDeletedShapes(aResultBaseAlgoList, + aToolList, + aResultCompound); // remove the rest results if there were produced in the previous pass removeResults(aResultIndex);