1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
3 // File: FeaturesPlugin_CompositeBoolean.cpp
4 // Created: 11 June 2015
5 // Author: Dmitry Bobylev
7 #include "FeaturesPlugin_CompositeBoolean.h"
9 #include <ModelAPI_AttributeSelectionList.h>
10 #include <ModelAPI_ResultCompSolid.h>
11 #include <ModelAPI_Tools.h>
13 #include <GeomAlgoAPI_Boolean.h>
14 #include <GeomAlgoAPI_MakeShapeList.h>
15 #include <GeomAlgoAPI_PaveFiller.h>
16 #include <GeomAlgoAPI_ShapeTools.h>
18 #include <GeomAPI_ShapeExplorer.h>
22 //=================================================================================================
23 void FeaturesPlugin_CompositeBoolean::initBooleanAttributes()
25 myFeature->data()->addAttribute(OBJECTS_ID(), ModelAPI_AttributeSelectionList::typeId());
28 //=================================================================================================
29 void FeaturesPlugin_CompositeBoolean::executeCompositeBoolean()
32 ListOfShape aGenBaseShapes;
33 ListOfMakeShape aGenMakeShapes;
34 if(!makeGeneration(aGenBaseShapes, aGenMakeShapes)) {
40 for(ListOfMakeShape::const_iterator
41 anIt = aGenMakeShapes.cbegin(); anIt != aGenMakeShapes.cend(); ++anIt) {
42 aTools.push_back((*anIt)->shape());
46 ListOfShape aBooleanObjects;
47 ListOfMakeShape aBooleanMakeShapes;
48 if(!makeBoolean(aTools, aBooleanObjects, aBooleanMakeShapes)) {
52 if(myOperationType == BOOL_FUSE) {
53 aTools.splice(aTools.begin(), aBooleanObjects);
54 aBooleanObjects.splice(aBooleanObjects.begin(), aTools, aTools.begin());
59 ListOfShape::const_iterator aBoolObjIt = aBooleanObjects.cbegin();
60 ListOfMakeShape::const_iterator aBoolMSIt = aBooleanMakeShapes.cbegin();
61 for(; aBoolObjIt != aBooleanObjects.cend() && aBoolMSIt != aBooleanMakeShapes.cend();
62 ++aBoolObjIt, ++aBoolMSIt) {
66 ResultBodyPtr aResultBody = myFeature->document()->createBody(myFeature->data(), aResultIndex);
67 aResultBody->storeModified(*aBoolObjIt, (*aBoolMSIt)->shape(), aTag);
71 // Store generation history.
72 ListOfShape::const_iterator aGenBaseIt = aGenBaseShapes.cbegin();
73 ListOfMakeShape::const_iterator aGenMSIt = aGenMakeShapes.cbegin();
74 for(; aGenBaseIt != aGenBaseShapes.cend() && aGenMSIt != aGenMakeShapes.cend();
75 ++aGenBaseIt, ++aGenMSIt) {
76 storeGenerationHistory(aResultBody, *aGenBaseIt, *aGenMSIt, aTag);
80 storeModificationHistory(aResultBody, *aBoolObjIt, aTools, *aBoolMSIt, aModTag);
82 myFeature->setResult(aResultBody, aResultIndex++);
85 myFeature->removeResults(aResultIndex);
88 //=================================================================================================
89 bool FeaturesPlugin_CompositeBoolean::makeBoolean(const ListOfShape& theTools,
90 ListOfShape& theObjects,
91 ListOfMakeShape& theMakeShapes)
94 ListOfShape anObjects, anEdgesAndFaces, aCompSolids;
95 std::map<GeomShapePtr, ListOfShape> aCompSolidsObjects;
96 AttributeSelectionListPtr anObjectsSelList = myFeature->selectionList(OBJECTS_ID());
97 for(int anObjectsIndex = 0; anObjectsIndex < anObjectsSelList->size(); anObjectsIndex++) {
98 AttributeSelectionPtr anObjectAttr = anObjectsSelList->value(anObjectsIndex);
99 GeomShapePtr anObject = anObjectAttr->value();
100 if(!anObject.get()) {
101 myFeature->setError("Error: Could not get object.");
104 ResultPtr aContext = anObjectAttr->context();
105 ResultCompSolidPtr aResCompSolidPtr = ModelAPI_Tools::compSolidOwner(aContext);
106 if(aResCompSolidPtr.get()) {
107 GeomShapePtr aContextShape = aResCompSolidPtr->shape();
108 std::map<GeomShapePtr, ListOfShape>::iterator anIt = aCompSolidsObjects.begin();
109 for(; anIt != aCompSolidsObjects.end(); anIt++) {
110 if(anIt->first->isEqual(aContextShape)) {
111 aCompSolidsObjects[anIt->first].push_back(anObject);
115 if(anIt == aCompSolidsObjects.end()) {
116 aCompSolidsObjects[aContextShape].push_back(anObject);
117 aCompSolids.push_back(aContextShape);
120 if(anObject->shapeType() == GeomAPI_Shape::EDGE ||
121 anObject->shapeType() == GeomAPI_Shape::FACE) {
122 anEdgesAndFaces.push_back(anObject);
124 anObjects.push_back(anObject);
129 switch(myOperationType) {
131 if((anObjects.empty() && aCompSolidsObjects.empty()) || theTools.empty()) {
132 myFeature->setError("Error: Not enough objects for boolean operation.");
136 // For solids cut each object with all tools.
137 for(ListOfShape::const_iterator
138 anIt = anObjects.cbegin(); anIt != anObjects.cend(); ++anIt) {
139 GeomShapePtr anObject = *anIt;
140 ListOfShape aListWithObject;
141 aListWithObject.push_back(anObject);
142 std::shared_ptr<GeomAlgoAPI_Boolean> aBoolAlgo(new GeomAlgoAPI_Boolean(aListWithObject,
144 GeomAlgoAPI_Boolean::BOOL_CUT));
146 // Checking that the algorithm worked properly.
147 if(!aBoolAlgo->isDone() || aBoolAlgo->shape()->isNull() || !aBoolAlgo->isValid()) {
148 myFeature->setError("Error: Boolean algorithm failed.");
152 if(GeomAlgoAPI_ShapeTools::volume(aBoolAlgo->shape()) > 1.e-27) {
153 theObjects.push_back(anObject);
154 theMakeShapes.push_back(aBoolAlgo);
158 // Compsolids handling
159 for(std::map<GeomShapePtr, ListOfShape>::const_iterator anIt = aCompSolidsObjects.cbegin();
160 anIt != aCompSolidsObjects.cend(); ++anIt) {
161 GeomShapePtr aCompSolid = anIt->first;
162 const ListOfShape& aUsedShapes = anIt->second;
164 // Collecting solids from compsolids which will not be modified in boolean operation.
165 ListOfShape aShapesToAdd;
166 for(GeomAPI_ShapeExplorer
167 anExp(aCompSolid, GeomAPI_Shape::SOLID); anExp.more(); anExp.next()) {
168 GeomShapePtr aSolidInCompSolid = anExp.current();
169 ListOfShape::const_iterator aUsedShapesIt = aUsedShapes.cbegin();
170 for(; aUsedShapesIt != aUsedShapes.cend(); ++aUsedShapesIt) {
171 if(aSolidInCompSolid->isEqual(*aUsedShapesIt)) {
175 if(aUsedShapesIt == aUsedShapes.end()) {
176 aShapesToAdd.push_back(aSolidInCompSolid);
180 std::shared_ptr<GeomAlgoAPI_Boolean> aBoolAlgo(new GeomAlgoAPI_Boolean(aUsedShapes,
182 GeomAlgoAPI_Boolean::BOOL_CUT));
184 // Checking that the algorithm worked properly.
185 if(!aBoolAlgo->isDone() || aBoolAlgo->shape()->isNull() || !aBoolAlgo->isValid()) {
186 myFeature->setError("Error: Boolean algorithm failed.");
190 std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeShapeList(new GeomAlgoAPI_MakeShapeList());
191 aMakeShapeList->appendAlgo(aBoolAlgo);
193 // Add result to not used solids from compsolid.
194 aShapesToAdd.push_back(aBoolAlgo->shape());
195 std::shared_ptr<GeomAlgoAPI_PaveFiller> aFillerAlgo(
196 new GeomAlgoAPI_PaveFiller(aShapesToAdd, true));
197 if(!aFillerAlgo->isDone() || aFillerAlgo->shape()->isNull() || !aFillerAlgo->isValid()) {
198 myFeature->setError("Error: PaveFiller algorithm failed.");
202 aMakeShapeList->appendAlgo(aFillerAlgo);
204 if(GeomAlgoAPI_ShapeTools::volume(aFillerAlgo->shape()) > 1.e-27) {
205 theObjects.push_back(aCompSolid);
206 theMakeShapes.push_back(aMakeShapeList);
213 theObjects.insert(theObjects.end(), anEdgesAndFaces.begin(), anEdgesAndFaces.end());
214 theObjects.insert(theObjects.end(), anObjects.begin(), anObjects.end());
215 theObjects.insert(theObjects.end(), aCompSolids.begin(), aCompSolids.end());
217 // Filter edges and faces in tools.
219 for(ListOfShape::const_iterator anIt = theTools.cbegin(); anIt != theTools.cend(); ++anIt) {
220 if((*anIt)->shapeType() == GeomAPI_Shape::EDGE ||
221 (*anIt)->shapeType() == GeomAPI_Shape::FACE) {
222 anEdgesAndFaces.push_back(*anIt);
224 aTools.push_back(*anIt);
228 if((anObjects.size() + aTools.size() +
229 aCompSolidsObjects.size() + anEdgesAndFaces.size()) < 2) {
230 myFeature->setError("Error: Not enough objects for boolean operation.");
234 // Collecting all solids which will be fused.
235 ListOfShape aSolidsToFuse;
236 aSolidsToFuse.insert(aSolidsToFuse.end(), anObjects.begin(), anObjects.end());
237 aSolidsToFuse.insert(aSolidsToFuse.end(), aTools.begin(), aTools.end());
239 // Collecting solids from compsolids which will not be
240 // modified in boolean operation and will be added to result.
241 ListOfShape aShapesToAdd;
242 for(std::map<GeomShapePtr, ListOfShape>::iterator anIt = aCompSolidsObjects.begin();
243 anIt != aCompSolidsObjects.end(); anIt++) {
244 GeomShapePtr aCompSolid = anIt->first;
245 ListOfShape& aUsedShapes = anIt->second;
246 aSolidsToFuse.insert(aSolidsToFuse.end(), aUsedShapes.begin(), aUsedShapes.end());
248 // Collect solids from compsolid which will not be modified in boolean operation.
249 for(GeomAPI_ShapeExplorer
250 anExp(aCompSolid, GeomAPI_Shape::SOLID); anExp.more(); anExp.next()) {
251 GeomShapePtr aSolidInCompSolid = anExp.current();
252 ListOfShape::iterator anIt = aUsedShapes.begin();
253 for(; anIt != aUsedShapes.end(); anIt++) {
254 if(aSolidInCompSolid->isEqual(*anIt)) {
258 if(anIt == aUsedShapes.end()) {
259 aShapesToAdd.push_back(aSolidInCompSolid);
264 // Cut edges and faces(if we have any) with solids.
265 ListOfShape aCutTools;
266 aCutTools.insert(aCutTools.end(), anObjects.begin(), anObjects.end());
267 aCutTools.insert(aCutTools.end(), aCompSolids.begin(), aCompSolids.end());
268 aCutTools.insert(aCutTools.end(), aTools.begin(), aTools.end());
270 std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeShapeList(new GeomAlgoAPI_MakeShapeList());
271 if(!anEdgesAndFaces.empty() && !aCutTools.empty()) {
272 std::shared_ptr<GeomAlgoAPI_Boolean> aCutAlgo(new GeomAlgoAPI_Boolean(anEdgesAndFaces,
274 GeomAlgoAPI_Boolean::BOOL_CUT));
275 if(aCutAlgo->isDone() && !aCutAlgo->shape()->isNull() && aCutAlgo->isValid()) {
276 anEdgesAndFaces.clear();
277 anEdgesAndFaces.push_back(aCutAlgo->shape());
278 aMakeShapeList->appendAlgo(aCutAlgo);
282 // If we have compsolids then cut with not used solids all others.
283 if(!aShapesToAdd.empty()) {
284 std::shared_ptr<GeomAlgoAPI_Boolean> aCutAlgo(new GeomAlgoAPI_Boolean(aSolidsToFuse,
286 GeomAlgoAPI_Boolean::BOOL_CUT));
287 if(aCutAlgo->isDone() && GeomAlgoAPI_ShapeTools::volume(aCutAlgo->shape()) > 1.e-27) {
288 aSolidsToFuse.clear();
289 aSolidsToFuse.push_back(aCutAlgo->shape());
290 aMakeShapeList->appendAlgo(aCutAlgo);
294 // Fuse all objects and all tools.
295 GeomShapePtr aFusedShape;
296 if(aSolidsToFuse.size() == 1) {
297 aFusedShape = aSolidsToFuse.front();
298 } else if(aSolidsToFuse.size() > 1){
300 anObjects.push_back(aSolidsToFuse.front());
301 aSolidsToFuse.pop_front();
302 aTools = aSolidsToFuse;
304 std::shared_ptr<GeomAlgoAPI_Boolean> aFuseAlgo(new GeomAlgoAPI_Boolean(anObjects,
306 GeomAlgoAPI_Boolean::BOOL_FUSE));
308 // Checking that the algorithm worked properly.
309 if(!aFuseAlgo->isDone() || aFuseAlgo->shape()->isNull() || !aFuseAlgo->isValid()) {
310 myFeature->setError("Error: Boolean algorithm failed.");
314 aFusedShape = aFuseAlgo->shape();
315 aMakeShapeList->appendAlgo(aFuseAlgo);
318 // Combine result with not used solids from compsolid and edges and faces (if we have any).
319 aShapesToAdd.insert(aShapesToAdd.end(), anEdgesAndFaces.begin(), anEdgesAndFaces.end());
320 if(!aShapesToAdd.empty()) {
321 if(aFusedShape.get()) {
322 aShapesToAdd.push_back(aFusedShape);
325 std::shared_ptr<GeomAlgoAPI_PaveFiller> aFillerAlgo(
326 new GeomAlgoAPI_PaveFiller(aShapesToAdd, true));
327 if(!aFillerAlgo->isDone() || aFillerAlgo->shape()->isNull() || !aFillerAlgo->isValid()) {
328 myFeature->setError("Error: PaveFiller algorithm failed.");
332 aMakeShapeList->appendAlgo(aFillerAlgo);
335 theMakeShapes.push_back(aMakeShapeList);
343 //=================================================================================================
344 void FeaturesPlugin_CompositeBoolean::storeModificationHistory(ResultBodyPtr theResultBody,
345 const GeomShapePtr theObject,
346 const ListOfShape& theTools,
347 const std::shared_ptr<GeomAlgoAPI_MakeShape> theMakeShape,
350 int aModTag = theTag;
351 int anEdgesAndFacesTag = ++aModTag;
352 int aDelTag = ++anEdgesAndFacesTag;
355 const std::string aModName = "Modfied";
357 ListOfShape aTools = theTools;
358 aTools.push_back(theObject);
360 std::shared_ptr<GeomAPI_DataMapOfShapeShape> aMap = theMakeShape->mapOfSubShapes();
364 for(ListOfShape::const_iterator anIt = aTools.begin(); anIt != aTools.end(); anIt++) {
365 if((*anIt)->shapeType() == GeomAPI_Shape::EDGE) {
366 aTag = anEdgesAndFacesTag;
367 aName = aModName + "_Edge";
369 else if((*anIt)->shapeType() == GeomAPI_Shape::FACE) {
370 aTag = anEdgesAndFacesTag;
371 aName = aModName + "_Face";
376 theResultBody->loadAndOrientModifiedShapes(theMakeShape.get(), *anIt,
377 (*anIt)->shapeType() == GeomAPI_Shape::EDGE ?
378 GeomAPI_Shape::EDGE : GeomAPI_Shape::FACE, aTag, aName, *aMap.get());
379 theResultBody->loadDeletedShapes(theMakeShape.get(), *anIt, GeomAPI_Shape::FACE, aDelTag);