X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FFeaturesPlugin%2FFeaturesPlugin_CompositeBoolean.cpp;h=d65e9f39888867da02726c1a3ec757688e05b5b0;hb=b928c27cd38f150c23d182df53c23ab266aa6b49;hp=6e3e8796b16493de7e94cbdb991ef587f26db77d;hpb=740d330c629fd842f00ea1dbd57749a95f0fa165;p=modules%2Fshaper.git diff --git a/src/FeaturesPlugin/FeaturesPlugin_CompositeBoolean.cpp b/src/FeaturesPlugin/FeaturesPlugin_CompositeBoolean.cpp index 6e3e8796b..d65e9f398 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_CompositeBoolean.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_CompositeBoolean.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2017 CEA/DEN, EDF R&D +// Copyright (C) 2014-2022 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 @@ -12,10 +12,9 @@ // // 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 +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // -// See http://www.salome-platform.org/ or -// email : webmaster.salome@opencascade.com +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // #include "FeaturesPlugin_CompositeBoolean.h" @@ -28,6 +27,7 @@ #include #include #include +#include #include @@ -118,6 +118,113 @@ void FeaturesPlugin_CompositeBoolean::executeCompositeBoolean() myFeature->removeResults(aResultIndex); } +//================================================================================================= +bool FeaturesPlugin_CompositeBoolean::cutRecursiveCompound(const GeomShapePtr theCompound, + const ListOfShape& theTools, + std::shared_ptr& theMakeShapeList, + GeomShapePtr& theResult) +{ + // I. If theCompound is among the selected objects, + // cut it by all tools and return result through theResult. + // It can be a SOLID, ?COMPOUND?, ?COMPSOLID? + AttributeSelectionListPtr anObjectsSelList = myFeature->selectionList(OBJECTS_ID()); + for (int anObjIndex = 0; anObjIndex < anObjectsSelList->size(); anObjIndex++) { + AttributeSelectionPtr anObjectAttr = anObjectsSelList->value(anObjIndex); + GeomShapePtr anObject = anObjectAttr->value(); + if (theCompound->isEqual(anObject)) { + // Cut theCompound itself + ListOfShape aListWithObject; + aListWithObject.push_back(anObject); + std::shared_ptr aBoolAlgo + (new GeomAlgoAPI_Boolean(aListWithObject, theTools, GeomAlgoAPI_Tools::BOOL_CUT)); + + // Checking that the algorithm worked properly. + if (!aBoolAlgo->isDone() || aBoolAlgo->shape()->isNull() || !aBoolAlgo->isValid()) { + myFeature->setError("Error: Boolean algorithm failed."); + return false; + } + + if (GeomAlgoAPI_ShapeTools::area(aBoolAlgo->shape()) > 1.e-27) { + theMakeShapeList->appendAlgo(aBoolAlgo); + theResult = aBoolAlgo->shape(); + return true; + } + return false; + } + } + + // II. Iterate the COMPOUND or COMPSOLID + // to find and cut Objects among its sub-shapes + if (theCompound->shapeType() == GeomAPI_Shape::COMPOUND || + theCompound->shapeType() == GeomAPI_Shape::COMPSOLID) { + + bool hasCut = false; + ListOfShape aShapesToAdd; + for (GeomAPI_ShapeIterator it (theCompound); it.more(); it.next()) { + GeomShapePtr aSubShape = it.current(); + GeomShapePtr aResult; + if (cutRecursiveCompound(aSubShape, theTools, theMakeShapeList, aResult)) { + hasCut = true; + aShapesToAdd.push_back(aResult); + } + else { + aShapesToAdd.push_back(aSubShape); + } + } + + if (hasCut) { + if (theCompound->shapeType() == GeomAPI_Shape::COMPSOLID) { + // Build COMPSOLID + std::shared_ptr aFillerAlgo + (new GeomAlgoAPI_PaveFiller(aShapesToAdd, true)); + if (!aFillerAlgo->isDone() || aFillerAlgo->shape()->isNull() || !aFillerAlgo->isValid()) { + myFeature->setError("Error: PaveFiller algorithm failed."); + return false; + } + theResult = aFillerAlgo->shape(); + theMakeShapeList->appendAlgo(aFillerAlgo); + } + else { + // Build COMPOUND + theResult = GeomAlgoAPI_CompoundBuilder::compound(aShapesToAdd); + std::shared_ptr aCompMkr (new GeomAlgoAPI_MakeShapeCustom); + aCompMkr->setResult(theResult); + aCompMkr->addModified(theCompound, theResult); // ?? + theMakeShapeList->appendAlgo(aCompMkr); + } + return true; + } + } + + return false; // no cuts +} + +//================================================================================================= +void FeaturesPlugin_CompositeBoolean::addSubShapes (const GeomShapePtr theCompound, + const ListOfShape& theSubShapesToAvoid, + ListOfShape& theSubShapesToAdd) { + for (GeomAPI_ShapeIterator aCompoundIt (theCompound); + aCompoundIt.more(); + aCompoundIt.next()) { + GeomShapePtr aCompoundSS = aCompoundIt.current(); + ListOfShape::const_iterator aUseIt = theSubShapesToAvoid.cbegin(); + for (; aUseIt != theSubShapesToAvoid.cend(); aUseIt++) { + if (aCompoundSS->isEqual(*aUseIt)) { + break; + } + } + if (aUseIt == theSubShapesToAvoid.cend()) { + if (aCompoundSS->shapeType() == GeomAPI_Shape::COMPSOLID || + aCompoundSS->shapeType() == GeomAPI_Shape::COMPOUND) { + addSubShapes(aCompoundSS, theSubShapesToAvoid, theSubShapesToAdd); + } + else { + theSubShapesToAdd.push_back(aCompoundSS); + } + } + } +} + //================================================================================================= bool FeaturesPlugin_CompositeBoolean::makeBoolean(const ListOfShape& theTools, ListOfShape& theObjects, @@ -126,7 +233,27 @@ bool FeaturesPlugin_CompositeBoolean::makeBoolean(const ListOfShape& theTools, // Getting objects. ListOfShape anObjects, anEdgesAndFaces, aCompSolids; std::map aCompSolidsObjects; + bool aCompoundsOnly = true;// if there are only compounds, do not use filler restoring compsolids + AttributeSelectionListPtr anObjectsSelList = myFeature->selectionList(OBJECTS_ID()); + + // collect recursive (complex) compounds, if any + ListOfShape aCompounds; // recursive compounds + GeomAPI_DataMapOfShapeShape aCompoundsMap; // recursive compounds map + for(int anObjectsIndex = 0; anObjectsIndex < anObjectsSelList->size(); anObjectsIndex++) { + AttributeSelectionPtr anObjectAttr = anObjectsSelList->value(anObjectsIndex); + ResultPtr aContext = anObjectAttr->context(); + ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext); + if (aResCompSolidPtr.get()) { + // Root body owner (true) + ResultBodyPtr aResRootPtr = ModelAPI_Tools::bodyOwner(aContext, true); + if (!aResRootPtr->isSame(aResCompSolidPtr)) { + aCompoundsMap.bind(aResRootPtr->shape(), aResRootPtr->shape()); + aCompounds.push_back(aResRootPtr->shape()); + } + } + } + for(int anObjectsIndex = 0; anObjectsIndex < anObjectsSelList->size(); anObjectsIndex++) { AttributeSelectionPtr anObjectAttr = anObjectsSelList->value(anObjectsIndex); GeomShapePtr anObject = anObjectAttr->value(); @@ -137,17 +264,23 @@ bool FeaturesPlugin_CompositeBoolean::makeBoolean(const ListOfShape& theTools, ResultPtr aContext = anObjectAttr->context(); ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext); if(aResCompSolidPtr.get()) { - GeomShapePtr aContextShape = aResCompSolidPtr->shape(); - std::map::iterator anIt = aCompSolidsObjects.begin(); - for(; anIt != aCompSolidsObjects.end(); anIt++) { - if(anIt->first->isEqual(aContextShape)) { - aCompSolidsObjects[anIt->first].push_back(anObject); - break; + ResultBodyPtr aResRootPtr = ModelAPI_Tools::bodyOwner(aContext, true); + if (!aCompoundsMap.isBound(aResRootPtr->shape())) { + // Compsolid or a simple (one-level) compound + GeomShapePtr aContextShape = aResCompSolidPtr->shape(); + std::map::iterator anIt = aCompSolidsObjects.begin(); + for(; anIt != aCompSolidsObjects.end(); anIt++) { + if(anIt->first->isEqual(aContextShape)) { + aCompSolidsObjects[anIt->first].push_back(anObject); + break; + } + } + if(anIt == aCompSolidsObjects.end()) { + aCompSolidsObjects[aContextShape].push_back(anObject); + aCompSolids.push_back(aContextShape); + if (aContextShape->shapeType() != GeomAPI_Shape::COMPOUND) + aCompoundsOnly = false; } - } - if(anIt == aCompSolidsObjects.end()) { - aCompSolidsObjects[aContextShape].push_back(anObject); - aCompSolids.push_back(aContextShape); } } else { if(anObject->shapeType() == GeomAPI_Shape::EDGE || @@ -161,7 +294,8 @@ bool FeaturesPlugin_CompositeBoolean::makeBoolean(const ListOfShape& theTools, switch(myOperationType) { case BOOL_CUT: { - if((anObjects.empty() && aCompSolidsObjects.empty()) || theTools.empty()) { + if((anObjects.empty() && aCompSolidsObjects.empty() + && aCompoundsMap.size() < 1) || theTools.empty()) { myFeature->setError("Error: Not enough objects for boolean operation."); return false; } @@ -174,7 +308,7 @@ bool FeaturesPlugin_CompositeBoolean::makeBoolean(const ListOfShape& theTools, aListWithObject.push_back(anObject); std::shared_ptr aBoolAlgo(new GeomAlgoAPI_Boolean(aListWithObject, theTools, - GeomAlgoAPI_Boolean::BOOL_CUT)); + GeomAlgoAPI_Tools::BOOL_CUT)); // Checking that the algorithm worked properly. if(!aBoolAlgo->isDone() || aBoolAlgo->shape()->isNull() || !aBoolAlgo->isValid()) { @@ -182,7 +316,7 @@ bool FeaturesPlugin_CompositeBoolean::makeBoolean(const ListOfShape& theTools, return false; } - if(GeomAlgoAPI_ShapeTools::volume(aBoolAlgo->shape()) > 1.e-27) { + if(GeomAlgoAPI_ShapeTools::area(aBoolAlgo->shape()) > 1.e-27) { theObjects.push_back(anObject); theMakeShapes.push_back(aBoolAlgo); } @@ -214,7 +348,7 @@ bool FeaturesPlugin_CompositeBoolean::makeBoolean(const ListOfShape& theTools, std::shared_ptr aBoolAlgo(new GeomAlgoAPI_Boolean(aUsedShapes, theTools, - GeomAlgoAPI_Boolean::BOOL_CUT)); + GeomAlgoAPI_Tools::BOOL_CUT)); // Checking that the algorithm worked properly. if(!aBoolAlgo->isDone() || aBoolAlgo->shape()->isNull() || !aBoolAlgo->isValid()) { @@ -226,21 +360,49 @@ bool FeaturesPlugin_CompositeBoolean::makeBoolean(const ListOfShape& theTools, aMakeShapeList->appendAlgo(aBoolAlgo); // Add result to not used solids from compsolid. - aShapesToAdd.push_back(aBoolAlgo->shape()); - std::shared_ptr aFillerAlgo( - new GeomAlgoAPI_PaveFiller(aShapesToAdd, true)); - if(!aFillerAlgo->isDone() || aFillerAlgo->shape()->isNull() || !aFillerAlgo->isValid()) { - myFeature->setError("Error: PaveFiller algorithm failed."); - return false; + GeomShapePtr aBoolRes = aBoolAlgo->shape(); + if (!aShapesToAdd.empty()) { + aShapesToAdd.push_back(aBoolRes); + if (aCompoundsOnly) + { // 23885: if there are no compsolids in input, do not use filler to make compsolids + aBoolRes = GeomAlgoAPI_CompoundBuilder::compound(aShapesToAdd); + std::shared_ptr aCompMkr(new GeomAlgoAPI_MakeShapeCustom); + aCompMkr->setResult(aBoolRes); + for(ListOfShape::iterator aCS = aCompSolids.begin(); aCS != aCompSolids.end(); aCS++) + aCompMkr->addModified(*aCS, aBoolRes); + aMakeShapeList->appendAlgo(aCompMkr); + } + else + { + std::shared_ptr aFillerAlgo( + new GeomAlgoAPI_PaveFiller(aShapesToAdd, true)); + if (!aFillerAlgo->isDone() || aFillerAlgo->shape()->isNull() || !aFillerAlgo->isValid()) + { + myFeature->setError("Error: PaveFiller algorithm failed."); + return false; + } + aBoolRes = aFillerAlgo->shape(); + aMakeShapeList->appendAlgo(aFillerAlgo); + } } - aMakeShapeList->appendAlgo(aFillerAlgo); - - if(GeomAlgoAPI_ShapeTools::volume(aFillerAlgo->shape()) > 1.e-27) { + if(GeomAlgoAPI_ShapeTools::area(aBoolRes) > 1.e-27) { theObjects.push_back(aCompSolid); theMakeShapes.push_back(aMakeShapeList); } } + + // Complex (recursive) compounds handling + for(ListOfShape::const_iterator anIt = aCompounds.cbegin(); + anIt != aCompounds.cend(); ++anIt) { + GeomShapePtr aCompound = (*anIt); + GeomShapePtr aRes; + std::shared_ptr aMakeShapeList (new GeomAlgoAPI_MakeShapeList()); + cutRecursiveCompound(aCompound, theTools, aMakeShapeList, aRes); + theObjects.push_back(aCompound); + theMakeShapes.push_back(aMakeShapeList); + } + break; } case BOOL_FUSE: { @@ -248,6 +410,7 @@ bool FeaturesPlugin_CompositeBoolean::makeBoolean(const ListOfShape& theTools, theObjects.insert(theObjects.end(), anEdgesAndFaces.begin(), anEdgesAndFaces.end()); theObjects.insert(theObjects.end(), anObjects.begin(), anObjects.end()); theObjects.insert(theObjects.end(), aCompSolids.begin(), aCompSolids.end()); + theObjects.insert(theObjects.end(), aCompounds.begin(), aCompounds.end()); // Filter edges and faces in tools. ListOfShape aTools; @@ -260,7 +423,7 @@ bool FeaturesPlugin_CompositeBoolean::makeBoolean(const ListOfShape& theTools, } } - if((anObjects.size() + aTools.size() + + if((anObjects.size() + aTools.size() + aCompounds.size() + aCompSolidsObjects.size() + anEdgesAndFaces.size()) < 2) { myFeature->setError("Error: Not enough objects for boolean operation."); return false; @@ -271,31 +434,23 @@ bool FeaturesPlugin_CompositeBoolean::makeBoolean(const ListOfShape& theTools, aSolidsToFuse.insert(aSolidsToFuse.end(), anObjects.begin(), anObjects.end()); aSolidsToFuse.insert(aSolidsToFuse.end(), aTools.begin(), aTools.end()); - // Collecting solids from compsolids which will not be + // Collecting solids and compsolids from compounds which will not be // modified in boolean operation and will be added to result. ListOfShape aShapesToAdd; - for(std::map::iterator anIt = aCompSolidsObjects.begin(); - anIt != aCompSolidsObjects.end(); anIt++) { + for (ListOfShape::iterator anIt = aCompounds.begin(); + anIt != aCompounds.end(); anIt++) { + GeomShapePtr aCompound = (*anIt); + addSubShapes(aCompound, anObjects, aShapesToAdd); + } + + // Collecting solids from compsolids which will not be + // modified in boolean operation and will be added to result. + for (std::map::iterator anIt = aCompSolidsObjects.begin(); + anIt != aCompSolidsObjects.end(); anIt++) { GeomShapePtr aCompSolid = anIt->first; ListOfShape& aUsedShapes = anIt->second; - aSolidsToFuse.insert(aSolidsToFuse.end(), aUsedShapes.begin(), aUsedShapes.end()); - - // Collect solids from compsolid which will not be modified in boolean operation. - for (GeomAPI_ShapeIterator aCompSolidIt(aCompSolid); - aCompSolidIt.more(); - aCompSolidIt.next()) - { - GeomShapePtr aSolidInCompSolid = aCompSolidIt.current(); - ListOfShape::iterator anIt = aUsedShapes.begin(); - for(; anIt != aUsedShapes.end(); anIt++) { - if(aSolidInCompSolid->isEqual(*anIt)) { - break; - } - } - if(anIt == aUsedShapes.end()) { - aShapesToAdd.push_back(aSolidInCompSolid); - } - } + aSolidsToFuse.insert(aSolidsToFuse.end(), aUsedShapes.begin(), aUsedShapes.end()); //??? + addSubShapes(aCompSolid, aUsedShapes, aShapesToAdd); } // Cut edges and faces(if we have any) with solids. @@ -308,7 +463,7 @@ bool FeaturesPlugin_CompositeBoolean::makeBoolean(const ListOfShape& theTools, if(!anEdgesAndFaces.empty() && !aCutTools.empty()) { std::shared_ptr aCutAlgo(new GeomAlgoAPI_Boolean(anEdgesAndFaces, aCutTools, - GeomAlgoAPI_Boolean::BOOL_CUT)); + GeomAlgoAPI_Tools::BOOL_CUT)); if(aCutAlgo->isDone() && !aCutAlgo->shape()->isNull() && aCutAlgo->isValid()) { anEdgesAndFaces.clear(); anEdgesAndFaces.push_back(aCutAlgo->shape()); @@ -320,8 +475,8 @@ bool FeaturesPlugin_CompositeBoolean::makeBoolean(const ListOfShape& theTools, if(!aShapesToAdd.empty()) { std::shared_ptr aCutAlgo(new GeomAlgoAPI_Boolean(aSolidsToFuse, aShapesToAdd, - GeomAlgoAPI_Boolean::BOOL_CUT)); - if(aCutAlgo->isDone() && GeomAlgoAPI_ShapeTools::volume(aCutAlgo->shape()) > 1.e-27) { + GeomAlgoAPI_Tools::BOOL_CUT)); + if(aCutAlgo->isDone() && GeomAlgoAPI_ShapeTools::area(aCutAlgo->shape()) > 1.e-27) { aSolidsToFuse.clear(); aSolidsToFuse.push_back(aCutAlgo->shape()); aMakeShapeList->appendAlgo(aCutAlgo); @@ -340,7 +495,7 @@ bool FeaturesPlugin_CompositeBoolean::makeBoolean(const ListOfShape& theTools, std::shared_ptr aFuseAlgo(new GeomAlgoAPI_Boolean(anObjects, aTools, - GeomAlgoAPI_Boolean::BOOL_FUSE)); + GeomAlgoAPI_Tools::BOOL_FUSE)); // Checking that the algorithm worked properly. if(!aFuseAlgo->isDone() || aFuseAlgo->shape()->isNull() || !aFuseAlgo->isValid()) { @@ -372,6 +527,8 @@ bool FeaturesPlugin_CompositeBoolean::makeBoolean(const ListOfShape& theTools, theMakeShapes.push_back(aMakeShapeList); break; } + default: // [to avoid compilation warnings] + break; } return true;