]> SALOME platform Git repositories - modules/shaper.git/blob - src/FeaturesPlugin/FeaturesPlugin_BooleanFuse.cpp
Salome HOME
[Code coverage]: Move checking the algorithm's result into separate function
[modules/shaper.git] / src / FeaturesPlugin / FeaturesPlugin_BooleanFuse.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_BooleanFuse.h"
22
23 #include "FeaturesPlugin_Tools.h"
24
25 #include <ModelAPI_ResultBody.h>
26 #include <ModelAPI_AttributeBoolean.h>
27 #include <ModelAPI_AttributeSelectionList.h>
28 #include <ModelAPI_AttributeString.h>
29 #include <ModelAPI_Session.h>
30 #include <ModelAPI_Tools.h>
31 #include <ModelAPI_Validator.h>
32
33 #include <GeomAlgoAPI_Boolean.h>
34 #include <GeomAlgoAPI_MakeShapeList.h>
35 #include <GeomAlgoAPI_PaveFiller.h>
36 #include <GeomAlgoAPI_ShapeTools.h>
37 #include <GeomAlgoAPI_Tools.h>
38 #include <GeomAlgoAPI_UnifySameDomain.h>
39 #include <GeomAPI_ShapeExplorer.h>
40
41 //==================================================================================================
42 FeaturesPlugin_BooleanFuse::FeaturesPlugin_BooleanFuse()
43 : FeaturesPlugin_Boolean(FeaturesPlugin_Boolean::BOOL_FUSE)
44 {
45 }
46
47 //==================================================================================================
48 void FeaturesPlugin_BooleanFuse::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   data()->addAttribute(REMOVE_INTERSECTION_EDGES_ID(), ModelAPI_AttributeBoolean::typeId());
56
57   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), OBJECT_LIST_ID());
58   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), TOOL_LIST_ID());
59 }
60
61 //==================================================================================================
62 void FeaturesPlugin_BooleanFuse::execute()
63 {
64   std::string anError;
65   ListOfShape anObjects, aTools, anEdgesAndFaces;
66   std::map<GeomShapePtr, ListOfShape> aCompSolidsObjects;
67
68   bool isSimpleCreation = false;
69
70   AttributeStringPtr aCreationMethodAttr = string(CREATION_METHOD());
71   if (aCreationMethodAttr.get()
72       && aCreationMethodAttr->value() == CREATION_METHOD_SIMPLE())
73   {
74     isSimpleCreation = true;
75   }
76
77   // Getting objects.
78   AttributeSelectionListPtr anObjectsSelList =
79     selectionList(FeaturesPlugin_Boolean::OBJECT_LIST_ID());
80   for (int anObjectsIndex = 0; anObjectsIndex < anObjectsSelList->size(); anObjectsIndex++) {
81     AttributeSelectionPtr anObjectAttr = anObjectsSelList->value(anObjectsIndex);
82     GeomShapePtr anObject = anObjectAttr->value();
83     if (!anObject.get()) {
84       return;
85     }
86     ResultPtr aContext = anObjectAttr->context();
87     ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
88     if (!isSimpleCreation
89         && aResCompSolidPtr.get()
90         && aResCompSolidPtr->shape()->shapeType() == GeomAPI_Shape::COMPSOLID)
91     {
92       GeomShapePtr aContextShape = aResCompSolidPtr->shape();
93       std::map<GeomShapePtr, ListOfShape>::iterator
94         anIt = aCompSolidsObjects.begin();
95       for (; anIt != aCompSolidsObjects.end(); anIt++) {
96         if (anIt->first->isEqual(aContextShape)) {
97           aCompSolidsObjects[anIt->first].push_back(anObject);
98           break;
99         }
100       }
101       if (anIt == aCompSolidsObjects.end()) {
102         aCompSolidsObjects[aContextShape].push_back(anObject);
103       }
104     } else {
105       if (anObject->shapeType() == GeomAPI_Shape::EDGE
106           || anObject->shapeType() == GeomAPI_Shape::FACE) {
107         anEdgesAndFaces.push_back(anObject);
108       } else {
109         anObjects.push_back(anObject);
110       }
111     }
112   }
113
114   // Getting tools.
115   if (!isSimpleCreation) {
116     AttributeSelectionListPtr aToolsSelList = selectionList(FeaturesPlugin_Boolean::TOOL_LIST_ID());
117     for (int aToolsIndex = 0; aToolsIndex < aToolsSelList->size(); aToolsIndex++) {
118       AttributeSelectionPtr aToolAttr = aToolsSelList->value(aToolsIndex);
119       GeomShapePtr aTool = aToolAttr->value();
120       if (aTool->shapeType() == GeomAPI_Shape::EDGE
121           || aTool->shapeType() == GeomAPI_Shape::FACE)
122       {
123         anEdgesAndFaces.push_back(aTool);
124       } else {
125         aTools.push_back(aTool);
126       }
127     }
128   }
129
130   if ((anObjects.size() + aTools.size() +
131     aCompSolidsObjects.size() + anEdgesAndFaces.size()) < 2) {
132     std::string aFeatureError = "Error: Not enough objects for boolean operation.";
133     setError(aFeatureError);
134     return;
135   }
136
137   // Collecting all solids which will be fused.
138   ListOfShape aSolidsToFuse;
139   aSolidsToFuse.insert(aSolidsToFuse.end(), anObjects.begin(), anObjects.end());
140   aSolidsToFuse.insert(aSolidsToFuse.end(), aTools.begin(), aTools.end());
141
142   // Collecting solids from compsolids which will not be modified
143   // in boolean operation and will be added to result.
144   ListOfShape aShapesToAdd;
145   for (std::map<GeomShapePtr, ListOfShape>::iterator anIt = aCompSolidsObjects.begin();
146        anIt != aCompSolidsObjects.end();
147        ++anIt)
148   {
149     GeomShapePtr aCompSolid = anIt->first;
150     ListOfShape& aUsedInOperationSolids = anIt->second;
151     aSolidsToFuse.insert(aSolidsToFuse.end(), aUsedInOperationSolids.begin(),
152                          aUsedInOperationSolids.end());
153
154     // Collect solids from compsolid which will not be modified in boolean operation.
155     for (GeomAPI_ShapeExplorer
156          anExp(aCompSolid, GeomAPI_Shape::SOLID); anExp.more(); anExp.next()) {
157       GeomShapePtr aSolidInCompSolid = anExp.current();
158       ListOfShape::iterator anIt = aUsedInOperationSolids.begin();
159       for (; anIt != aUsedInOperationSolids.end(); anIt++) {
160         if (aSolidInCompSolid->isEqual(*anIt)) {
161           break;
162         }
163       }
164       if (anIt == aUsedInOperationSolids.end()) {
165         aShapesToAdd.push_back(aSolidInCompSolid);
166       }
167     }
168   }
169
170   ListOfShape anOriginalShapes = aSolidsToFuse;
171   anOriginalShapes.insert(anOriginalShapes.end(), aShapesToAdd.begin(), aShapesToAdd.end());
172
173   // Cut edges and faces(if we have any) with solids.
174   std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeShapeList(new GeomAlgoAPI_MakeShapeList());
175   GeomShapePtr aCuttedEdgesAndFaces;
176   if (!anEdgesAndFaces.empty()) {
177     std::shared_ptr<GeomAlgoAPI_Boolean> aCutAlgo(new GeomAlgoAPI_Boolean(anEdgesAndFaces,
178       anOriginalShapes, GeomAlgoAPI_Boolean::BOOL_CUT));
179     if (aCutAlgo->isDone()) {
180       aCuttedEdgesAndFaces = aCutAlgo->shape();
181       aMakeShapeList->appendAlgo(aCutAlgo);
182     }
183   }
184   anOriginalShapes.insert(anOriginalShapes.end(), anEdgesAndFaces.begin(),
185                           anEdgesAndFaces.end());
186
187   // If we have compsolids then cut with not used solids all others.
188   if (!aShapesToAdd.empty()) {
189     aSolidsToFuse.clear();
190     for (ListOfShape::iterator
191          anIt = anOriginalShapes.begin(); anIt != anOriginalShapes.end(); anIt++) {
192       ListOfShape aOneObjectList;
193       aOneObjectList.push_back(*anIt);
194       std::shared_ptr<GeomAlgoAPI_Boolean> aCutAlgo(
195         new GeomAlgoAPI_Boolean(aOneObjectList, aShapesToAdd, GeomAlgoAPI_Boolean::BOOL_CUT));
196
197       if (GeomAlgoAPI_ShapeTools::volume(aCutAlgo->shape()) > 1.e-27) {
198         aSolidsToFuse.push_back(aCutAlgo->shape());
199         aMakeShapeList->appendAlgo(aCutAlgo);
200       }
201     }
202   }
203
204   if (!aSolidsToFuse.empty()) {
205     anObjects.clear();
206     anObjects.push_back(aSolidsToFuse.back());
207     aSolidsToFuse.pop_back();
208     aTools = aSolidsToFuse;
209   }
210
211   // Fuse all objects and all tools.
212   GeomShapePtr aShape;
213   if (anObjects.size() == 1 && aTools.empty()) {
214     aShape = anObjects.front();
215   } else if (anObjects.empty() && aTools.size() == 1) {
216     aShape = aTools.front();
217   } else if ((anObjects.size() + aTools.size()) > 1) {
218     std::shared_ptr<GeomAlgoAPI_Boolean> aFuseAlgo(new GeomAlgoAPI_Boolean(anObjects,
219       aTools,
220       GeomAlgoAPI_Boolean::BOOL_FUSE));
221
222     // Checking that the algorithm worked properly.
223     if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aFuseAlgo, getKind(), anError)) {
224       setError(anError);
225       return;
226     }
227
228     aShape = aFuseAlgo->shape();
229     aMakeShapeList->appendAlgo(aFuseAlgo);
230   }
231
232   // Combine result with not used solids from compsolid and edges and faces (if we have any).
233   if (aCuttedEdgesAndFaces.get() && !aCuttedEdgesAndFaces->isNull()) {
234     aShapesToAdd.push_back(aCuttedEdgesAndFaces);
235   } else {
236     aShapesToAdd.insert(aShapesToAdd.end(), anEdgesAndFaces.begin(), anEdgesAndFaces.end());
237   }
238   if (!aShapesToAdd.empty()) {
239     if (aShape.get()) {
240       aShapesToAdd.push_back(aShape);
241     }
242     std::shared_ptr<GeomAlgoAPI_PaveFiller> aFillerAlgo(
243       new GeomAlgoAPI_PaveFiller(aShapesToAdd, true));
244     if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aFillerAlgo, getKind(), anError)) {
245       setError(anError);
246       return;
247     }
248
249     aShape = aFillerAlgo->shape();
250     aMakeShapeList->appendAlgo(aFillerAlgo);
251   }
252
253   bool isRemoveEdges = false;
254   AttributeBooleanPtr removeEdgesAttr = boolean(REMOVE_INTERSECTION_EDGES_ID());
255   if (removeEdgesAttr.get()) {
256     isRemoveEdges = removeEdgesAttr->value();
257   }
258
259   if (isRemoveEdges) {
260     std::shared_ptr<GeomAlgoAPI_UnifySameDomain> aUnifyAlgo(
261       new GeomAlgoAPI_UnifySameDomain(aShape));
262
263     if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aUnifyAlgo, getKind(), anError)) {
264       setError(anError);
265       return;
266     }
267
268     aShape = aUnifyAlgo->shape();
269     aMakeShapeList->appendAlgo(aUnifyAlgo);
270   }
271
272   int aResultIndex = 0;
273
274   GeomShapePtr aBackShape = anOriginalShapes.back();
275   anOriginalShapes.pop_back();
276   ResultBodyPtr aResultBody = document()->createBody(data(), aResultIndex);
277
278   FeaturesPlugin_Tools::loadModifiedShapes(aResultBody,
279                                            aBackShape,
280                                            anOriginalShapes,
281                                            aMakeShapeList,
282                                            aShape);
283   setResult(aResultBody, aResultIndex);
284   aResultIndex++;
285
286   FeaturesPlugin_Tools::loadDeletedShapes(aResultBody,
287                                           aBackShape,
288                                           anOriginalShapes,
289                                           aMakeShapeList,
290                                           aShape);
291
292   // remove the rest results if there were produced in the previous pass
293   removeResults(aResultIndex);
294 }