X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FFeaturesPlugin%2FFeaturesPlugin_CompositeBoolean.cpp;h=9cdf2b7ccd45eafe2de8dcb2a7a4975c838dc6a1;hb=1e2eaa713f139d2617c80eba9ede62d4e9976bb7;hp=f31196f42c0fcbe4fd375a80fd0ebd5e6c22c531;hpb=a94908a12c7428994444fe4f5202461a94390b1d;p=modules%2Fshaper.git diff --git a/src/FeaturesPlugin/FeaturesPlugin_CompositeBoolean.cpp b/src/FeaturesPlugin/FeaturesPlugin_CompositeBoolean.cpp index f31196f42..9cdf2b7cc 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_CompositeBoolean.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_CompositeBoolean.cpp @@ -1,171 +1,131 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D - -// File: FeaturesPlugin_CompositeBoolean.cpp -// Created: 11 June 2015 -// Author: Dmitry Bobylev +// Copyright (C) 2014-2017 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_CompositeBoolean.h" #include -#include -#include -#include -#include #include -#include -#include +#include #include #include -#include -#include #include + #include +#include + //================================================================================================= -void FeaturesPlugin_CompositeBoolean::initAttributes() +void FeaturesPlugin_CompositeBoolean::initBooleanAttributes() { - data()->addAttribute(SKETCH_OBJECT_ID(), ModelAPI_AttributeReference::typeId()); - - // Boolean works with solids always. - data()->addAttribute(BOOLEAN_OBJECTS_ID(), ModelAPI_AttributeSelectionList::typeId()); - AttributeSelectionListPtr aSelection = data()->selectionList(BOOLEAN_OBJECTS_ID()); - aSelection->setSelectionType("SOLID"); - - initMakeSolidsAttributes(); - - data()->addAttribute(SKETCH_SELECTION_ID(), ModelAPI_AttributeSelection::typeId()); - ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), SKETCH_SELECTION_ID()); + myFeature->data()->addAttribute(OBJECTS_ID(), ModelAPI_AttributeSelectionList::typeId()); } //================================================================================================= -std::shared_ptr FeaturesPlugin_CompositeBoolean::addFeature(std::string theID) +void FeaturesPlugin_CompositeBoolean::executeCompositeBoolean() { - std::shared_ptr aNew = document()->addFeature(theID, false); - if (aNew) { - data()->reference(SKETCH_OBJECT_ID())->setValue(aNew); + // Make generation. + ListOfShape aGenBaseShapes; + ListOfMakeShape aGenMakeShapes; + if(!makeGeneration(aGenBaseShapes, aGenMakeShapes)) { + return; } - // set as current also after it becomes sub to set correctly enabled for other sketch subs - document()->setCurrentFeature(aNew, false); - return aNew; -} -//================================================================================================= -int FeaturesPlugin_CompositeBoolean::numberOfSubs(bool forTree) const -{ - ObjectPtr aObj = data()->reference(SKETCH_OBJECT_ID())->value(); - return aObj.get()? 1 : 0; -} + // Getting tools. + ListOfShape aTools; + for(ListOfMakeShape::const_iterator + anIt = aGenMakeShapes.cbegin(); anIt != aGenMakeShapes.cend(); ++anIt) { + aTools.push_back((*anIt)->shape()); + } -//================================================================================================= -std::shared_ptr FeaturesPlugin_CompositeBoolean::subFeature(const int theIndex, bool forTree) -{ - if (theIndex == 0) - return std::dynamic_pointer_cast(data()->reference(SKETCH_OBJECT_ID())->value()); - return std::shared_ptr(); -} + // Make boolean. + ListOfShape aBooleanObjects; + ListOfMakeShape aBooleanMakeShapes; + if(!makeBoolean(aTools, aBooleanObjects, aBooleanMakeShapes)) { + return; + } -//================================================================================================= -int FeaturesPlugin_CompositeBoolean::subFeatureId(const int theIndex) const -{ - if (theIndex == 0) { - FeaturePtr aFeature = - std::dynamic_pointer_cast(data()->reference(SKETCH_OBJECT_ID())->value()); - if (aFeature.get()) - return aFeature->data()->featureId(); + if(myOperationType == BOOL_FUSE) { + aTools.splice(aTools.begin(), aBooleanObjects); + aBooleanObjects.splice(aBooleanObjects.begin(), aTools, aTools.begin()); } - return -1; -} -//================================================================================================= -bool FeaturesPlugin_CompositeBoolean::isSub(ObjectPtr theObject) const -{ - // check is this feature of result - FeaturePtr aFeature = std::dynamic_pointer_cast(theObject); - if (!aFeature) - return false; - - ObjectPtr aSub = data()->reference(SKETCH_OBJECT_ID())->value(); - return aSub == theObject; -} + // Store result. + int aResultIndex = 0; + ListOfShape::const_iterator aBoolObjIt = aBooleanObjects.cbegin(); + ListOfMakeShape::const_iterator aBoolMSIt = aBooleanMakeShapes.cbegin(); + for(; aBoolObjIt != aBooleanObjects.cend() && aBoolMSIt != aBooleanMakeShapes.cend(); + ++aBoolObjIt, ++aBoolMSIt) { -//================================================================================================= -void FeaturesPlugin_CompositeBoolean::removeFeature(std::shared_ptr theFeature) -{ -} + int aTag = 1; -//================================================================================================= -void FeaturesPlugin_CompositeBoolean::erase() -{ - if (data().get() && data()->isValid()) { // on abort of sketch of this composite it may be invalid - FeaturePtr aSketch = - std::dynamic_pointer_cast(data()->reference(SKETCH_OBJECT_ID())->value()); - if (aSketch.get() && aSketch->data()->isValid()) { - document()->removeFeature(aSketch); + ResultBodyPtr aResultBody = myFeature->document()->createBody(myFeature->data(), aResultIndex); + + if((*aBoolObjIt)->isEqual((*aBoolMSIt)->shape())) { + aResultBody->store((*aBoolMSIt)->shape(), false); } - } - ModelAPI_CompositeFeature::erase(); -} + else + { + aResultBody->storeModified(*aBoolObjIt, (*aBoolMSIt)->shape(), aTag); + + aTag += 5000; + + // Store generation history. + ListOfShape::const_iterator aGenBaseIt = aGenBaseShapes.cbegin(); + ListOfMakeShape::const_iterator aGenMSIt = aGenMakeShapes.cbegin(); + for(; aGenBaseIt != aGenBaseShapes.cend() && aGenMSIt != aGenMakeShapes.cend(); + ++aGenBaseIt, ++aGenMSIt) { + storeGenerationHistory(aResultBody, *aGenBaseIt, *aGenMSIt, aTag); + } + int aModTag = aTag; + storeModificationHistory(aResultBody, *aBoolObjIt, aTools, *aBoolMSIt, aModTag); + } -//================================================================================================= -void FeaturesPlugin_CompositeBoolean::execute() -{ - // Getting faces to create solids. - std::shared_ptr aSketchFeature = std::dynamic_pointer_cast( - reference(SKETCH_OBJECT_ID())->value()); - if(!aSketchFeature || aSketchFeature->results().empty()) { - return; - } - ResultPtr aSketchRes = aSketchFeature->results().front(); - ResultConstructionPtr aConstruction = std::dynamic_pointer_cast(aSketchRes); - if(!aConstruction.get()) { - return; - } - selection(SKETCH_SELECTION_ID())->setValue(aSketchRes, std::shared_ptr()); - int aSketchFacesNum = aConstruction->facesNum(); - if(aSketchFacesNum == 0) { - return; - } - ListOfShape aFacesList; - for(int aFaceIndex = 0; aFaceIndex < aSketchFacesNum; aFaceIndex++) { - std::shared_ptr aFace = std::dynamic_pointer_cast(aConstruction->face(aFaceIndex)); - aFacesList.push_back(aFace); + myFeature->setResult(aResultBody, aResultIndex++); } - // Searching faces with common edges. - ListOfShape aShells; - ListOfShape aFreeFaces; - std::shared_ptr aFacesCompound = GeomAlgoAPI_CompoundBuilder::compound(aFacesList); - GeomAlgoAPI_ShapeTools::combineShapes(aFacesCompound, GeomAPI_Shape::SHELL, aShells, aFreeFaces); - aShells.insert(aShells.end(), aFreeFaces.begin(), aFreeFaces.end()); - - // Pass shells/faces to solids creation function. - ListOfShape aTools; - std::list> aSolidsAlgos; - makeSolids(aShells, aTools, aSolidsAlgos); - if(aTools.empty()) { - return; - } + myFeature->removeResults(aResultIndex); +} - // Getting objects for boolean operation. - ListOfShape anObjects; - std::map, ListOfShape> aCompSolidsObjects; - AttributeSelectionListPtr anObjectsSelList = selectionList(BOOLEAN_OBJECTS_ID()); - if(anObjectsSelList->size() == 0) { - return; - } +//================================================================================================= +bool FeaturesPlugin_CompositeBoolean::makeBoolean(const ListOfShape& theTools, + ListOfShape& theObjects, + ListOfMakeShape& theMakeShapes) +{ + // Getting objects. + ListOfShape anObjects, anEdgesAndFaces, aCompSolids; + std::map aCompSolidsObjects; + AttributeSelectionListPtr anObjectsSelList = myFeature->selectionList(OBJECTS_ID()); for(int anObjectsIndex = 0; anObjectsIndex < anObjectsSelList->size(); anObjectsIndex++) { AttributeSelectionPtr anObjectAttr = anObjectsSelList->value(anObjectsIndex); - std::shared_ptr anObject = anObjectAttr->value(); + GeomShapePtr anObject = anObjectAttr->value(); if(!anObject.get()) { - return; + myFeature->setError("Error: Could not get object."); + return false; } ResultPtr aContext = anObjectAttr->context(); - ResultCompSolidPtr aResCompSolidPtr = ModelAPI_Tools::compSolidOwner(aContext); + ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext); if(aResCompSolidPtr.get()) { - std::shared_ptr aContextShape = aResCompSolidPtr->shape(); - std::map, ListOfShape>::iterator anIt = aCompSolidsObjects.begin(); + 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); @@ -174,287 +134,268 @@ void FeaturesPlugin_CompositeBoolean::execute() } if(anIt == aCompSolidsObjects.end()) { aCompSolidsObjects[aContextShape].push_back(anObject); + aCompSolids.push_back(aContextShape); } } else { - anObjects.push_back(anObject); + if(anObject->shapeType() == GeomAPI_Shape::EDGE || + anObject->shapeType() == GeomAPI_Shape::FACE) { + anEdgesAndFaces.push_back(anObject); + } else { + anObjects.push_back(anObject); + } } } - // Cut from each object solids. - int aResultIndex = 0; + switch(myOperationType) { + case BOOL_CUT: { + if((anObjects.empty() && aCompSolidsObjects.empty()) || theTools.empty()) { + myFeature->setError("Error: Not enough objects for boolean operation."); + return false; + } - switch(myBooleanOperationType) { - case GeomAlgoAPI_Boolean::BOOL_CUT: - case GeomAlgoAPI_Boolean::BOOL_COMMON:{ - // Cut each object with all tools - for(ListOfShape::iterator anObjectsIt = anObjects.begin(); anObjectsIt != anObjects.end(); anObjectsIt++) { - std::shared_ptr anObject = *anObjectsIt; + // For solids cut each object with all tools. + for(ListOfShape::const_iterator + anIt = anObjects.cbegin(); anIt != anObjects.cend(); ++anIt) { + GeomShapePtr anObject = *anIt; ListOfShape aListWithObject; aListWithObject.push_back(anObject); - GeomAlgoAPI_Boolean aBoolAlgo(aListWithObject, aTools, myBooleanOperationType); + std::shared_ptr aBoolAlgo(new GeomAlgoAPI_Boolean(aListWithObject, + theTools, + GeomAlgoAPI_Boolean::BOOL_CUT)); // Checking that the algorithm worked properly. - if(!aBoolAlgo.isDone() || aBoolAlgo.shape()->isNull() || !aBoolAlgo.isValid()) { - setError("Boolean algorithm failed"); - return; + if(!aBoolAlgo->isDone() || aBoolAlgo->shape()->isNull() || !aBoolAlgo->isValid()) { + myFeature->setError("Error: Boolean algorithm failed."); + return false; } - if(GeomAlgoAPI_ShapeTools::volume(aBoolAlgo.shape()) > 1.e-7) { - std::shared_ptr aResultBody = document()->createBody(data(), aResultIndex); - loadNamingDS(aResultBody, aShells, aSolidsAlgos, anObject, aTools, aBoolAlgo.shape(), - *aBoolAlgo.makeShape(), *aBoolAlgo.mapOfShapes()); - setResult(aResultBody, aResultIndex); - aResultIndex++; + if(GeomAlgoAPI_ShapeTools::volume(aBoolAlgo->shape()) > 1.e-27) { + theObjects.push_back(anObject); + theMakeShapes.push_back(aBoolAlgo); } } // Compsolids handling - for(std::map, ListOfShape>::iterator anIt = aCompSolidsObjects.begin(); - anIt != aCompSolidsObjects.end(); anIt++) { - std::shared_ptr aCompSolid = anIt->first; - ListOfShape& aUsedInOperationSolids = anIt->second; + for(std::map::const_iterator anIt = aCompSolidsObjects.cbegin(); + anIt != aCompSolidsObjects.cend(); ++anIt) { + GeomShapePtr aCompSolid = anIt->first; + const ListOfShape& aUsedShapes = 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)) { + ListOfShape aShapesToAdd; + for(GeomAPI_ShapeExplorer + anExp(aCompSolid, GeomAPI_Shape::SOLID); anExp.more(); anExp.next()) { + GeomShapePtr aSolidInCompSolid = anExp.current(); + ListOfShape::const_iterator aUsedShapesIt = aUsedShapes.cbegin(); + for(; aUsedShapesIt != aUsedShapes.cend(); ++aUsedShapesIt) { + if(aSolidInCompSolid->isEqual(*aUsedShapesIt)) { break; } } - if(anIt == aUsedInOperationSolids.end()) { - aNotUsedSolids.push_back(aSolidInCompSolid); + if(aUsedShapesIt == aUsedShapes.end()) { + aShapesToAdd.push_back(aSolidInCompSolid); } } - GeomAlgoAPI_Boolean aBoolAlgo(aUsedInOperationSolids, aTools, myBooleanOperationType); + std::shared_ptr aBoolAlgo(new GeomAlgoAPI_Boolean(aUsedShapes, + theTools, + GeomAlgoAPI_Boolean::BOOL_CUT)); // Checking that the algorithm worked properly. - if(!aBoolAlgo.isDone() || aBoolAlgo.shape()->isNull() || !aBoolAlgo.isValid()) { - setError("Boolean algorithm failed"); - return; + if(!aBoolAlgo->isDone() || aBoolAlgo->shape()->isNull() || !aBoolAlgo->isValid()) { + myFeature->setError("Error: Boolean algorithm failed."); + return false; } - GeomAlgoAPI_MakeShapeList aMakeShapeList; - aMakeShapeList.appendAlgo(aBoolAlgo.makeShape()); - GeomAPI_DataMapOfShapeShape aMapOfShapes; - aMapOfShapes.merge(aBoolAlgo.mapOfShapes()); + std::shared_ptr aMakeShapeList(new GeomAlgoAPI_MakeShapeList()); + aMakeShapeList->appendAlgo(aBoolAlgo); // Add result to not used solids from compsolid. - ListOfShape aShapesToAdd = aNotUsedSolids; - aShapesToAdd.push_back(aBoolAlgo.shape()); - GeomAlgoAPI_PaveFiller aFillerAlgo(aShapesToAdd, true); - if(!aFillerAlgo.isDone()) { - std::string aFeatureError = "PaveFiller algorithm failed"; - setError(aFeatureError); - return; + 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; } - aMakeShapeList.appendAlgo(aFillerAlgo.makeShape()); - aMapOfShapes.merge(aFillerAlgo.mapOfShapes()); + aMakeShapeList->appendAlgo(aFillerAlgo); - if(GeomAlgoAPI_ShapeTools::volume(aFillerAlgo.shape()) > 1.e-7) { - std::shared_ptr aResultBody = document()->createBody(data(), aResultIndex); - loadNamingDS(aResultBody, aShells, aSolidsAlgos, aCompSolid, aTools, aFillerAlgo.shape(), aMakeShapeList, aMapOfShapes); - setResult(aResultBody, aResultIndex); - aResultIndex++; + if(GeomAlgoAPI_ShapeTools::volume(aFillerAlgo->shape()) > 1.e-27) { + theObjects.push_back(aCompSolid); + theMakeShapes.push_back(aMakeShapeList); } } break; } - case GeomAlgoAPI_Boolean::BOOL_FUSE: { + case BOOL_FUSE: { + // Set objects. + theObjects.insert(theObjects.end(), anEdgesAndFaces.begin(), anEdgesAndFaces.end()); + theObjects.insert(theObjects.end(), anObjects.begin(), anObjects.end()); + theObjects.insert(theObjects.end(), aCompSolids.begin(), aCompSolids.end()); + + // Filter edges and faces in tools. + ListOfShape aTools; + for(ListOfShape::const_iterator anIt = theTools.cbegin(); anIt != theTools.cend(); ++anIt) { + if((*anIt)->shapeType() == GeomAPI_Shape::EDGE || + (*anIt)->shapeType() == GeomAPI_Shape::FACE) { + anEdgesAndFaces.push_back(*anIt); + } else { + aTools.push_back(*anIt); + } + } + + if((anObjects.size() + aTools.size() + + aCompSolidsObjects.size() + anEdgesAndFaces.size()) < 2) { + myFeature->setError("Error: Not enough objects for boolean operation."); + return false; + } + // 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. - ListOfShape aNotUsedSolids; - 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()); + // Collecting solids from compsolids 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++) { + 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_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++) { + for(GeomAPI_ShapeExplorer + anExp(aCompSolid, GeomAPI_Shape::SOLID); anExp.more(); anExp.next()) { + GeomShapePtr aSolidInCompSolid = anExp.current(); + ListOfShape::iterator anIt = aUsedShapes.begin(); + for(; anIt != aUsedShapes.end(); anIt++) { if(aSolidInCompSolid->isEqual(*anIt)) { break; } } - if(anIt == aUsedInOperationSolids.end()) { - aNotUsedSolids.push_back(aSolidInCompSolid); + if(anIt == aUsedShapes.end()) { + aShapesToAdd.push_back(aSolidInCompSolid); } } } - ListOfShape anOriginalSolids = aSolidsToFuse; - anOriginalSolids.insert(anOriginalSolids.end(), aNotUsedSolids.begin(), aNotUsedSolids.end()); - GeomAlgoAPI_MakeShapeList aMakeShapeList; - GeomAPI_DataMapOfShapeShape aMapOfShapes; + // Cut edges and faces(if we have any) with solids. + ListOfShape aCutTools; + aCutTools.insert(aCutTools.end(), anObjects.begin(), anObjects.end()); + aCutTools.insert(aCutTools.end(), aCompSolids.begin(), aCompSolids.end()); + aCutTools.insert(aCutTools.end(), aTools.begin(), aTools.end()); + + std::shared_ptr aMakeShapeList(new GeomAlgoAPI_MakeShapeList()); + if(!anEdgesAndFaces.empty() && !aCutTools.empty()) { + std::shared_ptr aCutAlgo(new GeomAlgoAPI_Boolean(anEdgesAndFaces, + aCutTools, + GeomAlgoAPI_Boolean::BOOL_CUT)); + if(aCutAlgo->isDone() && !aCutAlgo->shape()->isNull() && aCutAlgo->isValid()) { + anEdgesAndFaces.clear(); + anEdgesAndFaces.push_back(aCutAlgo->shape()); + aMakeShapeList->appendAlgo(aCutAlgo); + } + } // If we have compsolids then cut with not used solids all others. - if(!aNotUsedSolids.empty()) { - aSolidsToFuse.clear(); - for(ListOfShape::iterator anIt = anOriginalSolids.begin(); anIt != anOriginalSolids.end(); anIt++) { - ListOfShape aOneObjectList; - aOneObjectList.push_back(*anIt); - GeomAlgoAPI_Boolean aCutAlgo(aOneObjectList, aNotUsedSolids, GeomAlgoAPI_Boolean::BOOL_CUT); - - if(GeomAlgoAPI_ShapeTools::volume(aCutAlgo.shape()) > 1.e-7) { - aSolidsToFuse.push_back(aCutAlgo.shape()); - aMakeShapeList.appendAlgo(aCutAlgo.makeShape()); - aMapOfShapes.merge(aCutAlgo.mapOfShapes()); - } + 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) { + aSolidsToFuse.clear(); + aSolidsToFuse.push_back(aCutAlgo->shape()); + aMakeShapeList->appendAlgo(aCutAlgo); } } - anObjects.clear(); - anObjects.push_back(aSolidsToFuse.back()); - aSolidsToFuse.pop_back(); - aTools = aSolidsToFuse; - // Fuse all objects and all tools. - GeomAlgoAPI_Boolean aFuseAlgo(anObjects, aTools, myBooleanOperationType); + GeomShapePtr aFusedShape; + if(aSolidsToFuse.size() == 1) { + aFusedShape = aSolidsToFuse.front(); + } else if(aSolidsToFuse.size() > 1){ + anObjects.clear(); + anObjects.push_back(aSolidsToFuse.front()); + aSolidsToFuse.pop_front(); + aTools = aSolidsToFuse; + + std::shared_ptr aFuseAlgo(new GeomAlgoAPI_Boolean(anObjects, + aTools, + GeomAlgoAPI_Boolean::BOOL_FUSE)); - // Checking that the algorithm worked properly. - if(!aFuseAlgo.isDone() || aFuseAlgo.shape()->isNull() || !aFuseAlgo.isValid()) { - static const std::string aFeatureError = "Boolean algorithm failed"; - setError(aFeatureError); - return; + // Checking that the algorithm worked properly. + if(!aFuseAlgo->isDone() || aFuseAlgo->shape()->isNull() || !aFuseAlgo->isValid()) { + myFeature->setError("Error: Boolean algorithm failed."); + return false; + } + + aFusedShape = aFuseAlgo->shape(); + aMakeShapeList->appendAlgo(aFuseAlgo); } - std::shared_ptr aShape = aFuseAlgo.shape(); - aMakeShapeList.appendAlgo(aFuseAlgo.makeShape()); - aMapOfShapes.merge(aFuseAlgo.mapOfShapes()); - - // Add result to not used solids from compsolid (if we have any). - if(!aNotUsedSolids.empty()) { - aNotUsedSolids.push_back(aShape); - GeomAlgoAPI_PaveFiller aFillerAlgo(aNotUsedSolids, true); - if(!aFillerAlgo.isDone()) { - std::string aFeatureError = "PaveFiller algorithm failed"; - setError(aFeatureError); - return; + // Combine result with not used solids from compsolid and edges and faces (if we have any). + aShapesToAdd.insert(aShapesToAdd.end(), anEdgesAndFaces.begin(), anEdgesAndFaces.end()); + if(!aShapesToAdd.empty()) { + if(aFusedShape.get()) { + aShapesToAdd.push_back(aFusedShape); } - if(aFillerAlgo.shape()->isNull()) { - static const std::string aShapeError = "Resulting shape is Null"; - setError(aShapeError); - return; - } - if(!aFillerAlgo.isValid()) { - std::string aFeatureError = "Warning: resulting shape is not valid"; - setError(aFeatureError); - return; + + 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; } - aShape = aFillerAlgo.shape(); - aMakeShapeList.appendAlgo(aFillerAlgo.makeShape()); - aMapOfShapes.merge(aFillerAlgo.mapOfShapes()); + aMakeShapeList->appendAlgo(aFillerAlgo); } - std::shared_ptr aResultBody = document()->createBody(data(), aResultIndex); - loadNamingDS(aResultBody, aShells, aSolidsAlgos, anOriginalSolids.front(), anOriginalSolids, aShape, aMakeShapeList, aMapOfShapes); - setResult(aResultBody, aResultIndex); - aResultIndex++; + theMakeShapes.push_back(aMakeShapeList); break; } - default: { - setError("Error: wrong type of boolean operation"); - return; - } } - // Remove the rest results if there were produced in the previous pass. - removeResults(aResultIndex); + return true; } //================================================================================================= -void FeaturesPlugin_CompositeBoolean::loadNamingDS(std::shared_ptr theResultBody, - const ListOfShape& theShells, - const std::list>& theSolidsAlgos, - const std::shared_ptr theBaseShape, - const ListOfShape& theTools, - const std::shared_ptr theResultShape, - GeomAlgoAPI_MakeShape& theMakeShape, - GeomAPI_DataMapOfShapeShape& theMapOfShapes) +void FeaturesPlugin_CompositeBoolean::storeModificationHistory(ResultBodyPtr theResultBody, + const GeomShapePtr theObject, + const ListOfShape& theTools, + const std::shared_ptr theMakeShape, + int& theTag) { - //load result - if(theBaseShape->isEqual(theResultShape)) { - theResultBody->store(theResultShape); - } else { - const int aGenTag = 1; - const int aModTag = 2; - const int aDelTag = 3; - const int aSubsolidsTag=4; /// sub solids will be placed at labels 6, 7, etc. if result is compound of solids - int aToTag = 5; // may be many labels, starting from this index - int aFromTag = 10000; // may be many labels, starting from this index or last aToTag index - const std::string aGenName = "Generated"; - const std::string aModName = "Modified"; - const std::string aLatName = "LateralFace"; - const std::string aFromName = "FromFace"; - const std::string aToName = "ToFace"; - - theResultBody->storeModified(theBaseShape, theResultShape, aSubsolidsTag); - - ListOfShape::const_iterator aShellsIter = theShells.begin(); - std::list>::const_iterator aSolidsAlgosIter = theSolidsAlgos.begin(); - for(; aShellsIter != theShells.end() && aSolidsAlgosIter != theSolidsAlgos.end(); aShellsIter++, aSolidsAlgosIter++) { - ListOfShape aFromFaces; - ListOfShape aToFaces; - std::shared_ptr aSubShapes; - - //Insert lateral face : Face from Edge - if(std::dynamic_pointer_cast(*aSolidsAlgosIter)) { - std::shared_ptr aPrismAlgo = std::dynamic_pointer_cast(*aSolidsAlgosIter); - aSubShapes = aPrismAlgo->mapOfSubShapes(); - theResultBody->loadAndOrientGeneratedShapes(aPrismAlgo.get(), *aShellsIter, GeomAPI_Shape::EDGE, aGenTag, - aLatName, *aSubShapes.get()); - - aFromFaces = aPrismAlgo->fromFaces(); - aToFaces = aPrismAlgo->toFaces(); - } else if(std::dynamic_pointer_cast(*aSolidsAlgosIter)) { - std::shared_ptr aRevolAlgo = std::dynamic_pointer_cast(*aSolidsAlgosIter); - aSubShapes = aRevolAlgo->mapOfSubShapes(); - theResultBody->loadAndOrientGeneratedShapes(aRevolAlgo.get(), *aShellsIter, GeomAPI_Shape::EDGE, aGenTag, - aLatName, *aSubShapes.get()); - aFromFaces = aRevolAlgo->fromFaces(); - aToFaces = aRevolAlgo->toFaces(); - } + int aModTag = theTag; + int anEdgesAndFacesTag = ++aModTag; + int aDelTag = ++anEdgesAndFacesTag; + theTag = aDelTag; - //Insert to faces - for(ListOfShape::const_iterator anIt = aToFaces.cbegin(); anIt != aToFaces.cend(); anIt++) { - std::shared_ptr aToFace = *anIt; - if(aSubShapes->isBound(aToFace)) { - aToFace = aSubShapes->find(aToFace); - } - theResultBody->generated(aToFace, aToName, aToTag++); - } + const std::string aModName = "Modfied"; - //Insert from faces - if (aFromTag < aToTag) aFromTag = aToTag; - for(ListOfShape::const_iterator anIt = aFromFaces.cbegin(); anIt != aFromFaces.cend(); anIt++) { - std::shared_ptr aFromFace = *anIt; - if(aSubShapes->isBound(aFromFace)) { - aFromFace = aSubShapes->find(aFromFace); - } - theResultBody->generated(aFromFace, aFromName, aFromTag++); - } - } + ListOfShape aTools = theTools; + aTools.push_back(theObject); - theResultBody->loadAndOrientModifiedShapes(&theMakeShape, theBaseShape, GeomAPI_Shape::FACE, - aModTag, aModName, theMapOfShapes); - theResultBody->loadDeletedShapes(&theMakeShape, theBaseShape, GeomAPI_Shape::FACE, aDelTag); + std::shared_ptr aMap = theMakeShape->mapOfSubShapes(); - for(ListOfShape::const_iterator anIter = theTools.begin(); anIter != theTools.end(); anIter++) { - theResultBody->loadAndOrientModifiedShapes(&theMakeShape, *anIter, GeomAPI_Shape::FACE, - aModTag, aModName, theMapOfShapes); - theResultBody->loadDeletedShapes(&theMakeShape, *anIter, GeomAPI_Shape::FACE, aDelTag); + int aTag; + std::string aName; + for(ListOfShape::const_iterator anIt = aTools.begin(); anIt != aTools.end(); anIt++) { + if((*anIt)->shapeType() == GeomAPI_Shape::EDGE) { + aTag = anEdgesAndFacesTag; + aName = aModName + "_Edge"; + } + else if((*anIt)->shapeType() == GeomAPI_Shape::FACE) { + aTag = anEdgesAndFacesTag; + aName = aModName + "_Face"; + } else { + aTag = aModTag; + aName = aModName; } + theResultBody->loadAndOrientModifiedShapes(theMakeShape.get(), *anIt, + (*anIt)->shapeType() == GeomAPI_Shape::EDGE ? + GeomAPI_Shape::EDGE : GeomAPI_Shape::FACE, aTag, aName, *aMap.get(), false, false, true); + theResultBody->loadDeletedShapes(theMakeShape.get(), *anIt, GeomAPI_Shape::FACE, aDelTag); } }