Salome HOME
Issue #2609: Impossible to select compund of compounds as a base or tool object for...
[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 <ModelAPI_ResultBody.h>
24 #include <ModelAPI_AttributeSelectionList.h>
25 #include <ModelAPI_AttributeString.h>
26 #include <ModelAPI_Tools.h>
27
28 #include <GeomAlgoAPI_Boolean.h>
29 #include <GeomAlgoAPI_MakeShapeCustom.h>
30 #include <GeomAlgoAPI_MakeShapeList.h>
31 #include <GeomAlgoAPI_ShapeTools.h>
32 #include <GeomAPI_Face.h>
33 #include <GeomAPI_ShapeIterator.h>
34
35
36 //==================================================================================================
37 FeaturesPlugin_BooleanCommon::FeaturesPlugin_BooleanCommon()
38 : FeaturesPlugin_Boolean(FeaturesPlugin_Boolean::BOOL_COMMON)
39 {
40 }
41
42 //==================================================================================================
43 void FeaturesPlugin_BooleanCommon::initAttributes()
44 {
45   data()->addAttribute(CREATION_METHOD(), ModelAPI_AttributeString::typeId());
46
47   data()->addAttribute(OBJECT_LIST_ID(), ModelAPI_AttributeSelectionList::typeId());
48   data()->addAttribute(TOOL_LIST_ID(), ModelAPI_AttributeSelectionList::typeId());
49 }
50
51 //==================================================================================================
52 void FeaturesPlugin_BooleanCommon::execute()
53 {
54   ListOfShape anObjects, aTools, aPlanes;
55   std::map<std::shared_ptr<GeomAPI_Shape>, ListOfShape> aCompSolidsObjects;
56
57   bool isSimpleMode = false;
58
59   AttributeStringPtr aCreationMethodAttr = string(CREATION_METHOD());
60   if (aCreationMethodAttr.get()
61       && aCreationMethodAttr->value() == CREATION_METHOD_SIMPLE()) {
62     isSimpleMode = true;
63   }
64
65   // Getting objects.
66   AttributeSelectionListPtr anObjectsSelList =
67     selectionList(FeaturesPlugin_Boolean::OBJECT_LIST_ID());
68   for (int anObjectsIndex = 0; anObjectsIndex < anObjectsSelList->size(); anObjectsIndex++) {
69     AttributeSelectionPtr anObjectAttr = anObjectsSelList->value(anObjectsIndex);
70     std::shared_ptr<GeomAPI_Shape> anObject = anObjectAttr->value();
71     if (!anObject.get()) {
72       return;
73     }
74     ResultPtr aContext = anObjectAttr->context();
75     ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
76     if (!isSimpleMode
77         && aResCompSolidPtr.get()
78         && aResCompSolidPtr->shape()->shapeType() == GeomAPI_Shape::COMPSOLID) {
79       std::shared_ptr<GeomAPI_Shape> aContextShape = aResCompSolidPtr->shape();
80       std::map<std::shared_ptr<GeomAPI_Shape>, ListOfShape>::iterator
81         anIt = aCompSolidsObjects.begin();
82       for (; anIt != aCompSolidsObjects.end(); anIt++) {
83         if (anIt->first->isEqual(aContextShape)) {
84           aCompSolidsObjects[anIt->first].push_back(anObject);
85           break;
86         }
87       }
88       if (anIt == aCompSolidsObjects.end()) {
89         aCompSolidsObjects[aContextShape].push_back(anObject);
90       }
91     } else {
92       anObjects.push_back(anObject);
93     }
94   }
95
96   // Getting tools.
97   if (!isSimpleMode) {
98     AttributeSelectionListPtr aToolsSelList = selectionList(FeaturesPlugin_Boolean::TOOL_LIST_ID());
99     for (int aToolsIndex = 0; aToolsIndex < aToolsSelList->size(); aToolsIndex++) {
100       AttributeSelectionPtr aToolAttr = aToolsSelList->value(aToolsIndex);
101       GeomShapePtr aTool = aToolAttr->value();
102       if (!aTool.get()) {
103         // It could be a construction plane.
104         ResultPtr aContext = aToolAttr->context();
105         aPlanes.push_back(aToolAttr->context()->shape());
106       } else {
107         aTools.push_back(aTool);
108       }
109     }
110   }
111
112   if ((anObjects.empty() && aCompSolidsObjects.empty())
113       || (!isSimpleMode && aTools.empty() && aPlanes.empty())) {
114     std::string aFeatureError = "Error: Not enough objects for boolean operation.";
115     setError(aFeatureError);
116     return;
117   }
118
119   int aResultIndex = 0;
120   GeomAlgoAPI_MakeShapeList aMakeShapeList;
121   GeomAPI_DataMapOfShapeShape aMapOfShapes;
122
123   if (isSimpleMode)
124   {
125     ListOfShape::iterator anObjectsIt = anObjects.begin();
126     GeomShapePtr aShape = *anObjectsIt;
127     for (++anObjectsIt; anObjectsIt != anObjects.end(); ++anObjectsIt) {
128       std::shared_ptr<GeomAlgoAPI_Boolean> aCommonAlgo(
129         new GeomAlgoAPI_Boolean(aShape,
130                                 *anObjectsIt,
131                                 GeomAlgoAPI_Boolean::BOOL_COMMON));
132
133       if (!aCommonAlgo->isDone()) {
134         std::string aFeatureError = "Error: An algorithm failed.";
135         setError(aFeatureError);
136         return;
137       }
138       if (aCommonAlgo->shape()->isNull()) {
139         static const std::string aShapeError = "Error: Resulting shape is Null.";
140         setError(aShapeError);
141         return;
142       }
143       if (!aCommonAlgo->isValid()) {
144         std::string aFeatureError = "Error: Resulting shape is not valid.";
145         setError(aFeatureError);
146         return;
147       }
148
149       aShape = aCommonAlgo->shape();
150       aMakeShapeList.appendAlgo(aCommonAlgo);
151       aMapOfShapes.merge(aCommonAlgo->mapOfSubShapes());
152     }
153
154     GeomAPI_ShapeIterator aShapeIt(aShape);
155     if (aShapeIt.more() || aShape->shapeType() == GeomAPI_Shape::VERTEX) {
156       std::shared_ptr<ModelAPI_ResultBody> aResultBody =
157         document()->createBody(data(), aResultIndex);
158
159       loadNamingDS(aResultBody, anObjects.front(), anObjects, aShape, aMakeShapeList, aMapOfShapes);
160       setResult(aResultBody, aResultIndex);
161       aResultIndex++;
162     }
163   } else {
164     for (ListOfShape::iterator anObjectsIt = anObjects.begin();
165          anObjectsIt != anObjects.end();
166          ++anObjectsIt)
167     {
168       std::shared_ptr<GeomAPI_Shape> anObject = *anObjectsIt;
169       ListOfShape aListWithObject;
170       aListWithObject.push_back(anObject);
171       GeomAlgoAPI_MakeShapeList aMakeShapeList;
172       std::shared_ptr<GeomAlgoAPI_MakeShape> aBoolAlgo;
173       GeomShapePtr aResShape;
174
175       std::list<std::shared_ptr<GeomAPI_Pnt> > aBoundingPoints =
176         GeomAlgoAPI_ShapeTools::getBoundingBox(aListWithObject, 1.0);
177
178       // Resize planes.
179       ListOfShape aToolsWithPlanes = aTools;
180       for (ListOfShape::const_iterator anIt = aPlanes.cbegin();
181            anIt != aPlanes.cend();
182            ++anIt) {
183         GeomShapePtr aPlane = *anIt;
184         GeomShapePtr aTool = GeomAlgoAPI_ShapeTools::fitPlaneToBox(aPlane, aBoundingPoints);
185         std::shared_ptr<GeomAlgoAPI_MakeShapeCustom> aMkShCustom(
186           new GeomAlgoAPI_MakeShapeCustom);
187         aMkShCustom->addModified(aPlane, aTool);
188         aMakeShapeList.appendAlgo(aMkShCustom);
189         aToolsWithPlanes.push_back(aTool);
190       }
191
192       aBoolAlgo.reset(new GeomAlgoAPI_Boolean(aListWithObject,
193         aToolsWithPlanes,
194         GeomAlgoAPI_Boolean::BOOL_COMMON));
195       aResShape = aBoolAlgo->shape();
196
197       // Checking that the algorithm worked properly.
198       if (!aBoolAlgo->isDone()) {
199         static const std::string aFeatureError = "Error: Boolean algorithm failed.";
200         setError(aFeatureError);
201         return;
202       }
203       if (aResShape->isNull()) {
204         static const std::string aShapeError = "Error: Resulting shape is Null.";
205         setError(aShapeError);
206         return;
207       }
208       if (!aBoolAlgo->isValid()) {
209         std::string aFeatureError = "Error: Resulting shape is not valid.";
210         setError(aFeatureError);
211         return;
212       }
213
214       aMakeShapeList.appendAlgo(aBoolAlgo);
215
216       GeomAPI_ShapeIterator aShapeIt(aResShape);
217       if (aShapeIt.more() || aResShape->shapeType() == GeomAPI_Shape::VERTEX) {
218         std::shared_ptr<ModelAPI_ResultBody> aResultBody =
219           document()->createBody(data(), aResultIndex);
220
221         loadNamingDS(aResultBody, anObject, aTools, aResShape,
222                      aMakeShapeList, *(aBoolAlgo->mapOfSubShapes()));
223         setResult(aResultBody, aResultIndex);
224         aResultIndex++;
225       }
226     }
227   }
228
229   // remove the rest results if there were produced in the previous pass
230   removeResults(aResultIndex);
231 }
232
233 //==================================================================================================
234 void FeaturesPlugin_BooleanCommon::loadNamingDS(ResultBodyPtr theResultBody,
235                                                 const GeomShapePtr theBaseShape,
236                                                 const ListOfShape& theTools,
237                                                 const GeomShapePtr theResultShape,
238                                                 GeomAlgoAPI_MakeShape& theMakeShape,
239                                                 GeomAPI_DataMapOfShapeShape& theMapOfShapes)
240 {
241   //load result
242   if (theBaseShape->isEqual(theResultShape)) {
243     theResultBody->store(theResultShape, false);
244   } else {
245     const int aModifyVTag = 1;
246     const int aModifyETag = 2;
247     const int aModifyFTag = 3;
248     const int aDeletedTag = 4;
249     /// sub solids will be placed at labels 5, 6, etc. if result is compound of solids
250     const int aSubsolidsTag = 5;
251
252     theResultBody->storeModified(theBaseShape, theResultShape, aSubsolidsTag);
253
254     const std::string aModVName = "Modified_Vertex";
255     const std::string aModEName = "Modified_Edge";
256     const std::string aModFName = "Modified_Face";
257
258     theResultBody->loadAndOrientModifiedShapes(&theMakeShape, theBaseShape, GeomAPI_Shape::VERTEX,
259                                                aModifyVTag, aModVName, theMapOfShapes, false,
260                                                false, true);
261     theResultBody->loadAndOrientModifiedShapes(&theMakeShape, theBaseShape, GeomAPI_Shape::EDGE,
262                                                aModifyETag, aModEName, theMapOfShapes, false,
263                                                false, true);
264     theResultBody->loadAndOrientModifiedShapes(&theMakeShape, theBaseShape, GeomAPI_Shape::FACE,
265                                                aModifyFTag, aModFName, theMapOfShapes, false,
266                                                false, true);
267
268     theResultBody->loadDeletedShapes(&theMakeShape, theBaseShape,
269                                      GeomAPI_Shape::VERTEX, aDeletedTag);
270     theResultBody->loadDeletedShapes(&theMakeShape, theBaseShape,
271                                      GeomAPI_Shape::EDGE, aDeletedTag);
272     theResultBody->loadDeletedShapes(&theMakeShape, theBaseShape,
273                                      GeomAPI_Shape::FACE, aDeletedTag);
274
275     for (ListOfShape::const_iterator anIter = theTools.begin(); anIter != theTools.end(); anIter++)
276     {
277       theResultBody->loadAndOrientModifiedShapes(&theMakeShape, *anIter, GeomAPI_Shape::VERTEX,
278                                                  aModifyVTag, aModVName, theMapOfShapes, false,
279                                                  false, true);
280
281       theResultBody->loadAndOrientModifiedShapes(&theMakeShape, *anIter, GeomAPI_Shape::EDGE,
282                                                  aModifyETag, aModEName, theMapOfShapes, false,
283                                                  false, true);
284
285       theResultBody->loadAndOrientModifiedShapes(&theMakeShape, *anIter, GeomAPI_Shape::FACE,
286                                                  aModifyFTag, aModFName, theMapOfShapes, false,
287                                                  false, true);
288
289       theResultBody->loadDeletedShapes(&theMakeShape, *anIter, GeomAPI_Shape::VERTEX, aDeletedTag);
290       theResultBody->loadDeletedShapes(&theMakeShape, *anIter, GeomAPI_Shape::EDGE, aDeletedTag);
291       theResultBody->loadDeletedShapes(&theMakeShape, *anIter, GeomAPI_Shape::FACE, aDeletedTag);
292     }
293   }
294 }