]> SALOME platform Git repositories - modules/shaper.git/blob - src/FeaturesPlugin/FeaturesPlugin_CompositeBoolean.cpp
Salome HOME
Add copyright header according to request of CEA from 06.06.2017
[modules/shaper.git] / src / FeaturesPlugin / FeaturesPlugin_CompositeBoolean.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 email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
18 //
19
20 #include "FeaturesPlugin_CompositeBoolean.h"
21
22 #include <ModelAPI_AttributeSelectionList.h>
23 #include <ModelAPI_ResultCompSolid.h>
24 #include <ModelAPI_Tools.h>
25
26 #include <GeomAlgoAPI_Boolean.h>
27 #include <GeomAlgoAPI_MakeShapeList.h>
28 #include <GeomAlgoAPI_PaveFiller.h>
29 #include <GeomAlgoAPI_ShapeTools.h>
30
31 #include <GeomAPI_ShapeExplorer.h>
32
33 #include <map>
34
35 //=================================================================================================
36 void FeaturesPlugin_CompositeBoolean::initBooleanAttributes()
37 {
38   myFeature->data()->addAttribute(OBJECTS_ID(), ModelAPI_AttributeSelectionList::typeId());
39 }
40
41 //=================================================================================================
42 void FeaturesPlugin_CompositeBoolean::executeCompositeBoolean()
43 {
44   // Make generation.
45   ListOfShape aGenBaseShapes;
46   ListOfMakeShape aGenMakeShapes;
47   if(!makeGeneration(aGenBaseShapes, aGenMakeShapes)) {
48     return;
49   }
50
51   // Getting tools.
52   ListOfShape aTools;
53   for(ListOfMakeShape::const_iterator
54       anIt = aGenMakeShapes.cbegin(); anIt != aGenMakeShapes.cend(); ++anIt) {
55     aTools.push_back((*anIt)->shape());
56   }
57
58   // Make boolean.
59   ListOfShape aBooleanObjects;
60   ListOfMakeShape aBooleanMakeShapes;
61   if(!makeBoolean(aTools, aBooleanObjects, aBooleanMakeShapes)) {
62     return;
63   }
64
65   if(myOperationType == BOOL_FUSE) {
66     aTools.splice(aTools.begin(), aBooleanObjects);
67     aBooleanObjects.splice(aBooleanObjects.begin(), aTools, aTools.begin());
68   }
69
70   // Store result.
71   int aResultIndex = 0;
72   ListOfShape::const_iterator aBoolObjIt = aBooleanObjects.cbegin();
73   ListOfMakeShape::const_iterator aBoolMSIt = aBooleanMakeShapes.cbegin();
74   for(; aBoolObjIt != aBooleanObjects.cend() && aBoolMSIt != aBooleanMakeShapes.cend();
75       ++aBoolObjIt, ++aBoolMSIt) {
76
77     int aTag = 1;
78
79     ResultBodyPtr aResultBody = myFeature->document()->createBody(myFeature->data(), aResultIndex);
80     aResultBody->storeModified(*aBoolObjIt, (*aBoolMSIt)->shape(), aTag);
81
82     aTag += 5000;
83
84     // Store generation history.
85     ListOfShape::const_iterator aGenBaseIt = aGenBaseShapes.cbegin();
86     ListOfMakeShape::const_iterator aGenMSIt = aGenMakeShapes.cbegin();
87     for(; aGenBaseIt != aGenBaseShapes.cend() && aGenMSIt != aGenMakeShapes.cend();
88         ++aGenBaseIt, ++aGenMSIt) {
89       storeGenerationHistory(aResultBody, *aGenBaseIt, *aGenMSIt, aTag);
90     }
91
92     int aModTag = aTag;
93     storeModificationHistory(aResultBody, *aBoolObjIt, aTools, *aBoolMSIt, aModTag);
94
95     myFeature->setResult(aResultBody, aResultIndex++);
96   }
97
98   myFeature->removeResults(aResultIndex);
99 }
100
101 //=================================================================================================
102 bool FeaturesPlugin_CompositeBoolean::makeBoolean(const ListOfShape& theTools,
103                                                   ListOfShape& theObjects,
104                                                   ListOfMakeShape& theMakeShapes)
105 {
106   // Getting objects.
107   ListOfShape anObjects, anEdgesAndFaces, aCompSolids;
108   std::map<GeomShapePtr, ListOfShape> aCompSolidsObjects;
109   AttributeSelectionListPtr anObjectsSelList = myFeature->selectionList(OBJECTS_ID());
110   for(int anObjectsIndex = 0; anObjectsIndex < anObjectsSelList->size(); anObjectsIndex++) {
111     AttributeSelectionPtr anObjectAttr = anObjectsSelList->value(anObjectsIndex);
112     GeomShapePtr anObject = anObjectAttr->value();
113     if(!anObject.get()) {
114       myFeature->setError("Error: Could not get object.");
115       return false;
116     }
117     ResultPtr aContext = anObjectAttr->context();
118     ResultCompSolidPtr aResCompSolidPtr = ModelAPI_Tools::compSolidOwner(aContext);
119     if(aResCompSolidPtr.get()) {
120       GeomShapePtr aContextShape = aResCompSolidPtr->shape();
121       std::map<GeomShapePtr, ListOfShape>::iterator anIt = aCompSolidsObjects.begin();
122       for(; anIt != aCompSolidsObjects.end(); anIt++) {
123         if(anIt->first->isEqual(aContextShape)) {
124           aCompSolidsObjects[anIt->first].push_back(anObject);
125           break;
126         }
127       }
128       if(anIt == aCompSolidsObjects.end()) {
129         aCompSolidsObjects[aContextShape].push_back(anObject);
130         aCompSolids.push_back(aContextShape);
131       }
132     } else {
133       if(anObject->shapeType() == GeomAPI_Shape::EDGE ||
134          anObject->shapeType() == GeomAPI_Shape::FACE) {
135         anEdgesAndFaces.push_back(anObject);
136       } else {
137         anObjects.push_back(anObject);
138       }
139     }
140   }
141
142   switch(myOperationType) {
143     case BOOL_CUT: {
144       if((anObjects.empty() && aCompSolidsObjects.empty()) || theTools.empty()) {
145         myFeature->setError("Error: Not enough objects for boolean operation.");
146         return false;
147       }
148
149       // For solids cut each object with all tools.
150       for(ListOfShape::const_iterator
151           anIt = anObjects.cbegin(); anIt != anObjects.cend(); ++anIt) {
152         GeomShapePtr anObject = *anIt;
153         ListOfShape aListWithObject;
154         aListWithObject.push_back(anObject);
155         std::shared_ptr<GeomAlgoAPI_Boolean> aBoolAlgo(new GeomAlgoAPI_Boolean(aListWithObject,
156                                                                 theTools,
157                                                                 GeomAlgoAPI_Boolean::BOOL_CUT));
158
159         // Checking that the algorithm worked properly.
160         if(!aBoolAlgo->isDone() || aBoolAlgo->shape()->isNull() || !aBoolAlgo->isValid()) {
161           myFeature->setError("Error: Boolean algorithm failed.");
162           return false;
163         }
164
165         if(GeomAlgoAPI_ShapeTools::volume(aBoolAlgo->shape()) > 1.e-27) {
166           theObjects.push_back(anObject);
167           theMakeShapes.push_back(aBoolAlgo);
168         }
169       }
170
171       // Compsolids handling
172       for(std::map<GeomShapePtr, ListOfShape>::const_iterator anIt = aCompSolidsObjects.cbegin();
173           anIt != aCompSolidsObjects.cend(); ++anIt) {
174         GeomShapePtr aCompSolid = anIt->first;
175         const ListOfShape& aUsedShapes = anIt->second;
176
177         // Collecting solids from compsolids which will not be modified in boolean operation.
178         ListOfShape aShapesToAdd;
179         for(GeomAPI_ShapeExplorer
180             anExp(aCompSolid, GeomAPI_Shape::SOLID); anExp.more(); anExp.next()) {
181           GeomShapePtr aSolidInCompSolid = anExp.current();
182           ListOfShape::const_iterator aUsedShapesIt = aUsedShapes.cbegin();
183           for(; aUsedShapesIt != aUsedShapes.cend(); ++aUsedShapesIt) {
184             if(aSolidInCompSolid->isEqual(*aUsedShapesIt)) {
185               break;
186             }
187           }
188           if(aUsedShapesIt == aUsedShapes.end()) {
189             aShapesToAdd.push_back(aSolidInCompSolid);
190           }
191         }
192
193         std::shared_ptr<GeomAlgoAPI_Boolean> aBoolAlgo(new GeomAlgoAPI_Boolean(aUsedShapes,
194                                                                   theTools,
195                                                                   GeomAlgoAPI_Boolean::BOOL_CUT));
196
197         // Checking that the algorithm worked properly.
198         if(!aBoolAlgo->isDone() || aBoolAlgo->shape()->isNull() || !aBoolAlgo->isValid()) {
199           myFeature->setError("Error: Boolean algorithm failed.");
200           return false;
201         }
202
203         std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeShapeList(new GeomAlgoAPI_MakeShapeList());
204         aMakeShapeList->appendAlgo(aBoolAlgo);
205
206         // Add result to not used solids from compsolid.
207         aShapesToAdd.push_back(aBoolAlgo->shape());
208         std::shared_ptr<GeomAlgoAPI_PaveFiller> aFillerAlgo(
209           new GeomAlgoAPI_PaveFiller(aShapesToAdd, true));
210         if(!aFillerAlgo->isDone() || aFillerAlgo->shape()->isNull() || !aFillerAlgo->isValid()) {
211           myFeature->setError("Error: PaveFiller algorithm failed.");
212           return false;
213         }
214
215         aMakeShapeList->appendAlgo(aFillerAlgo);
216
217         if(GeomAlgoAPI_ShapeTools::volume(aFillerAlgo->shape()) > 1.e-27) {
218           theObjects.push_back(aCompSolid);
219           theMakeShapes.push_back(aMakeShapeList);
220         }
221       }
222       break;
223     }
224     case BOOL_FUSE: {
225       // Set objects.
226       theObjects.insert(theObjects.end(), anEdgesAndFaces.begin(), anEdgesAndFaces.end());
227       theObjects.insert(theObjects.end(), anObjects.begin(), anObjects.end());
228       theObjects.insert(theObjects.end(), aCompSolids.begin(), aCompSolids.end());
229
230       // Filter edges and faces in tools.
231       ListOfShape aTools;
232       for(ListOfShape::const_iterator anIt = theTools.cbegin(); anIt != theTools.cend(); ++anIt) {
233         if((*anIt)->shapeType() == GeomAPI_Shape::EDGE ||
234            (*anIt)->shapeType() == GeomAPI_Shape::FACE) {
235           anEdgesAndFaces.push_back(*anIt);
236         } else {
237           aTools.push_back(*anIt);
238         }
239       }
240
241       if((anObjects.size() + aTools.size() +
242           aCompSolidsObjects.size() + anEdgesAndFaces.size()) < 2) {
243         myFeature->setError("Error: Not enough objects for boolean operation.");
244         return false;
245       }
246
247       // Collecting all solids which will be fused.
248       ListOfShape aSolidsToFuse;
249       aSolidsToFuse.insert(aSolidsToFuse.end(), anObjects.begin(), anObjects.end());
250       aSolidsToFuse.insert(aSolidsToFuse.end(), aTools.begin(), aTools.end());
251
252       // Collecting solids from compsolids which will not be
253       // modified in boolean operation and will be added to result.
254       ListOfShape aShapesToAdd;
255       for(std::map<GeomShapePtr, ListOfShape>::iterator anIt = aCompSolidsObjects.begin();
256           anIt != aCompSolidsObjects.end(); anIt++) {
257         GeomShapePtr aCompSolid = anIt->first;
258         ListOfShape& aUsedShapes = anIt->second;
259         aSolidsToFuse.insert(aSolidsToFuse.end(), aUsedShapes.begin(), aUsedShapes.end());
260
261         // Collect solids from compsolid which will not be modified in boolean operation.
262         for(GeomAPI_ShapeExplorer
263             anExp(aCompSolid, GeomAPI_Shape::SOLID); anExp.more(); anExp.next()) {
264           GeomShapePtr aSolidInCompSolid = anExp.current();
265           ListOfShape::iterator anIt = aUsedShapes.begin();
266           for(; anIt != aUsedShapes.end(); anIt++) {
267             if(aSolidInCompSolid->isEqual(*anIt)) {
268               break;
269             }
270           }
271           if(anIt == aUsedShapes.end()) {
272             aShapesToAdd.push_back(aSolidInCompSolid);
273           }
274         }
275       }
276
277       // Cut edges and faces(if we have any) with solids.
278       ListOfShape aCutTools;
279       aCutTools.insert(aCutTools.end(), anObjects.begin(), anObjects.end());
280       aCutTools.insert(aCutTools.end(), aCompSolids.begin(), aCompSolids.end());
281       aCutTools.insert(aCutTools.end(), aTools.begin(), aTools.end());
282
283       std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeShapeList(new GeomAlgoAPI_MakeShapeList());
284       if(!anEdgesAndFaces.empty() && !aCutTools.empty()) {
285         std::shared_ptr<GeomAlgoAPI_Boolean> aCutAlgo(new GeomAlgoAPI_Boolean(anEdgesAndFaces,
286                                                               aCutTools,
287                                                               GeomAlgoAPI_Boolean::BOOL_CUT));
288         if(aCutAlgo->isDone() && !aCutAlgo->shape()->isNull() && aCutAlgo->isValid()) {
289           anEdgesAndFaces.clear();
290           anEdgesAndFaces.push_back(aCutAlgo->shape());
291           aMakeShapeList->appendAlgo(aCutAlgo);
292         }
293       }
294
295       // If we have compsolids then cut with not used solids all others.
296       if(!aShapesToAdd.empty()) {
297         std::shared_ptr<GeomAlgoAPI_Boolean> aCutAlgo(new GeomAlgoAPI_Boolean(aSolidsToFuse,
298                                                               aShapesToAdd,
299                                                               GeomAlgoAPI_Boolean::BOOL_CUT));
300         if(aCutAlgo->isDone() && GeomAlgoAPI_ShapeTools::volume(aCutAlgo->shape()) > 1.e-27) {
301           aSolidsToFuse.clear();
302           aSolidsToFuse.push_back(aCutAlgo->shape());
303           aMakeShapeList->appendAlgo(aCutAlgo);
304         }
305       }
306
307       // Fuse all objects and all tools.
308       GeomShapePtr aFusedShape;
309       if(aSolidsToFuse.size() == 1) {
310         aFusedShape = aSolidsToFuse.front();
311       } else if(aSolidsToFuse.size() > 1){
312         anObjects.clear();
313         anObjects.push_back(aSolidsToFuse.front());
314         aSolidsToFuse.pop_front();
315         aTools = aSolidsToFuse;
316
317         std::shared_ptr<GeomAlgoAPI_Boolean> aFuseAlgo(new GeomAlgoAPI_Boolean(anObjects,
318                                                           aTools,
319                                                           GeomAlgoAPI_Boolean::BOOL_FUSE));
320
321         // Checking that the algorithm worked properly.
322         if(!aFuseAlgo->isDone() || aFuseAlgo->shape()->isNull() || !aFuseAlgo->isValid()) {
323           myFeature->setError("Error: Boolean algorithm failed.");
324           return false;
325         }
326
327         aFusedShape = aFuseAlgo->shape();
328         aMakeShapeList->appendAlgo(aFuseAlgo);
329       }
330
331       // Combine result with not used solids from compsolid and edges and faces (if we have any).
332       aShapesToAdd.insert(aShapesToAdd.end(), anEdgesAndFaces.begin(), anEdgesAndFaces.end());
333       if(!aShapesToAdd.empty()) {
334         if(aFusedShape.get()) {
335           aShapesToAdd.push_back(aFusedShape);
336         }
337
338         std::shared_ptr<GeomAlgoAPI_PaveFiller> aFillerAlgo(
339           new GeomAlgoAPI_PaveFiller(aShapesToAdd, true));
340         if(!aFillerAlgo->isDone() || aFillerAlgo->shape()->isNull() || !aFillerAlgo->isValid()) {
341           myFeature->setError("Error: PaveFiller algorithm failed.");
342           return false;
343         }
344
345         aMakeShapeList->appendAlgo(aFillerAlgo);
346       }
347
348       theMakeShapes.push_back(aMakeShapeList);
349       break;
350     }
351   }
352
353   return true;
354 }
355
356 //=================================================================================================
357 void FeaturesPlugin_CompositeBoolean::storeModificationHistory(ResultBodyPtr theResultBody,
358                                 const GeomShapePtr theObject,
359                                 const ListOfShape& theTools,
360                                 const std::shared_ptr<GeomAlgoAPI_MakeShape> theMakeShape,
361                                 int& theTag)
362 {
363   int aModTag = theTag;
364   int anEdgesAndFacesTag = ++aModTag;
365   int aDelTag = ++anEdgesAndFacesTag;
366   theTag = aDelTag;
367
368   const std::string aModName = "Modfied";
369
370   ListOfShape aTools = theTools;
371   aTools.push_back(theObject);
372
373   std::shared_ptr<GeomAPI_DataMapOfShapeShape> aMap = theMakeShape->mapOfSubShapes();
374
375   int aTag;
376   std::string aName;
377   for(ListOfShape::const_iterator anIt = aTools.begin(); anIt != aTools.end(); anIt++) {
378     if((*anIt)->shapeType() == GeomAPI_Shape::EDGE) {
379       aTag = anEdgesAndFacesTag;
380       aName = aModName + "_Edge";
381     }
382     else if((*anIt)->shapeType() == GeomAPI_Shape::FACE) {
383       aTag = anEdgesAndFacesTag;
384       aName = aModName + "_Face";
385     } else {
386       aTag = aModTag;
387       aName = aModName;
388     }
389     theResultBody->loadAndOrientModifiedShapes(theMakeShape.get(), *anIt,
390       (*anIt)->shapeType() == GeomAPI_Shape::EDGE ?
391       GeomAPI_Shape::EDGE : GeomAPI_Shape::FACE, aTag, aName, *aMap.get());
392     theResultBody->loadDeletedShapes(theMakeShape.get(), *anIt, GeomAPI_Shape::FACE, aDelTag);
393   }
394 }