From f6253bc3de6b7e40bcf023bc25ae718db4c28c96 Mon Sep 17 00:00:00 2001 From: jfa Date: Tue, 14 Sep 2021 21:03:05 +0300 Subject: [PATCH] [bos #24758] EDF 24017 - Problems with ExtrusionCut --- .../FeaturesPlugin_CompositeBoolean.cpp | 145 ++++++++++++++++-- .../FeaturesPlugin_CompositeBoolean.h | 15 +- 2 files changed, 146 insertions(+), 14 deletions(-) diff --git a/src/FeaturesPlugin/FeaturesPlugin_CompositeBoolean.cpp b/src/FeaturesPlugin/FeaturesPlugin_CompositeBoolean.cpp index f2a9b0a28..bf5293d83 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_CompositeBoolean.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_CompositeBoolean.cpp @@ -118,6 +118,87 @@ 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 +} + //================================================================================================= bool FeaturesPlugin_CompositeBoolean::makeBoolean(const ListOfShape& theTools, ListOfShape& theObjects, @@ -127,7 +208,26 @@ bool FeaturesPlugin_CompositeBoolean::makeBoolean(const ListOfShape& theTools, 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(); @@ -138,19 +238,25 @@ 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()) || myOperationType != BOOL_CUT) { + // Compsolid or a simple (one-level) compound + // Or not CUT + // TODO: correct FUSE for complex compounds? + 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); - if (aContextShape->shapeType() != GeomAPI_Shape::COMPOUND) - aCompoundsOnly = false; } } else { if(anObject->shapeType() == GeomAPI_Shape::EDGE || @@ -164,7 +270,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; } @@ -260,6 +367,18 @@ bool FeaturesPlugin_CompositeBoolean::makeBoolean(const ListOfShape& theTools, 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: { diff --git a/src/FeaturesPlugin/FeaturesPlugin_CompositeBoolean.h b/src/FeaturesPlugin/FeaturesPlugin_CompositeBoolean.h index 06c4d957f..bbcd26eb7 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_CompositeBoolean.h +++ b/src/FeaturesPlugin/FeaturesPlugin_CompositeBoolean.h @@ -25,6 +25,7 @@ #include #include #include +#include /// \class FeaturesPlugin_CompositeBoolean /// \ingroup Plugins @@ -72,7 +73,7 @@ protected: /// \param[in] theTools list of tools. /// \param[out] theObjects list of objects. /// \param[out] theMakeShapes list of according algos. - /// \return false in failed. + /// \return false if failed. bool makeBoolean(const ListOfShape& theTools, ListOfShape& theObjects, ListOfMakeShape& theMakeShapes); @@ -93,6 +94,18 @@ protected: const ListOfShape& theTools, const GeomShapePtr theResultShapesCompound); +private: + /// Makes cut operation recursively. Called from makeBoolean(). + /// \param[in] theCompound the shape to be cut. + /// \param[in] theTools list of tools. + /// \param[out] theMakeShapeList list of according algos. + /// \param[out] theResult result of cut. + /// \return false if failed or no cuts done (this is normal case). + bool cutRecursiveCompound (const GeomShapePtr theCompound, + const ListOfShape& theTools, + std::shared_ptr& theMakeShapeList, + GeomShapePtr& theResult); + protected: ModelAPI_Feature* myFeature; OperationType myOperationType; -- 2.39.2