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