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