1 // Copyright (C) 2014-2017 CEA/DEN, EDF R&D
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.
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.
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
17 // See http://www.salome-platform.org/ or
18 // email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
21 #include "FeaturesPlugin_BooleanCommon.h"
23 #include "FeaturesPlugin_Tools.h"
25 #include <ModelAPI_ResultBody.h>
26 #include <ModelAPI_AttributeSelectionList.h>
27 #include <ModelAPI_AttributeString.h>
28 #include <ModelAPI_Tools.h>
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>
41 //==================================================================================================
42 FeaturesPlugin_BooleanCommon::FeaturesPlugin_BooleanCommon()
43 : FeaturesPlugin_Boolean(FeaturesPlugin_Boolean::BOOL_COMMON)
47 //==================================================================================================
48 void FeaturesPlugin_BooleanCommon::initAttributes()
50 data()->addAttribute(CREATION_METHOD(), ModelAPI_AttributeString::typeId());
52 data()->addAttribute(OBJECT_LIST_ID(), ModelAPI_AttributeSelectionList::typeId());
53 data()->addAttribute(TOOL_LIST_ID(), ModelAPI_AttributeSelectionList::typeId());
56 //==================================================================================================
57 void FeaturesPlugin_BooleanCommon::execute()
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;
63 bool isSimpleMode = false;
65 AttributeStringPtr aCreationMethodAttr = string(CREATION_METHOD());
66 if (aCreationMethodAttr.get()
67 && aCreationMethodAttr->value() == CREATION_METHOD_SIMPLE()) {
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()) {
79 ResultPtr aContext = anObjectAttr->context();
80 ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
82 && aResCompSolidPtr.get())
84 std::shared_ptr<GeomAPI_Shape> aContextShape = aResCompSolidPtr->shape();
85 GeomAPI_Shape::ShapeType aShapeType = aResCompSolidPtr->shape()->shapeType();
86 std::map<std::shared_ptr<GeomAPI_Shape>, ListOfShape>& aMap =
87 aShapeType == GeomAPI_Shape::COMPSOLID ? aCompSolidsObjects : aCompoundObjects;
89 std::map<std::shared_ptr<GeomAPI_Shape>, ListOfShape>::iterator
91 for (; anIt != aMap.end(); anIt++) {
92 if (anIt->first->isEqual(aContextShape)) {
93 aMap[anIt->first].push_back(anObject);
97 if (anIt == aMap.end()) {
98 aMap[aContextShape].push_back(anObject);
103 anObjects.push_back(anObject);
109 AttributeSelectionListPtr aToolsSelList = selectionList(FeaturesPlugin_Boolean::TOOL_LIST_ID());
110 for (int aToolsIndex = 0; aToolsIndex < aToolsSelList->size(); aToolsIndex++) {
111 AttributeSelectionPtr aToolAttr = aToolsSelList->value(aToolsIndex);
112 GeomShapePtr aTool = aToolAttr->value();
114 // It could be a construction plane.
115 ResultPtr aContext = aToolAttr->context();
116 aPlanes.push_back(aToolAttr->context()->shape());
118 aTools.push_back(aTool);
123 if ((anObjects.empty() && aCompSolidsObjects.empty())
124 || (!isSimpleMode && aTools.empty() && aPlanes.empty())) {
125 std::string aFeatureError = "Error: Not enough objects for boolean operation.";
126 setError(aFeatureError);
130 int aResultIndex = 0;
131 std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeShapeList(new GeomAlgoAPI_MakeShapeList());
132 std::vector<FeaturesPlugin_Tools::ResultBaseAlgo> aResultBaseAlgoList;
133 ListOfShape aResultShapesList;
137 ListOfShape::iterator anObjectsIt = anObjects.begin();
138 GeomShapePtr aShape = *anObjectsIt;
139 for (++anObjectsIt; anObjectsIt != anObjects.end(); ++anObjectsIt) {
140 std::shared_ptr<GeomAlgoAPI_Boolean> aCommonAlgo(
141 new GeomAlgoAPI_Boolean(aShape,
143 GeomAlgoAPI_Boolean::BOOL_COMMON));
145 if (!aCommonAlgo->isDone()) {
146 std::string aFeatureError = "Error: An algorithm failed.";
147 setError(aFeatureError);
150 if (aCommonAlgo->shape()->isNull()) {
151 static const std::string aShapeError = "Error: Resulting shape is Null.";
152 setError(aShapeError);
155 if (!aCommonAlgo->isValid()) {
156 std::string aFeatureError = "Error: Resulting shape is not valid.";
157 setError(aFeatureError);
161 aShape = aCommonAlgo->shape();
162 aMakeShapeList->appendAlgo(aCommonAlgo);
165 GeomAPI_ShapeIterator aShapeIt(aShape);
166 if (aShapeIt.more() || aShape->shapeType() == GeomAPI_Shape::VERTEX) {
167 std::shared_ptr<ModelAPI_ResultBody> aResultBody =
168 document()->createBody(data(), aResultIndex);
170 GeomShapePtr aBaseShape = anObjects.front();
171 anObjects.pop_front();
172 FeaturesPlugin_Tools::loadModifiedShapes(aResultBody,
177 setResult(aResultBody, aResultIndex);
181 FeaturesPlugin_Tools::ResultBaseAlgo aRBA;
182 aRBA.resultBody = aResultBody;
183 aRBA.baseShape = aBaseShape;
184 aRBA.makeShape = aMakeShapeList;
185 aResultBaseAlgoList.push_back(aRBA);
186 aResultShapesList.push_back(aShape);
189 for (ListOfShape::iterator anObjectsIt = anObjects.begin();
190 anObjectsIt != anObjects.end();
193 std::shared_ptr<GeomAPI_Shape> anObject = *anObjectsIt;
194 ListOfShape aListWithObject;
195 aListWithObject.push_back(anObject);
196 std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeShapeList(new GeomAlgoAPI_MakeShapeList());
197 std::shared_ptr<GeomAlgoAPI_MakeShape> aBoolAlgo;
198 GeomShapePtr aResShape;
200 std::list<std::shared_ptr<GeomAPI_Pnt> > aBoundingPoints =
201 GeomAlgoAPI_ShapeTools::getBoundingBox(aListWithObject, 1.0);
204 ListOfShape aToolsWithPlanes = aTools;
205 for (ListOfShape::const_iterator anIt = aPlanes.cbegin();
206 anIt != aPlanes.cend();
208 GeomShapePtr aPlane = *anIt;
209 GeomShapePtr aTool = GeomAlgoAPI_ShapeTools::fitPlaneToBox(aPlane, aBoundingPoints);
210 std::shared_ptr<GeomAlgoAPI_MakeShapeCustom> aMkShCustom(
211 new GeomAlgoAPI_MakeShapeCustom);
212 aMkShCustom->addModified(aPlane, aTool);
213 aMakeShapeList->appendAlgo(aMkShCustom);
214 aToolsWithPlanes.push_back(aTool);
217 aBoolAlgo.reset(new GeomAlgoAPI_Boolean(aListWithObject,
219 GeomAlgoAPI_Boolean::BOOL_COMMON));
220 aResShape = aBoolAlgo->shape();
222 // Checking that the algorithm worked properly.
223 if (!aBoolAlgo->isDone()) {
224 static const std::string aFeatureError = "Error: Boolean algorithm failed.";
225 setError(aFeatureError);
228 if (aResShape->isNull()) {
229 static const std::string aShapeError = "Error: Resulting shape is Null.";
230 setError(aShapeError);
233 if (!aBoolAlgo->isValid()) {
234 std::string aFeatureError = "Error: Resulting shape is not valid.";
235 setError(aFeatureError);
239 aMakeShapeList->appendAlgo(aBoolAlgo);
241 GeomAPI_ShapeIterator aShapeIt(aResShape);
242 if (aShapeIt.more() || aResShape->shapeType() == GeomAPI_Shape::VERTEX) {
243 std::shared_ptr<ModelAPI_ResultBody> aResultBody =
244 document()->createBody(data(), aResultIndex);
246 FeaturesPlugin_Tools::loadModifiedShapes(aResultBody,
251 setResult(aResultBody, aResultIndex);
254 FeaturesPlugin_Tools::ResultBaseAlgo aRBA;
255 aRBA.resultBody = aResultBody;
256 aRBA.baseShape = anObject;
257 aRBA.makeShape = aMakeShapeList;
258 aResultBaseAlgoList.push_back(aRBA);
259 aResultShapesList.push_back(aResShape);
263 // Compsolids handling
264 for (std::map<std::shared_ptr<GeomAPI_Shape>, ListOfShape>::iterator
265 anIt = aCompSolidsObjects.begin();
266 anIt != aCompSolidsObjects.end();
269 std::shared_ptr<GeomAPI_Shape> aCompSolid = anIt->first;
270 ListOfShape& aUsedInOperationSolids = anIt->second;
272 // Collecting solids from compsolids which will not be modified in boolean operation.
273 ListOfShape aNotUsedSolids;
274 for (GeomAPI_ShapeExplorer anExp(aCompSolid, GeomAPI_Shape::SOLID);
278 std::shared_ptr<GeomAPI_Shape> aSolidInCompSolid = anExp.current();
279 ListOfShape::iterator aUsedIt = aUsedInOperationSolids.begin();
280 for (; aUsedIt != aUsedInOperationSolids.end(); aUsedIt++) {
281 if (aSolidInCompSolid->isEqual(*aUsedIt)) {
285 if (aUsedIt == aUsedInOperationSolids.end()) {
286 aNotUsedSolids.push_back(aSolidInCompSolid);
290 std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeShapeList(new GeomAlgoAPI_MakeShapeList());
291 std::shared_ptr<GeomAlgoAPI_Boolean> aCommonAlgo(
292 new GeomAlgoAPI_Boolean(aUsedInOperationSolids,
294 GeomAlgoAPI_Boolean::BOOL_COMMON));
296 // Checking that the algorithm worked properly.
297 if (!aCommonAlgo->isDone()) {
298 static const std::string aFeatureError = "Error: Boolean algorithm failed.";
299 setError(aFeatureError);
302 if (aCommonAlgo->shape()->isNull()) {
303 static const std::string aShapeError = "Error: Resulting shape is Null.";
304 setError(aShapeError);
307 if (!aCommonAlgo->isValid()) {
308 std::string aFeatureError = "Error: Resulting shape is not valid.";
309 setError(aFeatureError);
313 aMakeShapeList->appendAlgo(aCommonAlgo);
314 GeomShapePtr aResultShape = aCommonAlgo->shape();
316 // Add result to not used solids from compsolid.
317 if (!aNotUsedSolids.empty()) {
318 ListOfShape aShapesToAdd = aNotUsedSolids;
319 aShapesToAdd.push_back(aCommonAlgo->shape());
320 std::shared_ptr<GeomAlgoAPI_PaveFiller> aFillerAlgo(
321 new GeomAlgoAPI_PaveFiller(aShapesToAdd, true));
322 if (!aFillerAlgo->isDone()) {
323 std::string aFeatureError = "Error: PaveFiller algorithm failed.";
324 setError(aFeatureError);
328 aMakeShapeList->appendAlgo(aFillerAlgo);
329 aResultShape = aFillerAlgo->shape();
332 GeomAPI_ShapeIterator aShapeIt(aResultShape);
333 if (aShapeIt.more() || aResultShape->shapeType() == GeomAPI_Shape::VERTEX)
335 std::shared_ptr<ModelAPI_ResultBody> aResultBody =
336 document()->createBody(data(), aResultIndex);
338 FeaturesPlugin_Tools::loadModifiedShapes(aResultBody,
343 setResult(aResultBody, aResultIndex);
346 FeaturesPlugin_Tools::ResultBaseAlgo aRBA;
347 aRBA.resultBody = aResultBody;
348 aRBA.baseShape = aCompSolid;
349 aRBA.makeShape = aMakeShapeList;
350 aResultBaseAlgoList.push_back(aRBA);
351 aResultShapesList.push_back(aResultShape);
355 // Compounds handling
356 for (std::map<std::shared_ptr<GeomAPI_Shape>, ListOfShape>::iterator
357 anIt = aCompoundObjects.begin();
358 anIt != aCompoundObjects.end();
361 std::shared_ptr<GeomAPI_Shape> aCompound = anIt->first;
362 ListOfShape& aUsedInOperationShapes = anIt->second;
364 // Collecting shapes from compound which will not be modified in boolean operation.
365 ListOfShape aNotUsedShapes;
366 for (GeomAPI_ShapeIterator aCompIt(aCompound);
370 std::shared_ptr<GeomAPI_Shape> aShapeInCompound = aCompIt.current();
371 ListOfShape::iterator aUsedIt = aUsedInOperationShapes.begin();
372 for (; aUsedIt != aUsedInOperationShapes.end(); aUsedIt++) {
373 if (aShapeInCompound->isEqual(*aUsedIt)) {
377 if (aUsedIt == aUsedInOperationShapes.end()) {
378 aNotUsedShapes.push_back(aShapeInCompound);
382 std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeShapeList(new GeomAlgoAPI_MakeShapeList());
383 std::shared_ptr<GeomAlgoAPI_Boolean> aCommonAlgo(
384 new GeomAlgoAPI_Boolean(aUsedInOperationShapes,
386 GeomAlgoAPI_Boolean::BOOL_COMMON));
388 // Checking that the algorithm worked properly.
389 if (!aCommonAlgo->isDone()) {
390 static const std::string aFeatureError = "Error: Boolean algorithm failed.";
391 setError(aFeatureError);
394 if (aCommonAlgo->shape()->isNull()) {
395 static const std::string aShapeError = "Error: Resulting shape is Null.";
396 setError(aShapeError);
399 if (!aCommonAlgo->isValid()) {
400 std::string aFeatureError = "Error: Resulting shape is not valid.";
401 setError(aFeatureError);
405 aMakeShapeList->appendAlgo(aCommonAlgo);
406 GeomShapePtr aResultShape = aCommonAlgo->shape();
408 // Add result to not used shape from compound.
409 if (!aNotUsedShapes.empty()) {
410 ListOfShape aShapesForResult = aNotUsedShapes;
411 if (aResultShape->shapeType() == GeomAPI_Shape::COMPOUND) {
412 for (GeomAPI_ShapeIterator aResultIt(aResultShape); aResultIt.more(); aResultIt.next()) {
413 aShapesForResult.push_back(aResultIt.current());
417 aShapesForResult.push_back(aResultShape);
420 if (aShapesForResult.size() == 1) {
421 aResultShape = aShapesForResult.front();
424 aResultShape = GeomAlgoAPI_CompoundBuilder::compound(aShapesForResult);
428 GeomAPI_ShapeIterator aShapeIt(aResultShape);
429 if (aShapeIt.more() || aResultShape->shapeType() == GeomAPI_Shape::VERTEX) {
430 std::shared_ptr<ModelAPI_ResultBody> aResultBody =
431 document()->createBody(data(), aResultIndex);
433 FeaturesPlugin_Tools::loadModifiedShapes(aResultBody,
438 setResult(aResultBody, aResultIndex);
441 FeaturesPlugin_Tools::ResultBaseAlgo aRBA;
442 aRBA.resultBody = aResultBody;
443 aRBA.baseShape = aCompound;
444 aRBA.makeShape = aMakeShapeList;
445 aResultBaseAlgoList.push_back(aRBA);
446 aResultShapesList.push_back(aResultShape);
452 // Store deleted shapes after all results has been proceeded. This is to avoid issue when in one
453 // result shape has been deleted, but in another it was modified or stayed.
454 GeomShapePtr aResultShapesCompound = GeomAlgoAPI_CompoundBuilder::compound(aResultShapesList);
455 FeaturesPlugin_Tools::loadDeletedShapes(aResultBaseAlgoList, aTools, aResultShapesCompound);
457 // remove the rest results if there were produced in the previous pass
458 removeResults(aResultIndex);