]> SALOME platform Git repositories - modules/shaper.git/blob - src/FeaturesPlugin/FeaturesPlugin_BooleanCommon.cpp
Salome HOME
Fix for the issue #2693 : groups in error after loading dump (3-holes plate)
[modules/shaper.git] / src / FeaturesPlugin / FeaturesPlugin_BooleanCommon.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_BooleanCommon.h"
22
23 #include "FeaturesPlugin_Tools.h"
24
25 #include <ModelAPI_ResultBody.h>
26 #include <ModelAPI_AttributeSelectionList.h>
27 #include <ModelAPI_AttributeString.h>
28 #include <ModelAPI_Tools.h>
29
30 #include <GeomAlgoAPI_Boolean.h>
31 #include <GeomAlgoAPI_MakeShapeCustom.h>
32 #include <GeomAlgoAPI_MakeShapeList.h>
33 #include <GeomAlgoAPI_ShapeTools.h>
34 #include <GeomAPI_Face.h>
35 #include <GeomAPI_ShapeIterator.h>
36 #include <GeomAPI_ShapeExplorer.h>
37 #include <GeomAlgoAPI_PaveFiller.h>
38 #include <GeomAlgoAPI_CompoundBuilder.h>
39
40
41 //==================================================================================================
42 FeaturesPlugin_BooleanCommon::FeaturesPlugin_BooleanCommon()
43 : FeaturesPlugin_Boolean(FeaturesPlugin_Boolean::BOOL_COMMON)
44 {
45 }
46
47 //==================================================================================================
48 void FeaturesPlugin_BooleanCommon::initAttributes()
49 {
50   data()->addAttribute(CREATION_METHOD(), ModelAPI_AttributeString::typeId());
51
52   data()->addAttribute(OBJECT_LIST_ID(), ModelAPI_AttributeSelectionList::typeId());
53   data()->addAttribute(TOOL_LIST_ID(), ModelAPI_AttributeSelectionList::typeId());
54 }
55
56 //==================================================================================================
57 void FeaturesPlugin_BooleanCommon::execute()
58 {
59   ListOfShape anObjects, aTools, aPlanes;
60   std::map<std::shared_ptr<GeomAPI_Shape>, ListOfShape> aCompSolidsObjects;
61   std::map<std::shared_ptr<GeomAPI_Shape>, ListOfShape> aCompoundObjects;
62
63   bool isSimpleMode = false;
64
65   AttributeStringPtr aCreationMethodAttr = string(CREATION_METHOD());
66   if (aCreationMethodAttr.get()
67       && aCreationMethodAttr->value() == CREATION_METHOD_SIMPLE()) {
68     isSimpleMode = true;
69   }
70
71   // Getting objects.
72   AttributeSelectionListPtr anObjectsSelList = selectionList(OBJECT_LIST_ID());
73   for (int anObjectsIndex = 0; anObjectsIndex < anObjectsSelList->size(); anObjectsIndex++) {
74     AttributeSelectionPtr anObjectAttr = anObjectsSelList->value(anObjectsIndex);
75     std::shared_ptr<GeomAPI_Shape> anObject = anObjectAttr->value();
76     if (!anObject.get()) {
77       return;
78     }
79     ResultPtr aContext = anObjectAttr->context();
80     ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
81     if (aResCompSolidPtr.get())
82     {
83       std::shared_ptr<GeomAPI_Shape> aContextShape = aResCompSolidPtr->shape();
84       GeomAPI_Shape::ShapeType aShapeType = aResCompSolidPtr->shape()->shapeType();
85       std::map<std::shared_ptr<GeomAPI_Shape>, ListOfShape>& aMap =
86         aShapeType == GeomAPI_Shape::COMPSOLID ? aCompSolidsObjects : aCompoundObjects;
87
88       std::map<std::shared_ptr<GeomAPI_Shape>, ListOfShape>::iterator
89         anIt = aMap.begin();
90       for (; anIt != aMap.end(); anIt++) {
91         if (anIt->first->isEqual(aContextShape)) {
92           aMap[anIt->first].push_back(anObject);
93           break;
94         }
95       }
96       if (anIt == aMap.end()) {
97         aMap[aContextShape].push_back(anObject);
98       }
99
100     }
101     else {
102       anObjects.push_back(anObject);
103     }
104   }
105
106   // Getting tools.
107   if (!isSimpleMode) {
108     AttributeSelectionListPtr aToolsSelList = selectionList(FeaturesPlugin_Boolean::TOOL_LIST_ID());
109     for (int aToolsIndex = 0; aToolsIndex < aToolsSelList->size(); aToolsIndex++) {
110       AttributeSelectionPtr aToolAttr = aToolsSelList->value(aToolsIndex);
111       GeomShapePtr aTool = aToolAttr->value();
112       if (!aTool.get()) {
113         // It could be a construction plane.
114         ResultPtr aContext = aToolAttr->context();
115         aPlanes.push_back(aToolAttr->context()->shape());
116       } else {
117         aTools.push_back(aTool);
118       }
119     }
120   }
121
122   if ((anObjects.empty() && aCompSolidsObjects.empty())
123       || (!isSimpleMode && aTools.empty() && aPlanes.empty())) {
124     std::string aFeatureError = "Error: Not enough objects for boolean operation.";
125     setError(aFeatureError);
126     return;
127   }
128
129   int aResultIndex = 0;
130   std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeShapeList(new GeomAlgoAPI_MakeShapeList());
131   std::vector<FeaturesPlugin_Tools::ResultBaseAlgo> aResultBaseAlgoList;
132   ListOfShape aResultShapesList;
133
134   if (isSimpleMode)
135   {
136     ListOfShape::iterator anObjectsIt = anObjects.begin();
137     GeomShapePtr aShape = *anObjectsIt;
138     for (++anObjectsIt; anObjectsIt != anObjects.end(); ++anObjectsIt) {
139       std::shared_ptr<GeomAlgoAPI_Boolean> aCommonAlgo(
140         new GeomAlgoAPI_Boolean(aShape,
141                                 *anObjectsIt,
142                                 GeomAlgoAPI_Boolean::BOOL_COMMON));
143
144       if (!aCommonAlgo->isDone()) {
145         std::string aFeatureError = "Error: An algorithm failed.";
146         setError(aFeatureError);
147         return;
148       }
149       if (aCommonAlgo->shape()->isNull()) {
150         static const std::string aShapeError = "Error: Resulting shape is Null.";
151         setError(aShapeError);
152         return;
153       }
154       if (!aCommonAlgo->isValid()) {
155         std::string aFeatureError = "Error: Resulting shape is not valid.";
156         setError(aFeatureError);
157         return;
158       }
159
160       aShape = aCommonAlgo->shape();
161       aMakeShapeList->appendAlgo(aCommonAlgo);
162     }
163
164     GeomAPI_ShapeIterator aShapeIt(aShape);
165     if (aShapeIt.more() || aShape->shapeType() == GeomAPI_Shape::VERTEX) {
166       std::shared_ptr<ModelAPI_ResultBody> aResultBody =
167         document()->createBody(data(), aResultIndex);
168
169       GeomShapePtr aBaseShape = anObjects.front();
170       anObjects.pop_front();
171       FeaturesPlugin_Tools::loadModifiedShapes(aResultBody,
172                                                aBaseShape,
173                                                anObjects,
174                                                aMakeShapeList,
175                                                aShape);
176       setResult(aResultBody, aResultIndex);
177       aResultIndex++;
178
179       aTools = anObjects;
180       FeaturesPlugin_Tools::ResultBaseAlgo aRBA;
181       aRBA.resultBody = aResultBody;
182       aRBA.baseShape = aBaseShape;
183       aRBA.makeShape = aMakeShapeList;
184       aResultBaseAlgoList.push_back(aRBA);
185       aResultShapesList.push_back(aShape);
186     }
187   } else {
188     for (ListOfShape::iterator anObjectsIt = anObjects.begin();
189          anObjectsIt != anObjects.end();
190          ++anObjectsIt)
191     {
192       std::shared_ptr<GeomAPI_Shape> anObject = *anObjectsIt;
193       ListOfShape aListWithObject;
194       aListWithObject.push_back(anObject);
195       std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeShapeList(new GeomAlgoAPI_MakeShapeList());
196       std::shared_ptr<GeomAlgoAPI_MakeShape> aBoolAlgo;
197       GeomShapePtr aResShape;
198
199       std::list<std::shared_ptr<GeomAPI_Pnt> > aBoundingPoints =
200         GeomAlgoAPI_ShapeTools::getBoundingBox(aListWithObject, 1.0);
201
202       // Resize planes.
203       ListOfShape aToolsWithPlanes = aTools;
204       for (ListOfShape::const_iterator anIt = aPlanes.cbegin();
205            anIt != aPlanes.cend();
206            ++anIt) {
207         GeomShapePtr aPlane = *anIt;
208         GeomShapePtr aTool = GeomAlgoAPI_ShapeTools::fitPlaneToBox(aPlane, aBoundingPoints);
209         std::shared_ptr<GeomAlgoAPI_MakeShapeCustom> aMkShCustom(
210           new GeomAlgoAPI_MakeShapeCustom);
211         aMkShCustom->addModified(aPlane, aTool);
212         aMakeShapeList->appendAlgo(aMkShCustom);
213         aToolsWithPlanes.push_back(aTool);
214       }
215
216       aBoolAlgo.reset(new GeomAlgoAPI_Boolean(aListWithObject,
217         aToolsWithPlanes,
218         GeomAlgoAPI_Boolean::BOOL_COMMON));
219       aResShape = aBoolAlgo->shape();
220
221       // Checking that the algorithm worked properly.
222       if (!aBoolAlgo->isDone()) {
223         static const std::string aFeatureError = "Error: Boolean algorithm failed.";
224         setError(aFeatureError);
225         return;
226       }
227       if (aResShape->isNull()) {
228         static const std::string aShapeError = "Error: Resulting shape is Null.";
229         setError(aShapeError);
230         return;
231       }
232       if (!aBoolAlgo->isValid()) {
233         std::string aFeatureError = "Error: Resulting shape is not valid.";
234         setError(aFeatureError);
235         return;
236       }
237
238       aMakeShapeList->appendAlgo(aBoolAlgo);
239
240       GeomAPI_ShapeIterator aShapeIt(aResShape);
241       if (aShapeIt.more() || aResShape->shapeType() == GeomAPI_Shape::VERTEX) {
242         std::shared_ptr<ModelAPI_ResultBody> aResultBody =
243           document()->createBody(data(), aResultIndex);
244
245         FeaturesPlugin_Tools::loadModifiedShapes(aResultBody,
246                                                  anObject,
247                                                  aTools,
248                                                  aMakeShapeList,
249                                                  aResShape);
250         setResult(aResultBody, aResultIndex);
251         aResultIndex++;
252
253         FeaturesPlugin_Tools::ResultBaseAlgo aRBA;
254         aRBA.resultBody = aResultBody;
255         aRBA.baseShape = anObject;
256         aRBA.makeShape = aMakeShapeList;
257         aResultBaseAlgoList.push_back(aRBA);
258         aResultShapesList.push_back(aResShape);
259       }
260     }
261
262     // Compsolids handling
263     for (std::map<std::shared_ptr<GeomAPI_Shape>, ListOfShape>::iterator
264       anIt = aCompSolidsObjects.begin();
265       anIt != aCompSolidsObjects.end();
266       ++anIt)
267     {
268       std::shared_ptr<GeomAPI_Shape> aCompSolid = anIt->first;
269       ListOfShape& aUsedInOperationSolids = anIt->second;
270
271       // Collecting solids from compsolids which will not be modified in boolean operation.
272       ListOfShape aNotUsedSolids;
273       for (GeomAPI_ShapeExplorer anExp(aCompSolid, GeomAPI_Shape::SOLID);
274         anExp.more();
275         anExp.next())
276       {
277         std::shared_ptr<GeomAPI_Shape> aSolidInCompSolid = anExp.current();
278         ListOfShape::iterator aUsedIt = aUsedInOperationSolids.begin();
279         for (; aUsedIt != aUsedInOperationSolids.end(); aUsedIt++) {
280           if (aSolidInCompSolid->isEqual(*aUsedIt)) {
281             break;
282           }
283         }
284         if (aUsedIt == aUsedInOperationSolids.end()) {
285           aNotUsedSolids.push_back(aSolidInCompSolid);
286         }
287       }
288
289       std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeShapeList(new GeomAlgoAPI_MakeShapeList());
290       std::shared_ptr<GeomAlgoAPI_Boolean> aCommonAlgo(
291         new GeomAlgoAPI_Boolean(aUsedInOperationSolids,
292           aTools,
293           GeomAlgoAPI_Boolean::BOOL_COMMON));
294
295       // Checking that the algorithm worked properly.
296       if (!aCommonAlgo->isDone()) {
297         static const std::string aFeatureError = "Error: Boolean algorithm failed.";
298         setError(aFeatureError);
299         return;
300       }
301       if (aCommonAlgo->shape()->isNull()) {
302         static const std::string aShapeError = "Error: Resulting shape is Null.";
303         setError(aShapeError);
304         return;
305       }
306       if (!aCommonAlgo->isValid()) {
307         std::string aFeatureError = "Error: Resulting shape is not valid.";
308         setError(aFeatureError);
309         return;
310       }
311
312       aMakeShapeList->appendAlgo(aCommonAlgo);
313       GeomShapePtr aResultShape = aCommonAlgo->shape();
314
315       // Add result to not used solids from compsolid.
316       if (!aNotUsedSolids.empty()) {
317         ListOfShape aShapesToAdd = aNotUsedSolids;
318         aShapesToAdd.push_back(aCommonAlgo->shape());
319         std::shared_ptr<GeomAlgoAPI_PaveFiller> aFillerAlgo(
320           new GeomAlgoAPI_PaveFiller(aShapesToAdd, true));
321         if (!aFillerAlgo->isDone()) {
322           std::string aFeatureError = "Error: PaveFiller algorithm failed.";
323           setError(aFeatureError);
324           return;
325         }
326
327         aMakeShapeList->appendAlgo(aFillerAlgo);
328         aResultShape = aFillerAlgo->shape();
329       }
330
331       GeomAPI_ShapeIterator aShapeIt(aResultShape);
332       if (aShapeIt.more() || aResultShape->shapeType() == GeomAPI_Shape::VERTEX)
333       {
334         std::shared_ptr<ModelAPI_ResultBody> aResultBody =
335           document()->createBody(data(), aResultIndex);
336
337         FeaturesPlugin_Tools::loadModifiedShapes(aResultBody,
338                                                  aCompSolid,
339                                                  aTools,
340                                                  aMakeShapeList,
341                                                  aResultShape);
342         setResult(aResultBody, aResultIndex);
343         aResultIndex++;
344
345         FeaturesPlugin_Tools::ResultBaseAlgo aRBA;
346         aRBA.resultBody = aResultBody;
347         aRBA.baseShape = aCompSolid;
348         aRBA.makeShape = aMakeShapeList;
349         aResultBaseAlgoList.push_back(aRBA);
350         aResultShapesList.push_back(aResultShape);
351       }
352     }
353
354     // Compounds handling
355     for (std::map<std::shared_ptr<GeomAPI_Shape>, ListOfShape>::iterator
356       anIt = aCompoundObjects.begin();
357       anIt != aCompoundObjects.end();
358       ++anIt)
359     {
360       std::shared_ptr<GeomAPI_Shape> aCompound = anIt->first;
361       ListOfShape& aUsedInOperationShapes = anIt->second;
362
363       // Collecting shapes from compound which will not be modified in boolean operation.
364       ListOfShape aNotUsedShapes;
365       for (GeomAPI_ShapeIterator aCompIt(aCompound);
366         aCompIt.more();
367         aCompIt.next())
368       {
369         std::shared_ptr<GeomAPI_Shape> aShapeInCompound = aCompIt.current();
370         ListOfShape::iterator aUsedIt = aUsedInOperationShapes.begin();
371         for (; aUsedIt != aUsedInOperationShapes.end(); aUsedIt++) {
372           if (aShapeInCompound->isEqual(*aUsedIt)) {
373             break;
374           }
375         }
376         if (aUsedIt == aUsedInOperationShapes.end()) {
377           aNotUsedShapes.push_back(aShapeInCompound);
378         }
379       }
380
381       std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeShapeList(new GeomAlgoAPI_MakeShapeList());
382       std::shared_ptr<GeomAlgoAPI_Boolean> aCommonAlgo(
383         new GeomAlgoAPI_Boolean(aUsedInOperationShapes,
384           aTools,
385           GeomAlgoAPI_Boolean::BOOL_COMMON));
386
387       // Checking that the algorithm worked properly.
388       if (!aCommonAlgo->isDone()) {
389         static const std::string aFeatureError = "Error: Boolean algorithm failed.";
390         setError(aFeatureError);
391         return;
392       }
393       if (aCommonAlgo->shape()->isNull()) {
394         static const std::string aShapeError = "Error: Resulting shape is Null.";
395         setError(aShapeError);
396         return;
397       }
398       if (!aCommonAlgo->isValid()) {
399         std::string aFeatureError = "Error: Resulting shape is not valid.";
400         setError(aFeatureError);
401         return;
402       }
403
404       aMakeShapeList->appendAlgo(aCommonAlgo);
405       GeomShapePtr aResultShape = aCommonAlgo->shape();
406
407       // Add result to not used shape from compound.
408       if (!aNotUsedShapes.empty()) {
409         ListOfShape aShapesForResult = aNotUsedShapes;
410         if (aResultShape->shapeType() == GeomAPI_Shape::COMPOUND) {
411           for (GeomAPI_ShapeIterator aResultIt(aResultShape); aResultIt.more(); aResultIt.next()) {
412             aShapesForResult.push_back(aResultIt.current());
413           }
414         }
415         else {
416           aShapesForResult.push_back(aResultShape);
417         }
418
419         if (aShapesForResult.size() == 1) {
420           aResultShape = aShapesForResult.front();
421         }
422         else {
423           aResultShape = GeomAlgoAPI_CompoundBuilder::compound(aShapesForResult);
424         }
425       }
426
427       GeomAPI_ShapeIterator aShapeIt(aResultShape);
428       if (aShapeIt.more() || aResultShape->shapeType() == GeomAPI_Shape::VERTEX) {
429         std::shared_ptr<ModelAPI_ResultBody> aResultBody =
430           document()->createBody(data(), aResultIndex);
431
432         FeaturesPlugin_Tools::loadModifiedShapes(aResultBody,
433                                                  aCompound,
434                                                  aTools,
435                                                  aMakeShapeList,
436                                                  aResultShape);
437         setResult(aResultBody, aResultIndex);
438         aResultIndex++;
439
440         FeaturesPlugin_Tools::ResultBaseAlgo aRBA;
441         aRBA.resultBody = aResultBody;
442         aRBA.baseShape = aCompound;
443         aRBA.makeShape = aMakeShapeList;
444         aResultBaseAlgoList.push_back(aRBA);
445         aResultShapesList.push_back(aResultShape);
446       }
447     }
448
449   }
450
451   // Store deleted shapes after all results has been proceeded. This is to avoid issue when in one
452   // result shape has been deleted, but in another it was modified or stayed.
453   GeomShapePtr aResultShapesCompound = GeomAlgoAPI_CompoundBuilder::compound(aResultShapesList);
454   FeaturesPlugin_Tools::loadDeletedShapes(aResultBaseAlgoList, aTools, aResultShapesCompound);
455
456   // remove the rest results if there were produced in the previous pass
457   removeResults(aResultIndex);
458 }