Salome HOME
Issue #2716: no check that subshapes of the same shape are used for common
[modules/shaper.git] / src / FeaturesPlugin / FeaturesPlugin_Boolean.cpp
1 // Copyright (C) 2014-2017  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or
18 // email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
19 //
20
21 #include "FeaturesPlugin_Boolean.h"
22
23 #include <ModelAPI_Data.h>
24 #include <ModelAPI_Document.h>
25 #include <ModelAPI_AttributeReference.h>
26 #include <ModelAPI_AttributeInteger.h>
27 #include <ModelAPI_ResultBody.h>
28 #include <ModelAPI_AttributeSelectionList.h>
29 #include <ModelAPI_Session.h>
30 #include <ModelAPI_Validator.h>
31 #include <ModelAPI_Tools.h>
32
33 #include <GeomAlgoAPI_Boolean.h>
34 #include <GeomAlgoAPI_MakeShapeCustom.h>
35 #include <GeomAlgoAPI_MakeShapeList.h>
36 #include <GeomAlgoAPI_Partition.h>
37 #include <GeomAlgoAPI_PaveFiller.h>
38 #include <GeomAlgoAPI_ShapeTools.h>
39 #include <GeomAPI_Face.h>
40 #include <GeomAPI_ShapeExplorer.h>
41 #include <GeomAPI_ShapeIterator.h>
42
43 #include <algorithm>
44 #include <map>
45
46 //=================================================================================================
47 FeaturesPlugin_Boolean::FeaturesPlugin_Boolean(const OperationType theOperationType)
48 : myOperationType(theOperationType)
49 {
50 }
51
52 //=================================================================================================
53 void FeaturesPlugin_Boolean::initAttributes()
54 {
55   AttributeSelectionListPtr aSelection =
56     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(data()->addAttribute(
57     FeaturesPlugin_Boolean::OBJECT_LIST_ID(), ModelAPI_AttributeSelectionList::typeId()));
58
59   aSelection = std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(data()->addAttribute(
60     FeaturesPlugin_Boolean::TOOL_LIST_ID(), ModelAPI_AttributeSelectionList::typeId()));
61
62   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), OBJECT_LIST_ID());
63   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), TOOL_LIST_ID());
64 }
65
66 //=================================================================================================
67 std::shared_ptr<GeomAPI_Shape> FeaturesPlugin_Boolean::getShape(const std::string& theAttrName)
68 {
69   std::shared_ptr<ModelAPI_AttributeReference> aObjRef = std::dynamic_pointer_cast<
70       ModelAPI_AttributeReference>(data()->attribute(theAttrName));
71   if (aObjRef) {
72     std::shared_ptr<ModelAPI_ResultBody> aConstr = std::dynamic_pointer_cast<
73         ModelAPI_ResultBody>(aObjRef->value());
74     if (aConstr)
75       return aConstr->shape();
76   }
77   return std::shared_ptr<GeomAPI_Shape>();
78 }
79
80 //=================================================================================================
81 FeaturesPlugin_Boolean::OperationType FeaturesPlugin_Boolean::operationType()
82 {
83   return myOperationType;
84 }
85
86 //=================================================================================================
87 void FeaturesPlugin_Boolean::execute()
88 {
89   ListOfShape anObjects, aTools, anEdgesAndFaces, aPlanes;
90   std::map<std::shared_ptr<GeomAPI_Shape>, ListOfShape> aCompSolidsObjects;
91
92   // Getting objects.
93   AttributeSelectionListPtr anObjectsSelList =
94     selectionList(FeaturesPlugin_Boolean::OBJECT_LIST_ID());
95   for(int anObjectsIndex = 0; anObjectsIndex < anObjectsSelList->size(); anObjectsIndex++) {
96     AttributeSelectionPtr anObjectAttr = anObjectsSelList->value(anObjectsIndex);
97     std::shared_ptr<GeomAPI_Shape> anObject = anObjectAttr->value();
98     if(!anObject.get()) {
99       return;
100     }
101     ResultPtr aContext = anObjectAttr->context();
102     ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
103     if(aResCompSolidPtr.get()
104         && aResCompSolidPtr->shape()->shapeType() == GeomAPI_Shape::COMPSOLID) {
105       std::shared_ptr<GeomAPI_Shape> aContextShape = aResCompSolidPtr->shape();
106       std::map<std::shared_ptr<GeomAPI_Shape>, ListOfShape>::iterator
107         anIt = aCompSolidsObjects.begin();
108       for(; anIt != aCompSolidsObjects.end(); anIt++) {
109         if(anIt->first->isEqual(aContextShape)) {
110           aCompSolidsObjects[anIt->first].push_back(anObject);
111           break;
112         }
113       }
114       if(anIt == aCompSolidsObjects.end()) {
115         aCompSolidsObjects[aContextShape].push_back(anObject);
116       }
117     } else {
118       if(myOperationType != BOOL_FILL
119         && (anObject->shapeType() == GeomAPI_Shape::EDGE
120           || anObject->shapeType() == GeomAPI_Shape::FACE))
121       {
122         anEdgesAndFaces.push_back(anObject);
123       }
124       else
125       {
126         anObjects.push_back(anObject);
127       }
128     }
129   }
130
131   // Getting tools.
132   AttributeSelectionListPtr aToolsSelList = selectionList(FeaturesPlugin_Boolean::TOOL_LIST_ID());
133   for(int aToolsIndex = 0; aToolsIndex < aToolsSelList->size(); aToolsIndex++) {
134     AttributeSelectionPtr aToolAttr = aToolsSelList->value(aToolsIndex);
135     GeomShapePtr aTool = aToolAttr->value();
136     if(!aTool.get()) {
137       // It could be a construction plane.
138       ResultPtr aContext = aToolAttr->context();
139       aPlanes.push_back(aToolAttr->context()->shape());
140     }
141     else if (myOperationType != BOOL_FILL
142       && (aTool->shapeType() == GeomAPI_Shape::EDGE
143         || aTool->shapeType() == GeomAPI_Shape::FACE))
144     {
145       anEdgesAndFaces.push_back(aTool);
146     } else {
147       aTools.push_back(aTool);
148     }
149   }
150
151   int aResultIndex = 0;
152
153   switch(myOperationType) {
154     case BOOL_CUT:
155     case BOOL_COMMON:
156     case BOOL_FILL: {
157       if((anObjects.empty() && aCompSolidsObjects.empty())
158           || (aTools.empty() && aPlanes.empty())) {
159         std::string aFeatureError = "Error: Not enough objects for boolean operation.";
160         setError(aFeatureError);
161         return;
162       }
163
164       // For solids cut each object with all tools.
165       for(ListOfShape::iterator
166           anObjectsIt = anObjects.begin(); anObjectsIt != anObjects.end(); anObjectsIt++) {
167         std::shared_ptr<GeomAPI_Shape> anObject = *anObjectsIt;
168         ListOfShape aListWithObject;
169         aListWithObject.push_back(anObject);
170         std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeShapeList(new GeomAlgoAPI_MakeShapeList());
171         std::shared_ptr<GeomAlgoAPI_MakeShape> aBoolAlgo;
172         GeomShapePtr aResShape;
173
174         switch(myOperationType) {
175           case BOOL_CUT: {
176             aBoolAlgo.reset(new GeomAlgoAPI_Boolean(aListWithObject,
177                                                     aTools,
178                                                     GeomAlgoAPI_Boolean::BOOL_CUT));
179             aResShape = aBoolAlgo->shape();
180             break;
181           }
182           case BOOL_COMMON: {
183             aBoolAlgo.reset(new GeomAlgoAPI_Boolean(aListWithObject,
184                                                     aTools,
185                                                     GeomAlgoAPI_Boolean::BOOL_COMMON));
186             aResShape = aBoolAlgo->shape();
187             break;
188           }
189           case BOOL_FILL: {
190               std::list<std::shared_ptr<GeomAPI_Pnt> > aBoundingPoints =
191                 GeomAlgoAPI_ShapeTools::getBoundingBox(aListWithObject, 1.0);
192
193             // Resize planes.
194             ListOfShape aToolsWithPlanes = aTools;
195             for(ListOfShape::const_iterator anIt = aPlanes.cbegin();
196                                             anIt != aPlanes.cend();
197                                             ++anIt)
198             {
199               GeomShapePtr aPlane = *anIt;
200               GeomShapePtr aTool = GeomAlgoAPI_ShapeTools::fitPlaneToBox(aPlane, aBoundingPoints);
201               std::shared_ptr<GeomAlgoAPI_MakeShapeCustom> aMkShCustom(
202                 new GeomAlgoAPI_MakeShapeCustom);
203               aMkShCustom->addModified(aPlane, aTool);
204               aMakeShapeList->appendAlgo(aMkShCustom);
205               aToolsWithPlanes.push_back(aTool);
206             }
207
208             aBoolAlgo.reset(new GeomAlgoAPI_Partition(aListWithObject, aToolsWithPlanes));
209             aResShape = aBoolAlgo->shape();
210             if (aResShape.get() && aResShape->shapeType() == GeomAPI_Shape::COMPOUND) {
211               int aSubResultsNb = 0;
212               GeomAPI_ShapeIterator anIt(aResShape);
213               for(; anIt.more(); anIt.next()) {
214                 ++aSubResultsNb;
215               }
216               if(aSubResultsNb == 1) {
217                 anIt.init(aResShape);
218                 if(anIt.more()) {
219                   aResShape = anIt.current();
220                 }
221               }
222             }
223             break;
224           }
225         }
226
227         // Checking that the algorithm worked properly.
228         if(!aBoolAlgo->isDone()) {
229           static const std::string aFeatureError = "Error: Boolean algorithm failed.";
230           setError(aFeatureError);
231           return;
232         }
233         if(aResShape->isNull()) {
234           static const std::string aShapeError = "Error: Resulting shape is Null.";
235           setError(aShapeError);
236           return;
237         }
238         if(!aBoolAlgo->isValid()) {
239           std::string aFeatureError = "Error: Resulting shape is not valid.";
240           setError(aFeatureError);
241           return;
242         }
243
244         aMakeShapeList->appendAlgo(aBoolAlgo);
245
246         if(GeomAlgoAPI_ShapeTools::volume(aResShape) > 1.e-27
247            || (myOperationType != BOOL_CUT && myOperationType != BOOL_COMMON))
248         {
249           std::shared_ptr<ModelAPI_ResultBody> aResultBody =
250             document()->createBody(data(), aResultIndex);
251
252           ListOfShape aUsedTools = aTools;
253           if (myOperationType == BOOL_FILL) {
254             aUsedTools.insert(aUsedTools.end(), aPlanes.begin(), aPlanes.end());
255           }
256
257           loadNamingDS(aResultBody, anObject, aUsedTools, aResShape, aMakeShapeList);
258           setResult(aResultBody, aResultIndex);
259           aResultIndex++;
260         }
261       }
262
263       // Compsolids handling
264       for(std::map<std::shared_ptr<GeomAPI_Shape>, ListOfShape>::iterator
265           anIt = aCompSolidsObjects.begin();
266           anIt != aCompSolidsObjects.end(); anIt++) {
267         std::shared_ptr<GeomAPI_Shape> aCompSolid = anIt->first;
268         ListOfShape& aUsedInOperationSolids = anIt->second;
269
270         // Collecting solids from compsolids which will not be modified in boolean operation.
271         ListOfShape aNotUsedSolids;
272         for(GeomAPI_ShapeExplorer
273             anExp(aCompSolid, GeomAPI_Shape::SOLID); anExp.more(); anExp.next()) {
274           std::shared_ptr<GeomAPI_Shape> aSolidInCompSolid = anExp.current();
275           ListOfShape::iterator anIt = aUsedInOperationSolids.begin();
276           for(; anIt != aUsedInOperationSolids.end(); anIt++) {
277             if(aSolidInCompSolid->isEqual(*anIt)) {
278               break;
279             }
280           }
281           if(anIt == aUsedInOperationSolids.end()) {
282             aNotUsedSolids.push_back(aSolidInCompSolid);
283           }
284         }
285
286         std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeShapeList(new GeomAlgoAPI_MakeShapeList());
287         std::shared_ptr<GeomAlgoAPI_MakeShape> aBoolAlgo;
288
289         switch(myOperationType) {
290           case BOOL_CUT: {
291             aBoolAlgo.reset(new GeomAlgoAPI_Boolean(aUsedInOperationSolids,
292                                                     aTools,
293                                                     GeomAlgoAPI_Boolean::BOOL_CUT));
294             break;
295           }
296           case BOOL_COMMON: {
297             aBoolAlgo.reset(new GeomAlgoAPI_Boolean(aUsedInOperationSolids,
298                                                     aTools,
299                                                     GeomAlgoAPI_Boolean::BOOL_COMMON));
300             break;
301           }
302           case BOOL_FILL: {
303             std::list<std::shared_ptr<GeomAPI_Pnt> > aBoundingPoints =
304               GeomAlgoAPI_ShapeTools::getBoundingBox(aUsedInOperationSolids, 1.0);
305
306             // Resize planes.
307             ListOfShape aToolsWithPlanes = aTools;
308             for(ListOfShape::const_iterator anIt = aPlanes.cbegin();
309                                             anIt != aPlanes.cend();
310                                             ++anIt)
311             {
312               GeomShapePtr aPlane = *anIt;
313               GeomShapePtr aTool = GeomAlgoAPI_ShapeTools::fitPlaneToBox(aPlane, aBoundingPoints);
314               std::shared_ptr<GeomAlgoAPI_MakeShapeCustom> aMkShCustom(
315                 new GeomAlgoAPI_MakeShapeCustom);
316               aMkShCustom->addModified(aPlane, aTool);
317               aMakeShapeList->appendAlgo(aMkShCustom);
318               aToolsWithPlanes.push_back(aTool);
319             }
320
321             aBoolAlgo.reset(new GeomAlgoAPI_Partition(aUsedInOperationSolids, aToolsWithPlanes));
322             break;
323           }
324         }
325
326         // Checking that the algorithm worked properly.
327         if(!aBoolAlgo->isDone()) {
328           static const std::string aFeatureError = "Error: Boolean algorithm failed.";
329           setError(aFeatureError);
330           return;
331         }
332         if(aBoolAlgo->shape()->isNull()) {
333           static const std::string aShapeError = "Error: Resulting shape is Null.";
334           setError(aShapeError);
335           return;
336         }
337         if(!aBoolAlgo->isValid()) {
338           std::string aFeatureError = "Error: Resulting shape is not valid.";
339           setError(aFeatureError);
340           return;
341         }
342
343         aMakeShapeList->appendAlgo(aBoolAlgo);
344         GeomShapePtr aResultShape = aBoolAlgo->shape();
345
346         // Add result to not used solids from compsolid.
347         if(!aNotUsedSolids.empty()) {
348           ListOfShape aShapesToAdd = aNotUsedSolids;
349           aShapesToAdd.push_back(aBoolAlgo->shape());
350           std::shared_ptr<GeomAlgoAPI_PaveFiller> aFillerAlgo(
351             new GeomAlgoAPI_PaveFiller(aShapesToAdd, true));
352           if(!aFillerAlgo->isDone()) {
353             std::string aFeatureError = "Error: PaveFiller algorithm failed.";
354             setError(aFeatureError);
355             return;
356           }
357
358           aMakeShapeList->appendAlgo(aFillerAlgo);
359           aResultShape = aFillerAlgo->shape();
360         }
361
362         if(GeomAlgoAPI_ShapeTools::volume(aResultShape) > 1.e-27
363            || (myOperationType != BOOL_CUT && myOperationType != BOOL_COMMON))
364         {
365           std::shared_ptr<ModelAPI_ResultBody> aResultBody =
366             document()->createBody(data(), aResultIndex);
367
368           ListOfShape aUsedTools = aTools;
369           if (myOperationType == BOOL_FILL) {
370             aUsedTools.insert(aUsedTools.end(), aPlanes.begin(), aPlanes.end());
371           }
372
373           loadNamingDS(aResultBody,
374                        aCompSolid,
375                        aUsedTools,
376                        aResultShape,
377                        aMakeShapeList);
378           setResult(aResultBody, aResultIndex);
379           aResultIndex++;
380         }
381       }
382       break;
383     }
384     case BOOL_FUSE: {
385       if((anObjects.size() + aTools.size() +
386           aCompSolidsObjects.size() + anEdgesAndFaces.size()) < 2) {
387         std::string aFeatureError = "Error: Not enough objects for boolean operation.";
388         setError(aFeatureError);
389         return;
390       }
391
392       // Collecting all solids which will be fused.
393       ListOfShape aSolidsToFuse;
394       aSolidsToFuse.insert(aSolidsToFuse.end(), anObjects.begin(), anObjects.end());
395       aSolidsToFuse.insert(aSolidsToFuse.end(), aTools.begin(), aTools.end());
396
397       // Collecting solids from compsolids which will not be modified
398       // in boolean operation and will be added to result.
399       ListOfShape aShapesToAdd;
400       for(std::map<std::shared_ptr<GeomAPI_Shape>, ListOfShape>::iterator
401           anIt = aCompSolidsObjects.begin();
402           anIt != aCompSolidsObjects.end(); anIt++) {
403         std::shared_ptr<GeomAPI_Shape> aCompSolid = anIt->first;
404         ListOfShape& aUsedInOperationSolids = anIt->second;
405         aSolidsToFuse.insert(aSolidsToFuse.end(), aUsedInOperationSolids.begin(),
406                              aUsedInOperationSolids.end());
407
408         // Collect solids from compsolid which will not be modified in boolean operation.
409         for(GeomAPI_ShapeExplorer
410             anExp(aCompSolid, GeomAPI_Shape::SOLID); anExp.more(); anExp.next()) {
411           std::shared_ptr<GeomAPI_Shape> aSolidInCompSolid = anExp.current();
412           ListOfShape::iterator anIt = aUsedInOperationSolids.begin();
413           for(; anIt != aUsedInOperationSolids.end(); anIt++) {
414             if(aSolidInCompSolid->isEqual(*anIt)) {
415               break;
416             }
417           }
418           if(anIt == aUsedInOperationSolids.end()) {
419             aShapesToAdd.push_back(aSolidInCompSolid);
420           }
421         }
422       }
423
424       ListOfShape anOriginalShapes = aSolidsToFuse;
425       anOriginalShapes.insert(anOriginalShapes.end(), aShapesToAdd.begin(), aShapesToAdd.end());
426
427       // Cut edges and faces(if we have any) with solids.
428       std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeShapeList(new GeomAlgoAPI_MakeShapeList());
429       std::shared_ptr<GeomAPI_Shape> aCuttedEdgesAndFaces;
430       if(!anEdgesAndFaces.empty()) {
431         std::shared_ptr<GeomAlgoAPI_Boolean> aCutAlgo(new GeomAlgoAPI_Boolean(anEdgesAndFaces,
432                                             anOriginalShapes, GeomAlgoAPI_Boolean::BOOL_CUT));
433         if(aCutAlgo->isDone()) {
434           aCuttedEdgesAndFaces = aCutAlgo->shape();
435           aMakeShapeList->appendAlgo(aCutAlgo);
436         }
437       }
438       anOriginalShapes.insert(anOriginalShapes.end(), anEdgesAndFaces.begin(),
439                               anEdgesAndFaces.end());
440
441       // If we have compsolids then cut with not used solids all others.
442       if(!aShapesToAdd.empty()) {
443         aSolidsToFuse.clear();
444         for(ListOfShape::iterator
445             anIt = anOriginalShapes.begin(); anIt != anOriginalShapes.end(); anIt++) {
446           ListOfShape aOneObjectList;
447           aOneObjectList.push_back(*anIt);
448           std::shared_ptr<GeomAlgoAPI_Boolean> aCutAlgo(
449             new GeomAlgoAPI_Boolean(aOneObjectList, aShapesToAdd, GeomAlgoAPI_Boolean::BOOL_CUT));
450
451           if(GeomAlgoAPI_ShapeTools::volume(aCutAlgo->shape()) > 1.e-27) {
452             aSolidsToFuse.push_back(aCutAlgo->shape());
453             aMakeShapeList->appendAlgo(aCutAlgo);
454           }
455         }
456       }
457
458       if(!aSolidsToFuse.empty()) {
459         anObjects.clear();
460         anObjects.push_back(aSolidsToFuse.back());
461         aSolidsToFuse.pop_back();
462         aTools = aSolidsToFuse;
463       }
464
465       // Fuse all objects and all tools.
466       std::shared_ptr<GeomAPI_Shape> aShape;
467       if(anObjects.size() == 1 && aTools.empty()) {
468         aShape = anObjects.front();
469       } else if(anObjects.empty() && aTools.size() == 1) {
470         aShape = aTools.front();
471       } else if((anObjects.size() + aTools.size()) > 1){
472         std::shared_ptr<GeomAlgoAPI_Boolean> aFuseAlgo(new GeomAlgoAPI_Boolean(anObjects,
473                                                                 aTools,
474                                                                 GeomAlgoAPI_Boolean::BOOL_FUSE));
475
476         // Checking that the algorithm worked properly.
477         if(!aFuseAlgo->isDone()) {
478           static const std::string aFeatureError = "Error: Boolean algorithm failed.";
479           setError(aFeatureError);
480           return;
481         }
482         if(aFuseAlgo->shape()->isNull()) {
483           static const std::string aShapeError = "Error: Resulting shape is Null.";
484           setError(aShapeError);
485           return;
486         }
487         if(!aFuseAlgo->isValid()) {
488           std::string aFeatureError = "Error: Resulting shape is not valid.";
489           setError(aFeatureError);
490           return;
491         }
492
493         aShape = aFuseAlgo->shape();
494         aMakeShapeList->appendAlgo(aFuseAlgo);
495       }
496
497       // Combine result with not used solids from compsolid and edges and faces (if we have any).
498       if(aCuttedEdgesAndFaces.get() && !aCuttedEdgesAndFaces->isNull()) {
499         aShapesToAdd.push_back(aCuttedEdgesAndFaces);
500       } else {
501         aShapesToAdd.insert(aShapesToAdd.end(), anEdgesAndFaces.begin(), anEdgesAndFaces.end());
502       }
503       if(!aShapesToAdd.empty()) {
504         if(aShape.get()) {
505           aShapesToAdd.push_back(aShape);
506         }
507         std::shared_ptr<GeomAlgoAPI_PaveFiller> aFillerAlgo(
508           new GeomAlgoAPI_PaveFiller(aShapesToAdd, true));
509         if(!aFillerAlgo->isDone()) {
510           std::string aFeatureError = "Error: PaveFiller algorithm failed.";
511           setError(aFeatureError);
512           return;
513         }
514         if(aFillerAlgo->shape()->isNull()) {
515           static const std::string aShapeError = "Error: Resulting shape is Null.";
516           setError(aShapeError);
517           return;
518         }
519         if(!aFillerAlgo->isValid()) {
520           std::string aFeatureError = "Error: Resulting shape is not valid.";
521           setError(aFeatureError);
522           return;
523         }
524
525         aShape = aFillerAlgo->shape();
526         aMakeShapeList->appendAlgo(aFillerAlgo);
527       }
528
529       std::shared_ptr<GeomAPI_Shape> aBackShape = anOriginalShapes.back();
530       anOriginalShapes.pop_back();
531       std::shared_ptr<ModelAPI_ResultBody> aResultBody =
532         document()->createBody(data(), aResultIndex);
533       loadNamingDS(aResultBody, aBackShape, anOriginalShapes,
534                    aShape, aMakeShapeList);
535       setResult(aResultBody, aResultIndex);
536       aResultIndex++;
537       break;
538     }
539     case BOOL_SMASH: {
540       if((anObjects.empty() && aCompSolidsObjects.empty()) || aTools.empty()) {
541         std::string aFeatureError = "Error: Not enough objects for boolean operation.";
542         setError(aFeatureError);
543         return;
544       }
545
546       // List of original solids for naming.
547       ListOfShape anOriginalShapes;
548       anOriginalShapes.insert(anOriginalShapes.end(), anObjects.begin(), anObjects.end());
549       anOriginalShapes.insert(anOriginalShapes.end(), aTools.begin(), aTools.end());
550
551       // Collecting all solids which will be smashed.
552       ListOfShape aShapesToSmash;
553       aShapesToSmash.insert(aShapesToSmash.end(), anObjects.begin(), anObjects.end());
554
555       // Collecting solids from compsolids which will not be modified in
556       // boolean operation and will be added to result.
557       ListOfShape aShapesToAdd;
558       for(std::map<std::shared_ptr<GeomAPI_Shape>, ListOfShape>::iterator
559         anIt = aCompSolidsObjects.begin();
560         anIt != aCompSolidsObjects.end(); anIt++) {
561         std::shared_ptr<GeomAPI_Shape> aCompSolid = anIt->first;
562         ListOfShape& aUsedInOperationSolids = anIt->second;
563         anOriginalShapes.push_back(aCompSolid);
564         aShapesToSmash.insert(aShapesToSmash.end(), aUsedInOperationSolids.begin(),
565                               aUsedInOperationSolids.end());
566
567         // Collect solids from compsolid which will not be modified in boolean operation.
568         for(GeomAPI_ShapeExplorer
569             anExp(aCompSolid, GeomAPI_Shape::SOLID); anExp.more(); anExp.next()) {
570           std::shared_ptr<GeomAPI_Shape> aSolidInCompSolid = anExp.current();
571           ListOfShape::iterator anIt = aUsedInOperationSolids.begin();
572           for(; anIt != aUsedInOperationSolids.end(); anIt++) {
573             if(aSolidInCompSolid->isEqual(*anIt)) {
574               break;
575             }
576           }
577           if(anIt == aUsedInOperationSolids.end()) {
578             aShapesToAdd.push_back(aSolidInCompSolid);
579           }
580         }
581       }
582
583       std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeShapeList;
584       if(!aShapesToAdd.empty()) {
585         // Cut objects with not used solids.
586         std::shared_ptr<GeomAlgoAPI_Boolean> anObjectsCutAlgo(new GeomAlgoAPI_Boolean(
587                                                               aShapesToSmash,
588                                                               aShapesToAdd,
589                                                               GeomAlgoAPI_Boolean::BOOL_CUT));
590
591         if(GeomAlgoAPI_ShapeTools::volume(anObjectsCutAlgo->shape()) > 1.e-27) {
592           aShapesToSmash.clear();
593           aShapesToSmash.push_back(anObjectsCutAlgo->shape());
594           aMakeShapeList->appendAlgo(anObjectsCutAlgo);
595         }
596
597         // Cut tools with not used solids.
598         std::shared_ptr<GeomAlgoAPI_Boolean> aToolsCutAlgo(new GeomAlgoAPI_Boolean(aTools,
599                                                               aShapesToAdd,
600                                                               GeomAlgoAPI_Boolean::BOOL_CUT));
601
602         if(GeomAlgoAPI_ShapeTools::volume(aToolsCutAlgo->shape()) > 1.e-27) {
603           aTools.clear();
604           aTools.push_back(aToolsCutAlgo->shape());
605           aMakeShapeList->appendAlgo(aToolsCutAlgo);
606         }
607       }
608
609       // Cut objects with tools.
610       std::shared_ptr<GeomAlgoAPI_Boolean> aBoolAlgo(new GeomAlgoAPI_Boolean(aShapesToSmash,
611                                                                 aTools,
612                                                                 GeomAlgoAPI_Boolean::BOOL_CUT));
613
614       // Checking that the algorithm worked properly.
615       if(!aBoolAlgo->isDone()) {
616         static const std::string aFeatureError = "Error: Boolean algorithm failed.";
617         setError(aFeatureError);
618         return;
619       }
620       if(aBoolAlgo->shape()->isNull()) {
621         static const std::string aShapeError = "Error: Resulting shape is Null.";
622         setError(aShapeError);
623         return;
624       }
625       if(!aBoolAlgo->isValid()) {
626         std::string aFeatureError = "Error: Resulting shape is not valid.";
627         setError(aFeatureError);
628         return;
629       }
630       aMakeShapeList->appendAlgo(aBoolAlgo);
631
632       // Put all (cut result, tools and not used solids) to PaveFiller.
633       aShapesToAdd.push_back(aBoolAlgo->shape());
634       aShapesToAdd.insert(aShapesToAdd.end(), aTools.begin(), aTools.end());
635
636       std::shared_ptr<GeomAlgoAPI_PaveFiller> aFillerAlgo(new GeomAlgoAPI_PaveFiller(aShapesToAdd,
637                                                                                      true));
638       if(!aFillerAlgo->isDone()) {
639         std::string aFeatureError = "Error: PaveFiller algorithm failed.";
640         setError(aFeatureError);
641         return;
642       }
643       if(aFillerAlgo->shape()->isNull()) {
644         static const std::string aShapeError = "Error: Resulting shape is Null.";
645         setError(aShapeError);
646         return;
647       }
648       if(!aFillerAlgo->isValid()) {
649         std::string aFeatureError = "Error: Resulting shape is not valid.";
650         setError(aFeatureError);
651         return;
652       }
653
654       std::shared_ptr<GeomAPI_Shape> aShape = aFillerAlgo->shape();
655       aMakeShapeList->appendAlgo(aFillerAlgo);
656
657       std::shared_ptr<GeomAPI_Shape> aFrontShape = anOriginalShapes.front();
658       anOriginalShapes.pop_front();
659       std::shared_ptr<ModelAPI_ResultBody> aResultBody =
660         document()->createBody(data(), aResultIndex);
661       loadNamingDS(aResultBody, aFrontShape, anOriginalShapes, aShape, aMakeShapeList);
662       setResult(aResultBody, aResultIndex);
663       aResultIndex++;
664
665       break;
666     }
667     default: {
668       std::string anOperationError = "Error: Wrong type of operation";
669       setError(anOperationError);
670       return;
671     }
672   }
673   // remove the rest results if there were produced in the previous pass
674   removeResults(aResultIndex);
675 }
676
677 //=================================================================================================
678 void FeaturesPlugin_Boolean::loadNamingDS(std::shared_ptr<ModelAPI_ResultBody> theResultBody,
679                                           const std::shared_ptr<GeomAPI_Shape> theBaseShape,
680                                           const ListOfShape& theTools,
681                                           const std::shared_ptr<GeomAPI_Shape> theResultShape,
682                                           const GeomMakeShapePtr& theMakeShape)
683 {
684   //load result
685   if(theBaseShape->isEqual(theResultShape)) {
686     theResultBody->store(theResultShape, false);
687     return;
688   }
689
690   theResultBody->storeModified(theBaseShape, theResultShape);
691
692   theResultBody->loadModifiedShapes(theMakeShape, theBaseShape, GeomAPI_Shape::EDGE);
693   theResultBody->loadModifiedShapes(theMakeShape, theBaseShape, GeomAPI_Shape::FACE);
694
695   theResultBody->loadDeletedShapes(theMakeShape, theBaseShape, GeomAPI_Shape::FACE);
696
697   for (ListOfShape::const_iterator anIter = theTools.begin();
698        anIter != theTools.end();
699        ++anIter)
700   {
701     GeomAPI_Shape::ShapeType aShapeType =
702       (*anIter)->shapeType() <= GeomAPI_Shape::FACE ? GeomAPI_Shape::FACE
703                                                     : GeomAPI_Shape::EDGE;
704     theResultBody->loadModifiedShapes(theMakeShape, *anIter, aShapeType);
705
706     theResultBody->loadDeletedShapes(theMakeShape, *anIter, GeomAPI_Shape::FACE);
707   }
708 }