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);
81 if (aResCompSolidPtr.get())
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;
88 std::map<std::shared_ptr<GeomAPI_Shape>, ListOfShape>::iterator
90 for (; anIt != aMap.end(); anIt++) {
91 if (anIt->first->isEqual(aContextShape)) {
92 aMap[anIt->first].push_back(anObject);
96 if (anIt == aMap.end()) {
97 aMap[aContextShape].push_back(anObject);
102 anObjects.push_back(anObject);
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();
113 // It could be a construction plane.
114 ResultPtr aContext = aToolAttr->context();
115 aPlanes.push_back(aToolAttr->context()->shape());
117 aTools.push_back(aTool);
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);
129 int aResultIndex = 0;
130 std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeShapeList(new GeomAlgoAPI_MakeShapeList());
131 std::vector<FeaturesPlugin_Tools::ResultBaseAlgo> aResultBaseAlgoList;
132 ListOfShape aResultShapesList;
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,
142 GeomAlgoAPI_Boolean::BOOL_COMMON));
144 if (!aCommonAlgo->isDone()) {
145 std::string aFeatureError = "Error: An algorithm failed.";
146 setError(aFeatureError);
149 if (aCommonAlgo->shape()->isNull()) {
150 static const std::string aShapeError = "Error: Resulting shape is Null.";
151 setError(aShapeError);
154 if (!aCommonAlgo->isValid()) {
155 std::string aFeatureError = "Error: Resulting shape is not valid.";
156 setError(aFeatureError);
160 aShape = aCommonAlgo->shape();
161 aMakeShapeList->appendAlgo(aCommonAlgo);
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);
169 GeomShapePtr aBaseShape = anObjects.front();
170 anObjects.pop_front();
171 FeaturesPlugin_Tools::loadModifiedShapes(aResultBody,
176 setResult(aResultBody, aResultIndex);
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);
188 for (ListOfShape::iterator anObjectsIt = anObjects.begin();
189 anObjectsIt != anObjects.end();
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;
199 std::list<std::shared_ptr<GeomAPI_Pnt> > aBoundingPoints =
200 GeomAlgoAPI_ShapeTools::getBoundingBox(aListWithObject, 1.0);
203 ListOfShape aToolsWithPlanes = aTools;
204 for (ListOfShape::const_iterator anIt = aPlanes.cbegin();
205 anIt != aPlanes.cend();
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);
216 aBoolAlgo.reset(new GeomAlgoAPI_Boolean(aListWithObject,
218 GeomAlgoAPI_Boolean::BOOL_COMMON));
219 aResShape = aBoolAlgo->shape();
221 // Checking that the algorithm worked properly.
222 if (!aBoolAlgo->isDone()) {
223 static const std::string aFeatureError = "Error: Boolean algorithm failed.";
224 setError(aFeatureError);
227 if (aResShape->isNull()) {
228 static const std::string aShapeError = "Error: Resulting shape is Null.";
229 setError(aShapeError);
232 if (!aBoolAlgo->isValid()) {
233 std::string aFeatureError = "Error: Resulting shape is not valid.";
234 setError(aFeatureError);
238 aMakeShapeList->appendAlgo(aBoolAlgo);
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);
245 FeaturesPlugin_Tools::loadModifiedShapes(aResultBody,
250 setResult(aResultBody, aResultIndex);
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);
262 // Compsolids handling
263 for (std::map<std::shared_ptr<GeomAPI_Shape>, ListOfShape>::iterator
264 anIt = aCompSolidsObjects.begin();
265 anIt != aCompSolidsObjects.end();
268 std::shared_ptr<GeomAPI_Shape> aCompSolid = anIt->first;
269 ListOfShape& aUsedInOperationSolids = anIt->second;
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);
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)) {
284 if (aUsedIt == aUsedInOperationSolids.end()) {
285 aNotUsedSolids.push_back(aSolidInCompSolid);
289 std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeShapeList(new GeomAlgoAPI_MakeShapeList());
290 std::shared_ptr<GeomAlgoAPI_Boolean> aCommonAlgo(
291 new GeomAlgoAPI_Boolean(aUsedInOperationSolids,
293 GeomAlgoAPI_Boolean::BOOL_COMMON));
295 // Checking that the algorithm worked properly.
296 if (!aCommonAlgo->isDone()) {
297 static const std::string aFeatureError = "Error: Boolean algorithm failed.";
298 setError(aFeatureError);
301 if (aCommonAlgo->shape()->isNull()) {
302 static const std::string aShapeError = "Error: Resulting shape is Null.";
303 setError(aShapeError);
306 if (!aCommonAlgo->isValid()) {
307 std::string aFeatureError = "Error: Resulting shape is not valid.";
308 setError(aFeatureError);
312 aMakeShapeList->appendAlgo(aCommonAlgo);
313 GeomShapePtr aResultShape = aCommonAlgo->shape();
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);
327 aMakeShapeList->appendAlgo(aFillerAlgo);
328 aResultShape = aFillerAlgo->shape();
331 GeomAPI_ShapeIterator aShapeIt(aResultShape);
332 if (aShapeIt.more() || aResultShape->shapeType() == GeomAPI_Shape::VERTEX)
334 std::shared_ptr<ModelAPI_ResultBody> aResultBody =
335 document()->createBody(data(), aResultIndex);
337 FeaturesPlugin_Tools::loadModifiedShapes(aResultBody,
342 setResult(aResultBody, aResultIndex);
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);
354 // Compounds handling
355 for (std::map<std::shared_ptr<GeomAPI_Shape>, ListOfShape>::iterator
356 anIt = aCompoundObjects.begin();
357 anIt != aCompoundObjects.end();
360 std::shared_ptr<GeomAPI_Shape> aCompound = anIt->first;
361 ListOfShape& aUsedInOperationShapes = anIt->second;
363 // Collecting shapes from compound which will not be modified in boolean operation.
364 ListOfShape aNotUsedShapes;
365 for (GeomAPI_ShapeIterator aCompIt(aCompound);
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)) {
376 if (aUsedIt == aUsedInOperationShapes.end()) {
377 aNotUsedShapes.push_back(aShapeInCompound);
381 std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeShapeList(new GeomAlgoAPI_MakeShapeList());
382 std::shared_ptr<GeomAlgoAPI_Boolean> aCommonAlgo(
383 new GeomAlgoAPI_Boolean(aUsedInOperationShapes,
385 GeomAlgoAPI_Boolean::BOOL_COMMON));
387 // Checking that the algorithm worked properly.
388 if (!aCommonAlgo->isDone()) {
389 static const std::string aFeatureError = "Error: Boolean algorithm failed.";
390 setError(aFeatureError);
393 if (aCommonAlgo->shape()->isNull()) {
394 static const std::string aShapeError = "Error: Resulting shape is Null.";
395 setError(aShapeError);
398 if (!aCommonAlgo->isValid()) {
399 std::string aFeatureError = "Error: Resulting shape is not valid.";
400 setError(aFeatureError);
404 aMakeShapeList->appendAlgo(aCommonAlgo);
405 GeomShapePtr aResultShape = aCommonAlgo->shape();
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());
416 aShapesForResult.push_back(aResultShape);
419 if (aShapesForResult.size() == 1) {
420 aResultShape = aShapesForResult.front();
423 aResultShape = GeomAlgoAPI_CompoundBuilder::compound(aShapesForResult);
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);
432 FeaturesPlugin_Tools::loadModifiedShapes(aResultBody,
437 setResult(aResultBody, aResultIndex);
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);
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);
456 // remove the rest results if there were produced in the previous pass
457 removeResults(aResultIndex);