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