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>
39 #include <GeomAlgoAPI_Tools.h>
42 //==================================================================================================
43 FeaturesPlugin_BooleanCommon::FeaturesPlugin_BooleanCommon()
44 : FeaturesPlugin_Boolean(FeaturesPlugin_Boolean::BOOL_COMMON)
48 //==================================================================================================
49 void FeaturesPlugin_BooleanCommon::initAttributes()
51 data()->addAttribute(CREATION_METHOD(), ModelAPI_AttributeString::typeId());
53 data()->addAttribute(OBJECT_LIST_ID(), ModelAPI_AttributeSelectionList::typeId());
54 data()->addAttribute(TOOL_LIST_ID(), ModelAPI_AttributeSelectionList::typeId());
57 //==================================================================================================
58 void FeaturesPlugin_BooleanCommon::execute()
60 ListOfShape anObjects, aTools, aPlanes;
61 std::map<std::shared_ptr<GeomAPI_Shape>, ListOfShape> aCompSolidsObjects;
62 std::map<std::shared_ptr<GeomAPI_Shape>, ListOfShape> aCompoundObjects;
64 bool isSimpleMode = false;
66 AttributeStringPtr aCreationMethodAttr = string(CREATION_METHOD());
67 if (aCreationMethodAttr.get()
68 && aCreationMethodAttr->value() == CREATION_METHOD_SIMPLE()) {
73 AttributeSelectionListPtr anObjectsSelList = selectionList(OBJECT_LIST_ID());
74 for (int anObjectsIndex = 0; anObjectsIndex < anObjectsSelList->size(); anObjectsIndex++) {
75 AttributeSelectionPtr anObjectAttr = anObjectsSelList->value(anObjectsIndex);
76 std::shared_ptr<GeomAPI_Shape> anObject = anObjectAttr->value();
77 if (!anObject.get()) {
80 ResultPtr aContext = anObjectAttr->context();
81 ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
83 && aResCompSolidPtr.get())
85 std::shared_ptr<GeomAPI_Shape> aContextShape = aResCompSolidPtr->shape();
86 GeomAPI_Shape::ShapeType aShapeType = aResCompSolidPtr->shape()->shapeType();
87 std::map<std::shared_ptr<GeomAPI_Shape>, ListOfShape>& aMap =
88 aShapeType == GeomAPI_Shape::COMPSOLID ? aCompSolidsObjects : aCompoundObjects;
90 std::map<std::shared_ptr<GeomAPI_Shape>, ListOfShape>::iterator
92 for (; anIt != aMap.end(); anIt++) {
93 if (anIt->first->isEqual(aContextShape)) {
94 aMap[anIt->first].push_back(anObject);
98 if (anIt == aMap.end()) {
99 aMap[aContextShape].push_back(anObject);
104 anObjects.push_back(anObject);
110 AttributeSelectionListPtr aToolsSelList = selectionList(FeaturesPlugin_Boolean::TOOL_LIST_ID());
111 for (int aToolsIndex = 0; aToolsIndex < aToolsSelList->size(); aToolsIndex++) {
112 AttributeSelectionPtr aToolAttr = aToolsSelList->value(aToolsIndex);
113 GeomShapePtr aTool = aToolAttr->value();
115 // It could be a construction plane.
116 ResultPtr aContext = aToolAttr->context();
117 aPlanes.push_back(aToolAttr->context()->shape());
119 aTools.push_back(aTool);
124 if ((anObjects.empty() && aCompSolidsObjects.empty() && aCompoundObjects.empty())
125 || (!isSimpleMode && aTools.empty() && aPlanes.empty())) {
126 std::string aFeatureError = "Error: Not enough objects for boolean operation.";
127 setError(aFeatureError);
131 int aResultIndex = 0;
133 std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeShapeList(new GeomAlgoAPI_MakeShapeList());
134 std::vector<FeaturesPlugin_Tools::ResultBaseAlgo> aResultBaseAlgoList;
135 ListOfShape aResultShapesList;
139 ListOfShape::iterator anObjectsIt = anObjects.begin();
140 GeomShapePtr aShape = *anObjectsIt;
141 for (++anObjectsIt; anObjectsIt != anObjects.end(); ++anObjectsIt) {
142 std::shared_ptr<GeomAlgoAPI_Boolean> aCommonAlgo(
143 new GeomAlgoAPI_Boolean(aShape,
145 GeomAlgoAPI_Boolean::BOOL_COMMON));
147 if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aCommonAlgo, getKind(), anError)) {
152 aShape = aCommonAlgo->shape();
153 aMakeShapeList->appendAlgo(aCommonAlgo);
156 GeomAPI_ShapeIterator aShapeIt(aShape);
157 if (aShapeIt.more() || aShape->shapeType() == GeomAPI_Shape::VERTEX) {
158 std::shared_ptr<ModelAPI_ResultBody> aResultBody =
159 document()->createBody(data(), aResultIndex);
161 GeomShapePtr aBaseShape = anObjects.front();
162 anObjects.pop_front();
163 FeaturesPlugin_Tools::loadModifiedShapes(aResultBody,
168 setResult(aResultBody, aResultIndex);
172 FeaturesPlugin_Tools::ResultBaseAlgo aRBA;
173 aRBA.resultBody = aResultBody;
174 aRBA.baseShape = aBaseShape;
175 aRBA.makeShape = aMakeShapeList;
176 aResultBaseAlgoList.push_back(aRBA);
177 aResultShapesList.push_back(aShape);
180 for (ListOfShape::iterator anObjectsIt = anObjects.begin();
181 anObjectsIt != anObjects.end();
184 std::shared_ptr<GeomAPI_Shape> anObject = *anObjectsIt;
185 ListOfShape aListWithObject;
186 aListWithObject.push_back(anObject);
187 std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeShapeList(new GeomAlgoAPI_MakeShapeList());
188 std::shared_ptr<GeomAlgoAPI_MakeShape> aBoolAlgo;
189 GeomShapePtr aResShape;
191 std::list<std::shared_ptr<GeomAPI_Pnt> > aBoundingPoints =
192 GeomAlgoAPI_ShapeTools::getBoundingBox(aListWithObject, 1.0);
195 ListOfShape aToolsWithPlanes = aTools;
196 for (ListOfShape::const_iterator anIt = aPlanes.cbegin();
197 anIt != aPlanes.cend();
199 GeomShapePtr aPlane = *anIt;
200 GeomShapePtr aTool = GeomAlgoAPI_ShapeTools::fitPlaneToBox(aPlane, aBoundingPoints);
201 std::shared_ptr<GeomAlgoAPI_MakeShapeCustom> aMkShCustom(
202 new GeomAlgoAPI_MakeShapeCustom);
203 aMkShCustom->addModified(aPlane, aTool);
204 aMakeShapeList->appendAlgo(aMkShCustom);
205 aToolsWithPlanes.push_back(aTool);
208 aBoolAlgo.reset(new GeomAlgoAPI_Boolean(aListWithObject,
210 GeomAlgoAPI_Boolean::BOOL_COMMON));
211 aResShape = aBoolAlgo->shape();
213 // Checking that the algorithm worked properly.
214 if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aBoolAlgo, getKind(), anError)) {
219 aMakeShapeList->appendAlgo(aBoolAlgo);
221 GeomAPI_ShapeIterator aShapeIt(aResShape);
222 if (aShapeIt.more() || aResShape->shapeType() == GeomAPI_Shape::VERTEX) {
223 std::shared_ptr<ModelAPI_ResultBody> aResultBody =
224 document()->createBody(data(), aResultIndex);
226 FeaturesPlugin_Tools::loadModifiedShapes(aResultBody,
231 setResult(aResultBody, aResultIndex);
234 FeaturesPlugin_Tools::ResultBaseAlgo aRBA;
235 aRBA.resultBody = aResultBody;
236 aRBA.baseShape = anObject;
237 aRBA.makeShape = aMakeShapeList;
238 aResultBaseAlgoList.push_back(aRBA);
239 aResultShapesList.push_back(aResShape);
243 // Compsolids handling
244 for (std::map<std::shared_ptr<GeomAPI_Shape>, ListOfShape>::iterator
245 anIt = aCompSolidsObjects.begin();
246 anIt != aCompSolidsObjects.end();
249 std::shared_ptr<GeomAPI_Shape> aCompSolid = anIt->first;
250 ListOfShape& aUsedInOperationSolids = anIt->second;
252 // Collecting solids from compsolids which will not be modified in boolean operation.
253 ListOfShape aNotUsedSolids;
254 for (GeomAPI_ShapeExplorer anExp(aCompSolid, GeomAPI_Shape::SOLID);
258 std::shared_ptr<GeomAPI_Shape> aSolidInCompSolid = anExp.current();
259 ListOfShape::iterator aUsedIt = aUsedInOperationSolids.begin();
260 for (; aUsedIt != aUsedInOperationSolids.end(); aUsedIt++) {
261 if (aSolidInCompSolid->isEqual(*aUsedIt)) {
265 if (aUsedIt == aUsedInOperationSolids.end()) {
266 aNotUsedSolids.push_back(aSolidInCompSolid);
270 std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeShapeList(new GeomAlgoAPI_MakeShapeList());
271 std::shared_ptr<GeomAlgoAPI_Boolean> aCommonAlgo(
272 new GeomAlgoAPI_Boolean(aUsedInOperationSolids,
274 GeomAlgoAPI_Boolean::BOOL_COMMON));
276 // Checking that the algorithm worked properly.
277 if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aCommonAlgo, getKind(), anError)) {
282 aMakeShapeList->appendAlgo(aCommonAlgo);
283 GeomShapePtr aResultShape = aCommonAlgo->shape();
285 // Add result to not used solids from compsolid.
286 if (!aNotUsedSolids.empty()) {
287 ListOfShape aShapesToAdd = aNotUsedSolids;
288 aShapesToAdd.push_back(aCommonAlgo->shape());
289 std::shared_ptr<GeomAlgoAPI_PaveFiller> aFillerAlgo(
290 new GeomAlgoAPI_PaveFiller(aShapesToAdd, true));
291 if (!aFillerAlgo->isDone()) {
292 std::string aFeatureError = "Error: PaveFiller algorithm failed.";
293 setError(aFeatureError);
297 aMakeShapeList->appendAlgo(aFillerAlgo);
298 aResultShape = aFillerAlgo->shape();
301 GeomAPI_ShapeIterator aShapeIt(aResultShape);
302 if (aShapeIt.more() || aResultShape->shapeType() == GeomAPI_Shape::VERTEX)
304 std::shared_ptr<ModelAPI_ResultBody> aResultBody =
305 document()->createBody(data(), aResultIndex);
307 FeaturesPlugin_Tools::loadModifiedShapes(aResultBody,
312 setResult(aResultBody, aResultIndex);
315 FeaturesPlugin_Tools::ResultBaseAlgo aRBA;
316 aRBA.resultBody = aResultBody;
317 aRBA.baseShape = aCompSolid;
318 aRBA.makeShape = aMakeShapeList;
319 aResultBaseAlgoList.push_back(aRBA);
320 aResultShapesList.push_back(aResultShape);
324 // Compounds handling
325 for (std::map<std::shared_ptr<GeomAPI_Shape>, ListOfShape>::iterator
326 anIt = aCompoundObjects.begin();
327 anIt != aCompoundObjects.end();
330 std::shared_ptr<GeomAPI_Shape> aCompound = anIt->first;
331 ListOfShape& aUsedInOperationShapes = anIt->second;
333 // Collecting shapes from compound which will not be modified in boolean operation.
334 ListOfShape aNotUsedShapes;
335 for (GeomAPI_ShapeIterator aCompIt(aCompound);
339 std::shared_ptr<GeomAPI_Shape> aShapeInCompound = aCompIt.current();
340 ListOfShape::iterator aUsedIt = aUsedInOperationShapes.begin();
341 for (; aUsedIt != aUsedInOperationShapes.end(); aUsedIt++) {
342 if (aShapeInCompound->isEqual(*aUsedIt)) {
346 if (aUsedIt == aUsedInOperationShapes.end()) {
347 aNotUsedShapes.push_back(aShapeInCompound);
351 std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeShapeList(new GeomAlgoAPI_MakeShapeList());
352 std::shared_ptr<GeomAlgoAPI_Boolean> aCommonAlgo(
353 new GeomAlgoAPI_Boolean(aUsedInOperationShapes,
355 GeomAlgoAPI_Boolean::BOOL_COMMON));
357 // Checking that the algorithm worked properly.
358 if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aCommonAlgo, getKind(), anError)) {
363 aMakeShapeList->appendAlgo(aCommonAlgo);
364 GeomShapePtr aResultShape = aCommonAlgo->shape();
366 // Add result to not used shape from compound.
367 if (!aNotUsedShapes.empty()) {
368 ListOfShape aShapesForResult = aNotUsedShapes;
369 if (aResultShape->shapeType() == GeomAPI_Shape::COMPOUND) {
370 for (GeomAPI_ShapeIterator aResultIt(aResultShape); aResultIt.more(); aResultIt.next()) {
371 aShapesForResult.push_back(aResultIt.current());
375 aShapesForResult.push_back(aResultShape);
378 if (aShapesForResult.size() == 1) {
379 aResultShape = aShapesForResult.front();
382 aResultShape = GeomAlgoAPI_CompoundBuilder::compound(aShapesForResult);
386 GeomAPI_ShapeIterator aShapeIt(aResultShape);
387 if (aShapeIt.more() || aResultShape->shapeType() == GeomAPI_Shape::VERTEX) {
388 std::shared_ptr<ModelAPI_ResultBody> aResultBody =
389 document()->createBody(data(), aResultIndex);
391 FeaturesPlugin_Tools::loadModifiedShapes(aResultBody,
396 setResult(aResultBody, aResultIndex);
399 FeaturesPlugin_Tools::ResultBaseAlgo aRBA;
400 aRBA.resultBody = aResultBody;
401 aRBA.baseShape = aCompound;
402 aRBA.makeShape = aMakeShapeList;
403 aResultBaseAlgoList.push_back(aRBA);
404 aResultShapesList.push_back(aResultShape);
410 // Store deleted shapes after all results has been proceeded. This is to avoid issue when in one
411 // result shape has been deleted, but in another it was modified or stayed.
412 GeomShapePtr aResultShapesCompound = GeomAlgoAPI_CompoundBuilder::compound(aResultShapesList);
413 FeaturesPlugin_Tools::loadDeletedShapes(aResultBaseAlgoList, aTools, aResultShapesCompound);
415 // remove the rest results if there were produced in the previous pass
416 removeResults(aResultIndex);