X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FFeaturesPlugin%2FFeaturesPlugin_Boolean.cpp;h=7f9ce37ac77b4a27d79d5d42dd71133c9edc666f;hb=05e6e5cea2a02ae15a2d254a355b08fad114a970;hp=7360f443cda6aeaedf3b9b533bdff020195fb76c;hpb=fb4f0172451724da7c67e5221e93f9fdc972e741;p=modules%2Fshaper.git diff --git a/src/FeaturesPlugin/FeaturesPlugin_Boolean.cpp b/src/FeaturesPlugin/FeaturesPlugin_Boolean.cpp index 7360f443c..7f9ce37ac 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_Boolean.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_Boolean.cpp @@ -1,8 +1,21 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D --> - -// File: FeaturesPlugin_Boolean.cpp -// Created: 02 Sept 2014 -// Author: Vitaly SMETANNIKOV +// Copyright (C) 2014-2019 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 "FeaturesPlugin_Boolean.h" @@ -17,423 +30,529 @@ #include #include +#include +#include #include +#include #include #include +#include +#include #include +#include #include +#include //================================================================================================= -FeaturesPlugin_Boolean::FeaturesPlugin_Boolean() +FeaturesPlugin_Boolean::FeaturesPlugin_Boolean(const OperationType theOperationType) +: myOperationType(theOperationType) { } //================================================================================================= void FeaturesPlugin_Boolean::initAttributes() { - data()->addAttribute(FeaturesPlugin_Boolean::TYPE_ID(), ModelAPI_AttributeInteger::typeId()); - - AttributeSelectionListPtr aSelection = + AttributeSelectionListPtr aSelection = std::dynamic_pointer_cast(data()->addAttribute( FeaturesPlugin_Boolean::OBJECT_LIST_ID(), ModelAPI_AttributeSelectionList::typeId())); - // extrusion works with faces always - aSelection->setSelectionType("SOLID"); aSelection = std::dynamic_pointer_cast(data()->addAttribute( FeaturesPlugin_Boolean::TOOL_LIST_ID(), ModelAPI_AttributeSelectionList::typeId())); - // extrusion works with faces always - aSelection->setSelectionType("SOLID"); ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), OBJECT_LIST_ID()); ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), TOOL_LIST_ID()); } //================================================================================================= -std::shared_ptr FeaturesPlugin_Boolean::getShape(const std::string& theAttrName) +FeaturesPlugin_Boolean::OperationType FeaturesPlugin_Boolean::operationType() { - std::shared_ptr aObjRef = std::dynamic_pointer_cast< - ModelAPI_AttributeReference>(data()->attribute(theAttrName)); - if (aObjRef) { - std::shared_ptr aConstr = std::dynamic_pointer_cast< - ModelAPI_ResultBody>(aObjRef->value()); - if (aConstr) - return aConstr->shape(); - } - return std::shared_ptr(); + return myOperationType; } //================================================================================================= -void FeaturesPlugin_Boolean::execute() +void FeaturesPlugin_Boolean::parentForShape(const GeomShapePtr& theShape, + const ResultPtr& theContext, + ObjectHierarchy& theShapesHierarchy) { - // Getting operation type. - std::shared_ptr aTypeAttr = std::dynamic_pointer_cast< - ModelAPI_AttributeInteger>(data()->attribute(FeaturesPlugin_Boolean::TYPE_ID())); - if (!aTypeAttr) - return; - GeomAlgoAPI_Boolean::OperationType aType = (GeomAlgoAPI_Boolean::OperationType)aTypeAttr->value(); - - ListOfShape anObjects, aTools, anEdgesAndFaces; - std::map, ListOfShape> aCompSolidsObjects; + 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); + } + } +} - // Getting objects. - AttributeSelectionListPtr anObjectsSelList = selectionList(FeaturesPlugin_Boolean::OBJECT_LIST_ID()); - for(int anObjectsIndex = 0; anObjectsIndex < anObjectsSelList->size(); anObjectsIndex++) { +bool FeaturesPlugin_Boolean::processAttribute(const std::string& theAttributeName, + ObjectHierarchy& theObjects, + ListOfShape& thePlanesList) +{ + AttributeSelectionListPtr anObjectsSelList = selectionList(theAttributeName); + for (int anObjectsIndex = 0; anObjectsIndex < anObjectsSelList->size(); anObjectsIndex++) { AttributeSelectionPtr anObjectAttr = anObjectsSelList->value(anObjectsIndex); - std::shared_ptr anObject = anObjectAttr->value(); - if(!anObject.get()) { - return; + GeomShapePtr anObject = anObjectAttr->value(); + if (!anObject.get()) { + // It could be a construction plane. + ResultPtr aContext = anObjectAttr->context(); + anObject = anObjectAttr->context()->shape(); + if (anObject.get()) { + thePlanesList.push_back(anObject); + continue; + } else + return false; } + + theObjects.AddObject(anObject); + ResultPtr aContext = anObjectAttr->context(); - ResultCompSolidPtr aResCompSolidPtr = ModelAPI_Tools::compSolidOwner(aContext); - if(aResCompSolidPtr.get()) { - std::shared_ptr aContextShape = aResCompSolidPtr->shape(); - std::map, ListOfShape>::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); - } - } else { - if(anObject->shapeType() == GeomAPI_Shape::EDGE || - anObject->shapeType() == GeomAPI_Shape::FACE) { - anEdgesAndFaces.push_back(anObject); - } else { - anObjects.push_back(anObject); - } - } + parentForShape(anObject, aContext, theObjects); + } + return true; +} + +//================================================================================================= +void FeaturesPlugin_Boolean::loadNamingDS(std::shared_ptr theResultBody, + const std::shared_ptr theBaseShape, + const ListOfShape& theTools, + const std::shared_ptr theResultShape, + const GeomMakeShapePtr& theMakeShape) +{ + //load result + if(theBaseShape->isEqual(theResultShape)) { + theResultBody->store(theResultShape, false); + return; } - // Getting tools. - AttributeSelectionListPtr aToolsSelList = selectionList(FeaturesPlugin_Boolean::TOOL_LIST_ID()); - for(int aToolsIndex = 0; aToolsIndex < aToolsSelList->size(); aToolsIndex++) { - AttributeSelectionPtr aToolAttr = aToolsSelList->value(aToolsIndex); - std::shared_ptr aTool = aToolAttr->value(); - if(!aTool.get()) { - return; - } - if(aTool->shapeType() == GeomAPI_Shape::EDGE || - aTool->shapeType() == GeomAPI_Shape::FACE) { - anEdgesAndFaces.push_back(aTool); - } else { - aTools.push_back(aTool); + theResultBody->storeModified(theBaseShape, theResultShape); + + theResultBody->loadModifiedShapes(theMakeShape, theBaseShape, GeomAPI_Shape::EDGE); + theResultBody->loadModifiedShapes(theMakeShape, theBaseShape, GeomAPI_Shape::FACE); + + theResultBody->loadDeletedShapes(theMakeShape, theBaseShape, GeomAPI_Shape::FACE); + + for (ListOfShape::const_iterator anIter = theTools.begin(); + anIter != theTools.end(); + ++anIter) + { + GeomAPI_Shape::ShapeType aShapeType = + (*anIter)->shapeType() <= GeomAPI_Shape::FACE ? GeomAPI_Shape::FACE + : GeomAPI_Shape::EDGE; + theResultBody->loadModifiedShapes(theMakeShape, *anIter, aShapeType); + + theResultBody->loadDeletedShapes(theMakeShape, *anIter, GeomAPI_Shape::FACE); + } +} + +//================================================================================================= +bool FeaturesPlugin_Boolean::processObject( + const GeomAlgoAPI_Tools::BOPType theBooleanType, + const GeomShapePtr& theObject, + const ListOfShape& theTools, + const ListOfShape& thePlanes, + int& theResultIndex, + std::vector& theResultBaseAlgoList, + ListOfShape& theResultShapesList) +{ + ListOfShape aListWithObject; + aListWithObject.push_back(theObject); + std::shared_ptr aMakeShapeList(new GeomAlgoAPI_MakeShapeList()); + std::shared_ptr aBoolAlgo; + GeomShapePtr aResShape; + + std::list > aBoundingPoints = + GeomAlgoAPI_ShapeTools::getBoundingBox(aListWithObject, 1.0); + + // Resize planes. + ListOfShape aToolsWithPlanes = theTools; + for (ListOfShape::const_iterator anIt = thePlanes.begin(); anIt != thePlanes.end(); ++anIt) { + GeomShapePtr aPlane = *anIt; + GeomShapePtr aTool = GeomAlgoAPI_ShapeTools::fitPlaneToBox(aPlane, aBoundingPoints); + std::shared_ptr aMkShCustom( + new GeomAlgoAPI_MakeShapeCustom); + aMkShCustom->addModified(aPlane, aTool); + aMakeShapeList->appendAlgo(aMkShCustom); + aToolsWithPlanes.push_back(aTool); + } + + if (theBooleanType == GeomAlgoAPI_Tools::BOOL_PARTITION) + aBoolAlgo.reset(new GeomAlgoAPI_Partition(aListWithObject, aToolsWithPlanes)); + else + aBoolAlgo.reset(new GeomAlgoAPI_Boolean(aListWithObject, + aToolsWithPlanes, + theBooleanType)); + + // Checking that the algorithm worked properly. + std::string anError; + if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aBoolAlgo, getKind(), anError)) { + setError(anError); + return false; + } + + aResShape = aBoolAlgo->shape(); + if (aResShape.get() && aResShape->shapeType() == GeomAPI_Shape::COMPOUND) { + int aSubResultsNb = 0; + GeomAPI_ShapeIterator anIt(aResShape); + for (; anIt.more(); anIt.next()) + ++aSubResultsNb; + + if (aSubResultsNb == 1) { + anIt.init(aResShape); + if (anIt.more()) + aResShape = anIt.current(); } } - int aResultIndex = 0; + aMakeShapeList->appendAlgo(aBoolAlgo); + + GeomAPI_ShapeIterator aShapeIt(aResShape); + if (aShapeIt.more() || aResShape->shapeType() == GeomAPI_Shape::VERTEX) { + std::shared_ptr aResultBody = + document()->createBody(data(), theResultIndex); + + // tools should be added to the list to fulfill the correct history of modification + aListWithObject.insert(aListWithObject.end(), theTools.begin(), theTools.end()); + + ListOfShape aUsedTools = theTools; + aUsedTools.insert(aUsedTools.end(), thePlanes.begin(), thePlanes.end()); + + FeaturesPlugin_Tools::loadModifiedShapes(aResultBody, + aListWithObject, + aUsedTools, + aMakeShapeList, + aResShape); + setResult(aResultBody, theResultIndex); + ++theResultIndex; + + FeaturesPlugin_Tools::ResultBaseAlgo aRBA; + aRBA.resultBody = aResultBody; + aRBA.baseShape = theObject; + aRBA.makeShape = aMakeShapeList; + theResultBaseAlgoList.push_back(aRBA); + theResultShapesList.push_back(aResShape); + } + return true; +} - switch(aType) { - case GeomAlgoAPI_Boolean::BOOL_CUT: - case GeomAlgoAPI_Boolean::BOOL_COMMON:{ - if((anObjects.empty() && aCompSolidsObjects.empty()) || aTools.empty()) { - std::string aFeatureError = "Error: Not enough objects for boolean operation."; - setError(aFeatureError); - return; - } +//================================================================================================= +bool FeaturesPlugin_Boolean::processCompsolid( + const GeomAlgoAPI_Tools::BOPType theBooleanType, + const ObjectHierarchy& theCompsolidHierarchy, + const GeomShapePtr& theCompsolid, + const ListOfShape& theTools, + const ListOfShape& thePlanes, + int& theResultIndex, + std::vector& theResultBaseAlgoList, + ListOfShape& theResultShapesList) +{ + ListOfShape aUsedInOperationSolids; + ListOfShape aNotUsedSolids; + theCompsolidHierarchy.SplitCompound(theCompsolid, aUsedInOperationSolids, aNotUsedSolids); + + std::shared_ptr aMakeShapeList(new GeomAlgoAPI_MakeShapeList()); + + std::list > aBoundingPoints = + GeomAlgoAPI_ShapeTools::getBoundingBox(aUsedInOperationSolids, 1.0); + + // Resize planes. + ListOfShape aToolsWithPlanes = theTools; + for (ListOfShape::const_iterator anIt = thePlanes.begin(); anIt != thePlanes.end(); ++anIt) + { + GeomShapePtr aPlane = *anIt; + GeomShapePtr aTool = GeomAlgoAPI_ShapeTools::fitPlaneToBox(aPlane, aBoundingPoints); + std::shared_ptr aMkShCustom( + new GeomAlgoAPI_MakeShapeCustom); + aMkShCustom->addModified(aPlane, aTool); + aMakeShapeList->appendAlgo(aMkShCustom); + aToolsWithPlanes.push_back(aTool); + } - // For solids cut each object with all tools. - for(ListOfShape::iterator anObjectsIt = anObjects.begin(); anObjectsIt != anObjects.end(); anObjectsIt++) { - std::shared_ptr anObject = *anObjectsIt; - ListOfShape aListWithObject; - aListWithObject.push_back(anObject); - GeomAlgoAPI_Boolean aBoolAlgo(aListWithObject, aTools, aType); - - // Checking that the algorithm worked properly. - if(!aBoolAlgo.isDone()) { - static const std::string aFeatureError = "Error: Boolean algorithm failed."; - setError(aFeatureError); - return; - } - if(aBoolAlgo.shape()->isNull()) { - static const std::string aShapeError = "Error: Resulting shape is Null."; - setError(aShapeError); - return; - } - if(!aBoolAlgo.isValid()) { - std::string aFeatureError = "Error: Resulting shape is not valid."; - setError(aFeatureError); - return; - } - - if(GeomAlgoAPI_ShapeTools::volume(aBoolAlgo.shape()) > 1.e-7) { - std::shared_ptr aResultBody = document()->createBody(data(), aResultIndex); - loadNamingDS(aResultBody, anObject, aTools, aBoolAlgo.shape(), aBoolAlgo, *aBoolAlgo.mapOfSubShapes().get()); - setResult(aResultBody, aResultIndex); - aResultIndex++; - } - } + std::shared_ptr aBoolAlgo; + if (theBooleanType == GeomAlgoAPI_Tools::BOOL_PARTITION) + aBoolAlgo.reset(new GeomAlgoAPI_Partition(aUsedInOperationSolids, aToolsWithPlanes)); + else + aBoolAlgo.reset(new GeomAlgoAPI_Boolean(aUsedInOperationSolids, + aToolsWithPlanes, + theBooleanType)); + + // Checking that the algorithm worked properly. + std::string anError; + if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aBoolAlgo, getKind(), anError)) { + setError(anError); + return false; + } - // 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 anIt = aUsedInOperationSolids.begin(); - for(; anIt != aUsedInOperationSolids.end(); anIt++) { - if(aSolidInCompSolid->isEqual(*anIt)) { - break; - } - } - if(anIt == aUsedInOperationSolids.end()) { - aNotUsedSolids.push_back(aSolidInCompSolid); - } - } - - std::shared_ptr aBoolAlgo(new GeomAlgoAPI_Boolean(aUsedInOperationSolids, aTools, aType)); - - // Checking that the algorithm worked properly. - if(!aBoolAlgo->isDone()) { - static const std::string aFeatureError = "Error: Boolean algorithm failed."; - setError(aFeatureError); - return; - } - if(aBoolAlgo->shape()->isNull()) { - static const std::string aShapeError = "Error: Resulting shape is Null."; - setError(aShapeError); - return; - } - if(!aBoolAlgo->isValid()) { - std::string aFeatureError = "Error: Resulting shape is not valid."; - setError(aFeatureError); - return; - } - - GeomAlgoAPI_MakeShapeList aMakeShapeList; - aMakeShapeList.appendAlgo(aBoolAlgo); - GeomAPI_DataMapOfShapeShape aMapOfShapes; - aMapOfShapes.merge(aBoolAlgo->mapOfSubShapes()); - - // Add result to not used solids from compsolid. - ListOfShape aShapesToAdd = aNotUsedSolids; - aShapesToAdd.push_back(aBoolAlgo->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); - aMapOfShapes.merge(aFillerAlgo->mapOfSubShapes()); - - if(GeomAlgoAPI_ShapeTools::volume(aFillerAlgo->shape()) > 1.e-7) { - std::shared_ptr aResultBody = document()->createBody(data(), aResultIndex); - loadNamingDS(aResultBody, aCompSolid, aTools, aFillerAlgo->shape(), aMakeShapeList, aMapOfShapes); - setResult(aResultBody, aResultIndex); - aResultIndex++; - } - } - break; + aMakeShapeList->appendAlgo(aBoolAlgo); + GeomShapePtr aResultShape = aBoolAlgo->shape(); + + // Add result to not used solids from compsolid. + if (!aNotUsedSolids.empty()) { + ListOfShape aShapesToAdd = aNotUsedSolids; + aShapesToAdd.push_back(aBoolAlgo->shape()); + std::shared_ptr aFillerAlgo( + new GeomAlgoAPI_PaveFiller(aShapesToAdd, true)); + if (!aFillerAlgo->isDone()) { + std::string aFeatureError = "Error: PaveFiller algorithm failed."; + setError(aFeatureError); + return false; } - case GeomAlgoAPI_Boolean::BOOL_FUSE: { - if((anObjects.size() + aTools.size() + aCompSolidsObjects.size() + anEdgesAndFaces.size()) < 2) { - std::string aFeatureError = "Error: Not enough objects for boolean operation."; - setError(aFeatureError); - return; - } - // Collecting all solids which will be fused. - ListOfShape aSolidsToFuse; - aSolidsToFuse.insert(aSolidsToFuse.end(), anObjects.begin(), anObjects.end()); - aSolidsToFuse.insert(aSolidsToFuse.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(std::map, ListOfShape>::iterator anIt = aCompSolidsObjects.begin(); - anIt != aCompSolidsObjects.end(); anIt++) { - std::shared_ptr aCompSolid = anIt->first; - ListOfShape& aUsedInOperationSolids = anIt->second; - aSolidsToFuse.insert(aSolidsToFuse.end(), aUsedInOperationSolids.begin(), aUsedInOperationSolids.end()); - - // Collect solids from compsolid which will not be modified in boolean operation. - for(GeomAPI_ShapeExplorer anExp(aCompSolid, GeomAPI_Shape::SOLID); anExp.more(); anExp.next()) { - std::shared_ptr aSolidInCompSolid = anExp.current(); - ListOfShape::iterator anIt = aUsedInOperationSolids.begin(); - for(; anIt != aUsedInOperationSolids.end(); anIt++) { - if(aSolidInCompSolid->isEqual(*anIt)) { - break; - } - } - if(anIt == aUsedInOperationSolids.end()) { - aShapesToAdd.push_back(aSolidInCompSolid); - } - } - } + aMakeShapeList->appendAlgo(aFillerAlgo); + aResultShape = aFillerAlgo->shape(); + } - ListOfShape anOriginalShapes = aSolidsToFuse; - anOriginalShapes.insert(anOriginalShapes.end(), aShapesToAdd.begin(), aShapesToAdd.end()); - - // Cut edges and faces(if we have any) with solids. - GeomAlgoAPI_MakeShapeList aMakeShapeList; - GeomAPI_DataMapOfShapeShape aMapOfShapes; - std::shared_ptr aCuttedEdgesAndFaces; - if(!anEdgesAndFaces.empty()) { - std::shared_ptr aCutAlgo(new GeomAlgoAPI_Boolean(anEdgesAndFaces, anOriginalShapes, GeomAlgoAPI_Boolean::BOOL_CUT)); - if(aCutAlgo->isDone()) { - aCuttedEdgesAndFaces = aCutAlgo->shape(); - aMakeShapeList.appendAlgo(aCutAlgo); - aMapOfShapes.merge(aCutAlgo->mapOfSubShapes()); - } - } - anOriginalShapes.insert(anOriginalShapes.end(), anEdgesAndFaces.begin(), anEdgesAndFaces.end()); - - // If we have compsolids then cut with not used solids all others. - if(!aShapesToAdd.empty()) { - aSolidsToFuse.clear(); - for(ListOfShape::iterator anIt = anOriginalShapes.begin(); anIt != anOriginalShapes.end(); anIt++) { - ListOfShape aOneObjectList; - aOneObjectList.push_back(*anIt); - std::shared_ptr aCutAlgo(new GeomAlgoAPI_Boolean(aOneObjectList, aShapesToAdd, GeomAlgoAPI_Boolean::BOOL_CUT)); - - if(GeomAlgoAPI_ShapeTools::volume(aCutAlgo->shape()) > 1.e-7) { - aSolidsToFuse.push_back(aCutAlgo->shape()); - aMakeShapeList.appendAlgo(aCutAlgo); - aMapOfShapes.merge(aCutAlgo->mapOfSubShapes()); - } - } - } + GeomAPI_ShapeIterator aShapeIt(aResultShape); + if (aShapeIt.more() || aResultShape->shapeType() == GeomAPI_Shape::VERTEX) + { + std::shared_ptr aResultBody = + document()->createBody(data(), theResultIndex); + + ListOfShape aCompSolidList; + aCompSolidList.push_back(theCompsolid); + // tools should be added to the list to fulfill the correct history of modification + aCompSolidList.insert(aCompSolidList.end(), theTools.begin(), theTools.end()); + + ListOfShape aUsedTools = theTools; + aUsedTools.insert(aUsedTools.end(), thePlanes.begin(), thePlanes.end()); + + FeaturesPlugin_Tools::loadModifiedShapes(aResultBody, + aCompSolidList, + aUsedTools, + aMakeShapeList, + aResultShape); + setResult(aResultBody, theResultIndex); + ++theResultIndex; + + FeaturesPlugin_Tools::ResultBaseAlgo aRBA; + aRBA.resultBody = aResultBody; + aRBA.baseShape = theCompsolid; + aRBA.makeShape = aMakeShapeList; + theResultBaseAlgoList.push_back(aRBA); + theResultShapesList.push_back(aResultShape); + } + return true; +} - if(!aSolidsToFuse.empty()) { - anObjects.clear(); - anObjects.push_back(aSolidsToFuse.back()); - aSolidsToFuse.pop_back(); - aTools = aSolidsToFuse; - } +//================================================================================================= +bool FeaturesPlugin_Boolean::processCompound( + const GeomAlgoAPI_Tools::BOPType theBooleanType, + const ObjectHierarchy& theCompoundHierarchy, + const GeomShapePtr& theCompound, + const ListOfShape& theTools, + int& theResultIndex, + std::vector& theResultBaseAlgoList, + ListOfShape& theResultShapesList) +{ + ListOfShape aUsedInOperationShapes; + ListOfShape aNotUsedShapes; + theCompoundHierarchy.SplitCompound(theCompound, aUsedInOperationShapes, aNotUsedShapes); + + std::shared_ptr aMakeShapeList(new GeomAlgoAPI_MakeShapeList()); + std::shared_ptr aBoolAlgo( + new GeomAlgoAPI_Boolean(aUsedInOperationShapes, + theTools, + theBooleanType)); + + // Checking that the algorithm worked properly. + std::string anError; + if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aBoolAlgo, getKind(), anError)) { + setError(anError); + return false; + } - // Fuse all objects and all tools. - std::shared_ptr aShape; - if(anObjects.size() == 1 && aTools.empty()) { - aShape = anObjects.front(); - } else if(anObjects.empty() && aTools.size() == 1) { - aShape = aTools.front(); - } else if((anObjects.size() + aTools.size()) > 1){ - std::shared_ptr aFuseAlgo(new GeomAlgoAPI_Boolean(anObjects, aTools, aType)); - - // Checking that the algorithm worked properly. - if(!aFuseAlgo->isDone()) { - static const std::string aFeatureError = "Error: Boolean algorithm failed."; - setError(aFeatureError); - return; - } - if(aFuseAlgo->shape()->isNull()) { - static const std::string aShapeError = "Error: Resulting shape is Null."; - setError(aShapeError); - return; - } - if(!aFuseAlgo->isValid()) { - std::string aFeatureError = "Error: Resulting shape is not valid."; - setError(aFeatureError); - return; - } - - aShape = aFuseAlgo->shape(); - aMakeShapeList.appendAlgo(aFuseAlgo); - aMapOfShapes.merge(aFuseAlgo->mapOfSubShapes()); - } + aMakeShapeList->appendAlgo(aBoolAlgo); + GeomShapePtr aResultShape = aBoolAlgo->shape(); - // Combine result with not used solids from compsolid and edges and faces (if we have any). - if(aCuttedEdgesAndFaces.get() && !aCuttedEdgesAndFaces->isNull()) { - aShapesToAdd.push_back(aCuttedEdgesAndFaces); - } else { - aShapesToAdd.insert(aShapesToAdd.end(), anEdgesAndFaces.begin(), anEdgesAndFaces.end()); - } - if(!aShapesToAdd.empty()) { - if(aShape.get()) { - aShapesToAdd.push_back(aShape); - } - std::shared_ptr aFillerAlgo(new GeomAlgoAPI_PaveFiller(aShapesToAdd, true)); - if(!aFillerAlgo->isDone()) { - std::string aFeatureError = "Error: PaveFiller algorithm failed."; - setError(aFeatureError); - return; - } - if(aFillerAlgo->shape()->isNull()) { - static const std::string aShapeError = "Error: Resulting shape is Null."; - setError(aShapeError); - return; - } - if(!aFillerAlgo->isValid()) { - std::string aFeatureError = "Error: Resulting shape is not valid."; - setError(aFeatureError); - return; - } - - aShape = aFillerAlgo->shape(); - aMakeShapeList.appendAlgo(aFillerAlgo); - aMapOfShapes.merge(aFillerAlgo->mapOfSubShapes()); + // 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); + } - std::shared_ptr aBackShape = anOriginalShapes.back(); - anOriginalShapes.pop_back(); - std::shared_ptr aResultBody = document()->createBody(data(), aResultIndex); - loadNamingDS(aResultBody, aBackShape, anOriginalShapes, aShape, aMakeShapeList, aMapOfShapes); - setResult(aResultBody, aResultIndex); - aResultIndex++; - break; + if (aShapesForResult.size() == 1) { + aResultShape = aShapesForResult.front(); } - default: { - std::string anOperationError = "Error: Wrong type of operation"; - setError(anOperationError); - return; + else { + aResultShape = GeomAlgoAPI_CompoundBuilder::compound(aShapesForResult); } } - // remove the rest results if there were produced in the previous pass - removeResults(aResultIndex); + + GeomAPI_ShapeIterator aShapeIt(aResultShape); + if (aShapeIt.more() || aResultShape->shapeType() == GeomAPI_Shape::VERTEX) { + std::shared_ptr aResultBody = + document()->createBody(data(), theResultIndex); + + ListOfShape aCompoundList; + aCompoundList.push_back(theCompound); + FeaturesPlugin_Tools::loadModifiedShapes(aResultBody, + aCompoundList, + theTools, + aMakeShapeList, + aResultShape); + setResult(aResultBody, theResultIndex); + ++theResultIndex; + + FeaturesPlugin_Tools::ResultBaseAlgo aRBA; + aRBA.resultBody = aResultBody; + aRBA.baseShape = theCompound; + aRBA.makeShape = aMakeShapeList; + theResultBaseAlgoList.push_back(aRBA); + theResultShapesList.push_back(aResultShape); + } + return true; } //================================================================================================= -void FeaturesPlugin_Boolean::loadNamingDS(std::shared_ptr theResultBody, - const std::shared_ptr theBaseShape, - const ListOfShape& theTools, - const std::shared_ptr theResultShape, - GeomAlgoAPI_MakeShape& theMakeShape, - GeomAPI_DataMapOfShapeShape& theMapOfShapes) + +void FeaturesPlugin_Boolean::ObjectHierarchy::AddObject(const GeomShapePtr& theObject) { - //load result - if(theBaseShape->isEqual(theResultShape)) { - theResultBody->store(theResultShape); - } else { - const int aModifyTag = 1; - const int aDeletedTag = 2; - const int aSubsolidsTag = 3; /// sub solids will be placed at labels 3, 4, etc. if result is compound of solids - const int anEdgesAndFacesTag = 10000; - - theResultBody->storeModified(theBaseShape, theResultShape, aSubsolidsTag); - - const std::string aModName = "Modified"; - const std::string aModEName = "Modified_Edge"; - const std::string aModFName = "Modified_Face"; - - theResultBody->loadAndOrientModifiedShapes(&theMakeShape, theBaseShape, GeomAPI_Shape::FACE, - aModifyTag, aModName, theMapOfShapes); - theResultBody->loadDeletedShapes(&theMakeShape, theBaseShape, GeomAPI_Shape::FACE, aDeletedTag); - - int aTag; - std::string aName; - for(ListOfShape::const_iterator anIter = theTools.begin(); anIter != theTools.end(); anIter++) { - if((*anIter)->shapeType() == GeomAPI_Shape::EDGE) { - aTag = anEdgesAndFacesTag; - aName = aModEName; - } - else if((*anIter)->shapeType() == GeomAPI_Shape::FACE) { - aTag = anEdgesAndFacesTag; - aName = aModFName; - } else { - aTag = aModifyTag; - aName = aModName; - } - theResultBody->loadAndOrientModifiedShapes(&theMakeShape, *anIter, aName == aModEName ? GeomAPI_Shape::EDGE : GeomAPI_Shape::FACE, - aTag, aName, theMapOfShapes); - theResultBody->loadDeletedShapes(&theMakeShape, *anIter, GeomAPI_Shape::FACE, aDeletedTag); + myObjects.push_back(theObject); +} + +void FeaturesPlugin_Boolean::ObjectHierarchy::AddParent(const GeomShapePtr& theShape, + const GeomShapePtr& theParent) +{ + myParent[theShape] = theParent; + mySubshapes[theParent].push_back(theShape); +} + +GeomShapePtr FeaturesPlugin_Boolean::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[aParent]; + for (ListOfShape::const_iterator anIt = aSubs.begin(); anIt != aSubs.end(); ++anIt) + myProcessedObjects.insert(*anIt); } } + return aParent; +} + +void FeaturesPlugin_Boolean::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_Boolean::ObjectHierarchy::SplitCompound(const GeomShapePtr& theCompShape, + ListOfShape& theUsed, + ListOfShape& theNotUsed) const +{ + theUsed.clear(); + theNotUsed.clear(); + + const ListOfShape& aSubs = mySubshapes.find(theCompShape)->second; + SetOfShape aSubsSet; + aSubsSet.insert(aSubs.begin(), aSubs.end()); + + for (GeomAPI_ShapeExplorer anExp(theCompShape, GeomAPI_Shape::SOLID); + anExp.more(); anExp.next()) { + GeomShapePtr aCurrent = anExp.current(); + if (aSubsSet.find(aCurrent) == aSubsSet.end()) + theNotUsed.push_back(aCurrent); + else + theUsed.push_back(aCurrent); + } +} + +bool FeaturesPlugin_Boolean::ObjectHierarchy::IsEmpty() const +{ + return myObjects.empty(); +} + +FeaturesPlugin_Boolean::ObjectHierarchy::Iterator FeaturesPlugin_Boolean::ObjectHierarchy::Begin() +{ + return Iterator(this); +} + +FeaturesPlugin_Boolean::ObjectHierarchy::Iterator FeaturesPlugin_Boolean::ObjectHierarchy::End() +{ + return Iterator(this, false); +} + +FeaturesPlugin_Boolean::ObjectHierarchy::Iterator::Iterator( + FeaturesPlugin_Boolean::ObjectHierarchy* theHierarchy, bool isBegin) + : myHierarchy(theHierarchy) +{ + if (isBegin) { + myObject = myHierarchy->myObjects.begin(); + SkipAlreadyProcessed(); + } else + myObject = myHierarchy->myObjects.end(); +} + +void FeaturesPlugin_Boolean::ObjectHierarchy::Iterator::SkipAlreadyProcessed() +{ + while (myObject != myHierarchy->myObjects.end() && + myHierarchy->myProcessedObjects.find(*myObject) != myHierarchy->myProcessedObjects.end()) + ++myObject; +} + +bool FeaturesPlugin_Boolean::ObjectHierarchy::Iterator::operator==(const Iterator& theOther) const +{ + return myObject == theOther.myObject; +} + +bool FeaturesPlugin_Boolean::ObjectHierarchy::Iterator::operator!=(const Iterator& theOther) const +{ + return !operator==(theOther); +} + +FeaturesPlugin_Boolean::ObjectHierarchy::Iterator& +FeaturesPlugin_Boolean::ObjectHierarchy::Iterator::operator++() +{ + ++myObject; + SkipAlreadyProcessed(); + return *this; +} + +FeaturesPlugin_Boolean::ObjectHierarchy::Iterator +FeaturesPlugin_Boolean::ObjectHierarchy::Iterator::operator++(int) +{ + Iterator aCurrent; + aCurrent.myHierarchy = myHierarchy; + aCurrent.myObject = myObject; + + // increase iterator + operator++(); + + return aCurrent; +} + +GeomShapePtr FeaturesPlugin_Boolean::ObjectHierarchy::Iterator::operator*() const +{ + myHierarchy->myProcessedObjects.insert(*myObject); + return *myObject; }