]> SALOME platform Git repositories - modules/shaper.git/blob - src/FeaturesPlugin/FeaturesPlugin_Boolean.cpp
Salome HOME
37cecf7af1755b4366c65b3d8ee1bb9fc749444f
[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           std::shared_ptr<ModelAPI_ResultBody> aResultBody =
251             document()->createBody(data(), aResultIndex);
252
253           ListOfShape aUsedTools = aTools;
254           if (aType == BOOL_FILL) {
255             aUsedTools.insert(aUsedTools.end(), aPlanes.begin(), aPlanes.end());
256           }
257
258           loadNamingDS(aResultBody, anObject, aUsedTools, aResShape,
259                        aMakeShapeList, *(aBoolAlgo->mapOfSubShapes()), aType == BOOL_FILL);
260           setResult(aResultBody, aResultIndex);
261           aResultIndex++;
262         }
263       }
264
265       // Compsolids handling
266       for(std::map<std::shared_ptr<GeomAPI_Shape>, ListOfShape>::iterator
267           anIt = aCompSolidsObjects.begin();
268           anIt != aCompSolidsObjects.end(); anIt++) {
269         std::shared_ptr<GeomAPI_Shape> aCompSolid = anIt->first;
270         ListOfShape& aUsedInOperationSolids = anIt->second;
271
272         // Collecting solids from compsolids which will not be modified in boolean operation.
273         ListOfShape aNotUsedSolids;
274         for(GeomAPI_ShapeExplorer
275             anExp(aCompSolid, GeomAPI_Shape::SOLID); anExp.more(); anExp.next()) {
276           std::shared_ptr<GeomAPI_Shape> aSolidInCompSolid = anExp.current();
277           ListOfShape::iterator anIt = aUsedInOperationSolids.begin();
278           for(; anIt != aUsedInOperationSolids.end(); anIt++) {
279             if(aSolidInCompSolid->isEqual(*anIt)) {
280               break;
281             }
282           }
283           if(anIt == aUsedInOperationSolids.end()) {
284             aNotUsedSolids.push_back(aSolidInCompSolid);
285           }
286         }
287
288         GeomAlgoAPI_MakeShapeList aMakeShapeList;
289         std::shared_ptr<GeomAlgoAPI_MakeShape> aBoolAlgo;
290
291         switch(aType) {
292           case BOOL_CUT: {
293             aBoolAlgo.reset(new GeomAlgoAPI_Boolean(aUsedInOperationSolids,
294                                                     aTools,
295                                                     GeomAlgoAPI_Boolean::BOOL_CUT));
296             break;
297           }
298           case BOOL_COMMON: {
299             aBoolAlgo.reset(new GeomAlgoAPI_Boolean(aUsedInOperationSolids,
300                                                     aTools,
301                                                     GeomAlgoAPI_Boolean::BOOL_COMMON));
302             break;
303           }
304           case BOOL_FILL: {
305             std::list<std::shared_ptr<GeomAPI_Pnt> > aBoundingPoints =
306               GeomAlgoAPI_ShapeTools::getBoundingBox(aUsedInOperationSolids, 1.0);
307
308             // Resize planes.
309             ListOfShape aToolsWithPlanes = aTools;
310             for(ListOfShape::const_iterator anIt = aPlanes.cbegin();
311                                             anIt != aPlanes.cend();
312                                             ++anIt)
313             {
314               GeomShapePtr aPlane = *anIt;
315               GeomShapePtr aTool = GeomAlgoAPI_ShapeTools::fitPlaneToBox(aPlane, aBoundingPoints);
316               std::shared_ptr<GeomAlgoAPI_MakeShapeCustom> aMkShCustom(
317                 new GeomAlgoAPI_MakeShapeCustom);
318               aMkShCustom->addModified(aPlane, aTool);
319               aMakeShapeList.appendAlgo(aMkShCustom);
320               aToolsWithPlanes.push_back(aTool);
321             }
322
323             aBoolAlgo.reset(new GeomAlgoAPI_Partition(aUsedInOperationSolids, aToolsWithPlanes));
324             break;
325           }
326         }
327
328         // Checking that the algorithm worked properly.
329         if(!aBoolAlgo->isDone()) {
330           static const std::string aFeatureError = "Error: Boolean algorithm failed.";
331           setError(aFeatureError);
332           return;
333         }
334         if(aBoolAlgo->shape()->isNull()) {
335           static const std::string aShapeError = "Error: Resulting shape is Null.";
336           setError(aShapeError);
337           return;
338         }
339         if(!aBoolAlgo->isValid()) {
340           std::string aFeatureError = "Error: Resulting shape is not valid.";
341           setError(aFeatureError);
342           return;
343         }
344
345         aMakeShapeList.appendAlgo(aBoolAlgo);
346         GeomAPI_DataMapOfShapeShape aMapOfShapes;
347         aMapOfShapes.merge(aBoolAlgo->mapOfSubShapes());
348         GeomShapePtr aResultShape = aBoolAlgo->shape();
349
350         // Add result to not used solids from compsolid.
351         if(!aNotUsedSolids.empty()) {
352           ListOfShape aShapesToAdd = aNotUsedSolids;
353           aShapesToAdd.push_back(aBoolAlgo->shape());
354           std::shared_ptr<GeomAlgoAPI_PaveFiller> aFillerAlgo(
355             new GeomAlgoAPI_PaveFiller(aShapesToAdd, true));
356           if(!aFillerAlgo->isDone()) {
357             std::string aFeatureError = "Error: PaveFiller algorithm failed.";
358             setError(aFeatureError);
359             return;
360           }
361
362           aMakeShapeList.appendAlgo(aFillerAlgo);
363           aMapOfShapes.merge(aFillerAlgo->mapOfSubShapes());
364           aResultShape = aFillerAlgo->shape();
365         }
366
367         if(GeomAlgoAPI_ShapeTools::volume(aResultShape) > 1.e-27) {
368           std::shared_ptr<ModelAPI_ResultBody> aResultBody =
369             document()->createBody(data(), aResultIndex);
370
371           ListOfShape aUsedTools = aTools;
372           if (aType == BOOL_FILL) {
373             aUsedTools.insert(aUsedTools.end(), aPlanes.begin(), aPlanes.end());
374           }
375
376           loadNamingDS(aResultBody,
377                        aCompSolid,
378                        aUsedTools,
379                        aResultShape,
380                        aMakeShapeList,
381                        aMapOfShapes,
382                        aType == BOOL_FILL);
383           setResult(aResultBody, aResultIndex);
384           aResultIndex++;
385         }
386       }
387       break;
388     }
389     case BOOL_FUSE: {
390       if((anObjects.size() + aTools.size() +
391           aCompSolidsObjects.size() + anEdgesAndFaces.size()) < 2) {
392         std::string aFeatureError = "Error: Not enough objects for boolean operation.";
393         setError(aFeatureError);
394         return;
395       }
396
397       // Collecting all solids which will be fused.
398       ListOfShape aSolidsToFuse;
399       aSolidsToFuse.insert(aSolidsToFuse.end(), anObjects.begin(), anObjects.end());
400       aSolidsToFuse.insert(aSolidsToFuse.end(), aTools.begin(), aTools.end());
401
402       // Collecting solids from compsolids which will not be modified
403       // in boolean operation and will be added to result.
404       ListOfShape aShapesToAdd;
405       for(std::map<std::shared_ptr<GeomAPI_Shape>, ListOfShape>::iterator
406           anIt = aCompSolidsObjects.begin();
407           anIt != aCompSolidsObjects.end(); anIt++) {
408         std::shared_ptr<GeomAPI_Shape> aCompSolid = anIt->first;
409         ListOfShape& aUsedInOperationSolids = anIt->second;
410         aSolidsToFuse.insert(aSolidsToFuse.end(), aUsedInOperationSolids.begin(),
411                              aUsedInOperationSolids.end());
412
413         // Collect solids from compsolid which will not be modified in boolean operation.
414         for(GeomAPI_ShapeExplorer
415             anExp(aCompSolid, GeomAPI_Shape::SOLID); anExp.more(); anExp.next()) {
416           std::shared_ptr<GeomAPI_Shape> aSolidInCompSolid = anExp.current();
417           ListOfShape::iterator anIt = aUsedInOperationSolids.begin();
418           for(; anIt != aUsedInOperationSolids.end(); anIt++) {
419             if(aSolidInCompSolid->isEqual(*anIt)) {
420               break;
421             }
422           }
423           if(anIt == aUsedInOperationSolids.end()) {
424             aShapesToAdd.push_back(aSolidInCompSolid);
425           }
426         }
427       }
428
429       ListOfShape anOriginalShapes = aSolidsToFuse;
430       anOriginalShapes.insert(anOriginalShapes.end(), aShapesToAdd.begin(), aShapesToAdd.end());
431
432       // Cut edges and faces(if we have any) with solids.
433       GeomAlgoAPI_MakeShapeList aMakeShapeList;
434       GeomAPI_DataMapOfShapeShape aMapOfShapes;
435       std::shared_ptr<GeomAPI_Shape> aCuttedEdgesAndFaces;
436       if(!anEdgesAndFaces.empty()) {
437         std::shared_ptr<GeomAlgoAPI_Boolean> aCutAlgo(new GeomAlgoAPI_Boolean(anEdgesAndFaces,
438                                             anOriginalShapes, GeomAlgoAPI_Boolean::BOOL_CUT));
439         if(aCutAlgo->isDone()) {
440           aCuttedEdgesAndFaces = aCutAlgo->shape();
441           aMakeShapeList.appendAlgo(aCutAlgo);
442           aMapOfShapes.merge(aCutAlgo->mapOfSubShapes());
443         }
444       }
445       anOriginalShapes.insert(anOriginalShapes.end(), anEdgesAndFaces.begin(),
446                               anEdgesAndFaces.end());
447
448       // If we have compsolids then cut with not used solids all others.
449       if(!aShapesToAdd.empty()) {
450         aSolidsToFuse.clear();
451         for(ListOfShape::iterator
452             anIt = anOriginalShapes.begin(); anIt != anOriginalShapes.end(); anIt++) {
453           ListOfShape aOneObjectList;
454           aOneObjectList.push_back(*anIt);
455           std::shared_ptr<GeomAlgoAPI_Boolean> aCutAlgo(
456             new GeomAlgoAPI_Boolean(aOneObjectList, aShapesToAdd, GeomAlgoAPI_Boolean::BOOL_CUT));
457
458           if(GeomAlgoAPI_ShapeTools::volume(aCutAlgo->shape()) > 1.e-27) {
459             aSolidsToFuse.push_back(aCutAlgo->shape());
460             aMakeShapeList.appendAlgo(aCutAlgo);
461             aMapOfShapes.merge(aCutAlgo->mapOfSubShapes());
462           }
463         }
464       }
465
466       if(!aSolidsToFuse.empty()) {
467         anObjects.clear();
468         anObjects.push_back(aSolidsToFuse.back());
469         aSolidsToFuse.pop_back();
470         aTools = aSolidsToFuse;
471       }
472
473       // Fuse all objects and all tools.
474       std::shared_ptr<GeomAPI_Shape> aShape;
475       if(anObjects.size() == 1 && aTools.empty()) {
476         aShape = anObjects.front();
477       } else if(anObjects.empty() && aTools.size() == 1) {
478         aShape = aTools.front();
479       } else if((anObjects.size() + aTools.size()) > 1){
480         std::shared_ptr<GeomAlgoAPI_Boolean> aFuseAlgo(new GeomAlgoAPI_Boolean(anObjects,
481                                                                 aTools,
482                                                                 GeomAlgoAPI_Boolean::BOOL_FUSE));
483
484         // Checking that the algorithm worked properly.
485         if(!aFuseAlgo->isDone()) {
486           static const std::string aFeatureError = "Error: Boolean algorithm failed.";
487           setError(aFeatureError);
488           return;
489         }
490         if(aFuseAlgo->shape()->isNull()) {
491           static const std::string aShapeError = "Error: Resulting shape is Null.";
492           setError(aShapeError);
493           return;
494         }
495         if(!aFuseAlgo->isValid()) {
496           std::string aFeatureError = "Error: Resulting shape is not valid.";
497           setError(aFeatureError);
498           return;
499         }
500
501         aShape = aFuseAlgo->shape();
502         aMakeShapeList.appendAlgo(aFuseAlgo);
503         aMapOfShapes.merge(aFuseAlgo->mapOfSubShapes());
504       }
505
506       // Combine result with not used solids from compsolid and edges and faces (if we have any).
507       if(aCuttedEdgesAndFaces.get() && !aCuttedEdgesAndFaces->isNull()) {
508         aShapesToAdd.push_back(aCuttedEdgesAndFaces);
509       } else {
510         aShapesToAdd.insert(aShapesToAdd.end(), anEdgesAndFaces.begin(), anEdgesAndFaces.end());
511       }
512       if(!aShapesToAdd.empty()) {
513         if(aShape.get()) {
514           aShapesToAdd.push_back(aShape);
515         }
516         std::shared_ptr<GeomAlgoAPI_PaveFiller> aFillerAlgo(
517           new GeomAlgoAPI_PaveFiller(aShapesToAdd, true));
518         if(!aFillerAlgo->isDone()) {
519           std::string aFeatureError = "Error: PaveFiller algorithm failed.";
520           setError(aFeatureError);
521           return;
522         }
523         if(aFillerAlgo->shape()->isNull()) {
524           static const std::string aShapeError = "Error: Resulting shape is Null.";
525           setError(aShapeError);
526           return;
527         }
528         if(!aFillerAlgo->isValid()) {
529           std::string aFeatureError = "Error: Resulting shape is not valid.";
530           setError(aFeatureError);
531           return;
532         }
533
534         aShape = aFillerAlgo->shape();
535         aMakeShapeList.appendAlgo(aFillerAlgo);
536         aMapOfShapes.merge(aFillerAlgo->mapOfSubShapes());
537       }
538
539       std::shared_ptr<GeomAPI_Shape> aBackShape = anOriginalShapes.back();
540       anOriginalShapes.pop_back();
541       std::shared_ptr<ModelAPI_ResultBody> aResultBody =
542         document()->createBody(data(), aResultIndex);
543       loadNamingDS(aResultBody, aBackShape, anOriginalShapes,
544                    aShape, aMakeShapeList, aMapOfShapes);
545       setResult(aResultBody, aResultIndex);
546       aResultIndex++;
547       break;
548     }
549     case BOOL_SMASH: {
550       if((anObjects.empty() && aCompSolidsObjects.empty()) || aTools.empty()) {
551         std::string aFeatureError = "Error: Not enough objects for boolean operation.";
552         setError(aFeatureError);
553         return;
554       }
555
556       // List of original solids for naming.
557       ListOfShape anOriginalShapes;
558       anOriginalShapes.insert(anOriginalShapes.end(), anObjects.begin(), anObjects.end());
559       anOriginalShapes.insert(anOriginalShapes.end(), aTools.begin(), aTools.end());
560
561       // Collecting all solids which will be smashed.
562       ListOfShape aShapesToSmash;
563       aShapesToSmash.insert(aShapesToSmash.end(), anObjects.begin(), anObjects.end());
564
565       // Collecting solids from compsolids which will not be modified in
566       // boolean operation and will be added to result.
567       ListOfShape aShapesToAdd;
568       for(std::map<std::shared_ptr<GeomAPI_Shape>, ListOfShape>::iterator
569         anIt = aCompSolidsObjects.begin();
570         anIt != aCompSolidsObjects.end(); anIt++) {
571         std::shared_ptr<GeomAPI_Shape> aCompSolid = anIt->first;
572         ListOfShape& aUsedInOperationSolids = anIt->second;
573         anOriginalShapes.push_back(aCompSolid);
574         aShapesToSmash.insert(aShapesToSmash.end(), aUsedInOperationSolids.begin(),
575                               aUsedInOperationSolids.end());
576
577         // Collect solids from compsolid which will not be modified in boolean operation.
578         for(GeomAPI_ShapeExplorer
579             anExp(aCompSolid, GeomAPI_Shape::SOLID); anExp.more(); anExp.next()) {
580           std::shared_ptr<GeomAPI_Shape> aSolidInCompSolid = anExp.current();
581           ListOfShape::iterator anIt = aUsedInOperationSolids.begin();
582           for(; anIt != aUsedInOperationSolids.end(); anIt++) {
583             if(aSolidInCompSolid->isEqual(*anIt)) {
584               break;
585             }
586           }
587           if(anIt == aUsedInOperationSolids.end()) {
588             aShapesToAdd.push_back(aSolidInCompSolid);
589           }
590         }
591       }
592
593       GeomAlgoAPI_MakeShapeList aMakeShapeList;
594       GeomAPI_DataMapOfShapeShape aMapOfShapes;
595       if(!aShapesToAdd.empty()) {
596         // Cut objects with not used solids.
597         std::shared_ptr<GeomAlgoAPI_Boolean> anObjectsCutAlgo(new GeomAlgoAPI_Boolean(
598                                                               aShapesToSmash,
599                                                               aShapesToAdd,
600                                                               GeomAlgoAPI_Boolean::BOOL_CUT));
601
602         if(GeomAlgoAPI_ShapeTools::volume(anObjectsCutAlgo->shape()) > 1.e-27) {
603           aShapesToSmash.clear();
604           aShapesToSmash.push_back(anObjectsCutAlgo->shape());
605           aMakeShapeList.appendAlgo(anObjectsCutAlgo);
606           aMapOfShapes.merge(anObjectsCutAlgo->mapOfSubShapes());
607         }
608
609         // Cut tools with not used solids.
610         std::shared_ptr<GeomAlgoAPI_Boolean> aToolsCutAlgo(new GeomAlgoAPI_Boolean(aTools,
611                                                               aShapesToAdd,
612                                                               GeomAlgoAPI_Boolean::BOOL_CUT));
613
614         if(GeomAlgoAPI_ShapeTools::volume(aToolsCutAlgo->shape()) > 1.e-27) {
615           aTools.clear();
616           aTools.push_back(aToolsCutAlgo->shape());
617           aMakeShapeList.appendAlgo(aToolsCutAlgo);
618           aMapOfShapes.merge(aToolsCutAlgo->mapOfSubShapes());
619         }
620       }
621
622       // Cut objects with tools.
623       std::shared_ptr<GeomAlgoAPI_Boolean> aBoolAlgo(new GeomAlgoAPI_Boolean(aShapesToSmash,
624                                                                 aTools,
625                                                                 GeomAlgoAPI_Boolean::BOOL_CUT));
626
627       // Checking that the algorithm worked properly.
628       if(!aBoolAlgo->isDone()) {
629         static const std::string aFeatureError = "Error: Boolean algorithm failed.";
630         setError(aFeatureError);
631         return;
632       }
633       if(aBoolAlgo->shape()->isNull()) {
634         static const std::string aShapeError = "Error: Resulting shape is Null.";
635         setError(aShapeError);
636         return;
637       }
638       if(!aBoolAlgo->isValid()) {
639         std::string aFeatureError = "Error: Resulting shape is not valid.";
640         setError(aFeatureError);
641         return;
642       }
643       aMakeShapeList.appendAlgo(aBoolAlgo);
644       aMapOfShapes.merge(aBoolAlgo->mapOfSubShapes());
645
646       // Put all (cut result, tools and not used solids) to PaveFiller.
647       aShapesToAdd.push_back(aBoolAlgo->shape());
648       aShapesToAdd.insert(aShapesToAdd.end(), aTools.begin(), aTools.end());
649
650       std::shared_ptr<GeomAlgoAPI_PaveFiller> aFillerAlgo(new GeomAlgoAPI_PaveFiller(aShapesToAdd,
651                                                                                      true));
652       if(!aFillerAlgo->isDone()) {
653         std::string aFeatureError = "Error: PaveFiller algorithm failed.";
654         setError(aFeatureError);
655         return;
656       }
657       if(aFillerAlgo->shape()->isNull()) {
658         static const std::string aShapeError = "Error: Resulting shape is Null.";
659         setError(aShapeError);
660         return;
661       }
662       if(!aFillerAlgo->isValid()) {
663         std::string aFeatureError = "Error: Resulting shape is not valid.";
664         setError(aFeatureError);
665         return;
666       }
667
668       std::shared_ptr<GeomAPI_Shape> aShape = aFillerAlgo->shape();
669       aMakeShapeList.appendAlgo(aFillerAlgo);
670       aMapOfShapes.merge(aFillerAlgo->mapOfSubShapes());
671
672       std::shared_ptr<GeomAPI_Shape> aFrontShape = anOriginalShapes.front();
673       anOriginalShapes.pop_front();
674       std::shared_ptr<ModelAPI_ResultBody> aResultBody =
675         document()->createBody(data(), aResultIndex);
676       loadNamingDS(aResultBody, aFrontShape, anOriginalShapes,
677         aShape, aMakeShapeList, aMapOfShapes);
678       setResult(aResultBody, aResultIndex);
679       aResultIndex++;
680
681       break;
682     }
683     default: {
684       std::string anOperationError = "Error: Wrong type of operation";
685       setError(anOperationError);
686       return;
687     }
688   }
689   // remove the rest results if there were produced in the previous pass
690   removeResults(aResultIndex);
691 }
692
693 //=================================================================================================
694 void FeaturesPlugin_Boolean::loadNamingDS(std::shared_ptr<ModelAPI_ResultBody> theResultBody,
695                                           const std::shared_ptr<GeomAPI_Shape> theBaseShape,
696                                           const ListOfShape& theTools,
697                                           const std::shared_ptr<GeomAPI_Shape> theResultShape,
698                                           GeomAlgoAPI_MakeShape& theMakeShape,
699                                           GeomAPI_DataMapOfShapeShape& theMapOfShapes,
700                                           const bool theIsStoreAsGenerated)
701 {
702   //load result
703   if(theBaseShape->isEqual(theResultShape)) {
704     theResultBody->store(theResultShape, false);
705   } else {
706     const int aModifyTag = 1;
707     const int aDeletedTag = 2;
708     /// sub solids will be placed at labels 3, 4, etc. if result is compound of solids
709     const int aSubsolidsTag = 3;
710     const int anEdgesAndFacesTag = 10000;
711
712     theResultBody->storeModified(theBaseShape, theResultShape, aSubsolidsTag);
713
714     const std::string aModName = "Modified";
715     const std::string aModEName = "Modified_Edge";
716     const std::string aModFName = "Modified_Face";
717
718     theResultBody->loadAndOrientModifiedShapes(&theMakeShape, theBaseShape, GeomAPI_Shape::FACE,
719       aModifyTag, aModName, theMapOfShapes, false, theIsStoreAsGenerated, true);
720     theResultBody->loadDeletedShapes(&theMakeShape, theBaseShape,
721                                      GeomAPI_Shape::FACE, aDeletedTag);
722
723     int aTag;
724     std::string aName;
725     for(ListOfShape::const_iterator
726         anIter = theTools.begin(); anIter != theTools.end(); anIter++) {
727       if((*anIter)->shapeType() == GeomAPI_Shape::EDGE) {
728         aTag = anEdgesAndFacesTag;
729         aName = aModEName;
730       }
731       else if((*anIter)->shapeType() == GeomAPI_Shape::FACE) {
732         aTag = anEdgesAndFacesTag;
733         aName = aModFName;
734       } else {
735         aTag = aModifyTag;
736         aName = aModName;
737       }
738       theResultBody->loadAndOrientModifiedShapes(&theMakeShape, *anIter,
739         aName == aModEName ? GeomAPI_Shape::EDGE : GeomAPI_Shape::FACE,
740         aTag, aName, theMapOfShapes, false, theIsStoreAsGenerated, true);
741       theResultBody->loadDeletedShapes(&theMakeShape, *anIter, GeomAPI_Shape::FACE, aDeletedTag);
742     }
743   }
744 }