1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
3 // File: FeaturesPlugin_Boolean.cpp
4 // Created: 02 Sept 2014
5 // Author: Vitaly SMETANNIKOV
7 #include "FeaturesPlugin_Boolean.h"
9 #include <ModelAPI_Data.h>
10 #include <ModelAPI_Document.h>
11 #include <ModelAPI_AttributeReference.h>
12 #include <ModelAPI_AttributeInteger.h>
13 #include <ModelAPI_BodyBuilder.h>
14 #include <ModelAPI_ResultBody.h>
15 #include <ModelAPI_AttributeSelectionList.h>
16 #include <ModelAPI_Session.h>
17 #include <ModelAPI_Validator.h>
18 #include <ModelAPI_Tools.h>
20 #include <GeomAlgoAPI_Boolean.h>
21 #include <GeomAlgoAPI_MakeShapeList.h>
22 #include <GeomAlgoAPI_PaveFiller.h>
23 #include <GeomAlgoAPI_ShapeTools.h>
24 #include <GeomAPI_ShapeExplorer.h>
28 //=================================================================================================
29 FeaturesPlugin_Boolean::FeaturesPlugin_Boolean()
33 //=================================================================================================
34 void FeaturesPlugin_Boolean::initAttributes()
36 data()->addAttribute(FeaturesPlugin_Boolean::TYPE_ID(), ModelAPI_AttributeInteger::typeId());
38 AttributeSelectionListPtr aSelection =
39 std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(data()->addAttribute(
40 FeaturesPlugin_Boolean::OBJECT_LIST_ID(), ModelAPI_AttributeSelectionList::typeId()));
41 // extrusion works with faces always
42 aSelection->setSelectionType("SOLID");
44 aSelection = std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(data()->addAttribute(
45 FeaturesPlugin_Boolean::TOOL_LIST_ID(), ModelAPI_AttributeSelectionList::typeId()));
46 // extrusion works with faces always
47 aSelection->setSelectionType("SOLID");
49 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), OBJECT_LIST_ID());
50 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), TOOL_LIST_ID());
53 //=================================================================================================
54 std::shared_ptr<GeomAPI_Shape> FeaturesPlugin_Boolean::getShape(const std::string& theAttrName)
56 std::shared_ptr<ModelAPI_AttributeReference> aObjRef = std::dynamic_pointer_cast<
57 ModelAPI_AttributeReference>(data()->attribute(theAttrName));
59 std::shared_ptr<ModelAPI_ResultBody> aConstr = std::dynamic_pointer_cast<
60 ModelAPI_ResultBody>(aObjRef->value());
62 return aConstr->shape();
64 return std::shared_ptr<GeomAPI_Shape>();
67 //=================================================================================================
68 void FeaturesPlugin_Boolean::execute()
70 // Getting operation type.
71 std::shared_ptr<ModelAPI_AttributeInteger> aTypeAttr = std::dynamic_pointer_cast<
72 ModelAPI_AttributeInteger>(data()->attribute(FeaturesPlugin_Boolean::TYPE_ID()));
75 GeomAlgoAPI_Boolean::OperationType aType = (GeomAlgoAPI_Boolean::OperationType)aTypeAttr->value();
77 ListOfShape anObjects, aTools;
78 std::map<std::shared_ptr<GeomAPI_Shape>, ListOfShape> aCompSolidsObjects;
81 AttributeSelectionListPtr anObjectsSelList = selectionList(FeaturesPlugin_Boolean::OBJECT_LIST_ID());
82 for(int anObjectsIndex = 0; anObjectsIndex < anObjectsSelList->size(); anObjectsIndex++) {
83 AttributeSelectionPtr anObjectAttr = anObjectsSelList->value(anObjectsIndex);
84 std::shared_ptr<GeomAPI_Shape> anObject = anObjectAttr->value();
88 ResultPtr aContext = anObjectAttr->context();
89 ResultCompSolidPtr aResCompSolidPtr = ModelAPI_Tools::compSolidOwner(aContext);
90 if(aResCompSolidPtr.get()) {
91 std::shared_ptr<GeomAPI_Shape> aContextShape = aResCompSolidPtr->shape();
92 std::map<std::shared_ptr<GeomAPI_Shape>, ListOfShape>::iterator anIt = aCompSolidsObjects.begin();
93 for(; anIt != aCompSolidsObjects.end(); anIt++) {
94 if(anIt->first->isEqual(aContextShape)) {
95 aCompSolidsObjects[anIt->first].push_back(anObject);
99 if(anIt == aCompSolidsObjects.end()) {
100 aCompSolidsObjects[aContextShape].push_back(anObject);
103 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 std::shared_ptr<GeomAPI_Shape> aTool = aToolAttr->value();
115 aTools.push_back(aTool);
118 int aResultIndex = 0;
121 case GeomAlgoAPI_Boolean::BOOL_CUT:
122 case GeomAlgoAPI_Boolean::BOOL_COMMON:{
123 if((anObjects.empty() && aCompSolidsObjects.empty()) || aTools.empty()) {
124 std::string aFeatureError = "Not enough objects for boolean operation";
125 setError(aFeatureError);
129 // For solids cut each object with all tools.
130 for(ListOfShape::iterator anObjectsIt = anObjects.begin(); anObjectsIt != anObjects.end(); anObjectsIt++) {
131 std::shared_ptr<GeomAPI_Shape> anObject = *anObjectsIt;
132 ListOfShape aListWithObject;
133 aListWithObject.push_back(anObject);
134 GeomAlgoAPI_Boolean aBoolAlgo(aListWithObject, aTools, aType);
136 // Checking that the algorithm worked properly.
137 if(!aBoolAlgo.isDone()) {
138 static const std::string aFeatureError = "Boolean algorithm failed";
139 setError(aFeatureError);
142 if(aBoolAlgo.shape()->isNull()) {
143 static const std::string aShapeError = "Resulting shape is Null";
144 setError(aShapeError);
147 if(!aBoolAlgo.isValid()) {
148 std::string aFeatureError = "Warning: resulting shape is not valid";
149 setError(aFeatureError);
153 if(GeomAlgoAPI_ShapeTools::volume(aBoolAlgo.shape()) > 1.e-7) {
154 std::shared_ptr<ModelAPI_ResultBody> aResultBody = document()->createBody(data(), aResultIndex);
155 loadNamingDS(aResultBody, anObject, aTools, aBoolAlgo.shape(), *aBoolAlgo.makeShape(), *aBoolAlgo.mapOfShapes());
156 setResult(aResultBody, aResultIndex);
161 // Compsolids handling
162 for(std::map<std::shared_ptr<GeomAPI_Shape>, ListOfShape>::iterator anIt = aCompSolidsObjects.begin();
163 anIt != aCompSolidsObjects.end(); anIt++) {
164 std::shared_ptr<GeomAPI_Shape> aCompSolid = anIt->first;
165 ListOfShape& aUsedInOperationSolids = anIt->second;
167 // Collecting solids from compsolids which will not be modified in boolean operation.
168 ListOfShape aNotUsedSolids;
169 for(GeomAPI_ShapeExplorer anExp(aCompSolid, GeomAPI_Shape::SOLID); anExp.more(); anExp.next()) {
170 std::shared_ptr<GeomAPI_Shape> aSolidInCompSolid = anExp.current();
171 ListOfShape::iterator anIt = aUsedInOperationSolids.begin();
172 for(; anIt != aUsedInOperationSolids.end(); anIt++) {
173 if(aSolidInCompSolid->isEqual(*anIt)) {
177 if(anIt == aUsedInOperationSolids.end()) {
178 aNotUsedSolids.push_back(aSolidInCompSolid);
182 GeomAlgoAPI_Boolean aBoolAlgo(aUsedInOperationSolids, aTools, aType);
184 // Checking that the algorithm worked properly.
185 if(!aBoolAlgo.isDone()) {
186 static const std::string aFeatureError = "Boolean algorithm failed";
187 setError(aFeatureError);
190 if(aBoolAlgo.shape()->isNull()) {
191 static const std::string aShapeError = "Resulting shape is Null";
192 setError(aShapeError);
195 if(!aBoolAlgo.isValid()) {
196 std::string aFeatureError = "Warning: resulting shape is not valid";
197 setError(aFeatureError);
201 GeomAlgoAPI_MakeShapeList aMakeShapeList;
202 aMakeShapeList.append(aBoolAlgo.makeShape());
203 GeomAPI_DataMapOfShapeShape aMapOfShapes;
204 aMapOfShapes.merge(aBoolAlgo.mapOfShapes());
206 // Add result to not used solids from compsolid.
207 ListOfShape aShapesToAdd = aNotUsedSolids;
208 aShapesToAdd.push_back(aBoolAlgo.shape());
209 GeomAlgoAPI_PaveFiller aFillerAlgo(aShapesToAdd, true);
210 if(!aFillerAlgo.isDone()) {
211 std::string aFeatureError = "PaveFiller algorithm failed";
212 setError(aFeatureError);
216 aMakeShapeList.append(aFillerAlgo.makeShape());
217 aMapOfShapes.merge(aFillerAlgo.mapOfShapes());
219 if(GeomAlgoAPI_ShapeTools::volume(aFillerAlgo.shape()) > 1.e-7) {
220 std::shared_ptr<ModelAPI_ResultBody> aResultBody = document()->createBody(data(), aResultIndex);
221 loadNamingDS(aResultBody, aCompSolid, aTools, aFillerAlgo.shape(), aMakeShapeList, aMapOfShapes);
222 setResult(aResultBody, aResultIndex);
228 case GeomAlgoAPI_Boolean::BOOL_FUSE: {
229 if((anObjects.size() + aTools.size() + aCompSolidsObjects.size()) < 2) {
230 std::string aFeatureError = "Not enough objects for boolean operation";
231 setError(aFeatureError);
235 // Collecting all solids which will be fused.
236 ListOfShape aSolidsToFuse;
237 aSolidsToFuse.insert(aSolidsToFuse.end(), anObjects.begin(), anObjects.end());
238 aSolidsToFuse.insert(aSolidsToFuse.end(), aTools.begin(), aTools.end());
240 // Collecting solids from compsolids which will not be modified in boolean operation.
241 ListOfShape aNotUsedSolids;
242 for(std::map<std::shared_ptr<GeomAPI_Shape>, ListOfShape>::iterator anIt = aCompSolidsObjects.begin();
243 anIt != aCompSolidsObjects.end(); anIt++) {
244 std::shared_ptr<GeomAPI_Shape> aCompSolid = anIt->first;
245 ListOfShape& aUsedInOperationSolids = anIt->second;
246 aSolidsToFuse.insert(aSolidsToFuse.end(), aUsedInOperationSolids.begin(), aUsedInOperationSolids.end());
248 // Collect solids from compsolid which will not be modified in boolean operation.
249 for(GeomAPI_ShapeExplorer anExp(aCompSolid, GeomAPI_Shape::SOLID); anExp.more(); anExp.next()) {
250 std::shared_ptr<GeomAPI_Shape> aSolidInCompSolid = anExp.current();
251 ListOfShape::iterator anIt = aUsedInOperationSolids.begin();
252 for(; anIt != aUsedInOperationSolids.end(); anIt++) {
253 if(aSolidInCompSolid->isEqual(*anIt)) {
257 if(anIt == aUsedInOperationSolids.end()) {
258 aNotUsedSolids.push_back(aSolidInCompSolid);
263 ListOfShape anOriginalSolids = aSolidsToFuse;
264 anOriginalSolids.insert(anOriginalSolids.end(), aNotUsedSolids.begin(), aNotUsedSolids.end());
265 GeomAlgoAPI_MakeShapeList aMakeShapeList;
266 GeomAPI_DataMapOfShapeShape aMapOfShapes;
268 // If we have compsolids then cut with not used solids all others.
269 if(!aNotUsedSolids.empty()) {
270 aSolidsToFuse.clear();
271 for(ListOfShape::iterator anIt = anOriginalSolids.begin(); anIt != anOriginalSolids.end(); anIt++) {
272 ListOfShape aOneObjectList;
273 aOneObjectList.push_back(*anIt);
274 GeomAlgoAPI_Boolean aCutAlgo(aOneObjectList, aNotUsedSolids, GeomAlgoAPI_Boolean::BOOL_CUT);
276 if(GeomAlgoAPI_ShapeTools::volume(aCutAlgo.shape()) > 1.e-7) {
277 aSolidsToFuse.push_back(aCutAlgo.shape());
278 aMakeShapeList.append(aCutAlgo.makeShape());
279 aMapOfShapes.merge(aCutAlgo.mapOfShapes());
285 anObjects.push_back(aSolidsToFuse.back());
286 aSolidsToFuse.pop_back();
287 aTools = aSolidsToFuse;
289 // Fuse all objects and all tools.
290 GeomAlgoAPI_Boolean aFuseAlgo(anObjects, aTools, aType);
292 // Checking that the algorithm worked properly.
293 if(!aFuseAlgo.isDone()) {
294 static const std::string aFeatureError = "Boolean algorithm failed";
295 setError(aFeatureError);
298 if(aFuseAlgo.shape()->isNull()) {
299 static const std::string aShapeError = "Resulting shape is Null";
300 setError(aShapeError);
303 if(!aFuseAlgo.isValid()) {
304 std::string aFeatureError = "Warning: resulting shape is not valid";
305 setError(aFeatureError);
309 std::shared_ptr<GeomAPI_Shape> aShape = aFuseAlgo.shape();
310 aMakeShapeList.append(aFuseAlgo.makeShape());
311 aMapOfShapes.merge(aFuseAlgo.mapOfShapes());
313 // Add result to not used solids from compsolid (if we have any).
314 if(!aNotUsedSolids.empty()) {
315 aNotUsedSolids.push_back(aShape);
316 GeomAlgoAPI_PaveFiller aFillerAlgo(aNotUsedSolids, true);
317 if(!aFillerAlgo.isDone()) {
318 std::string aFeatureError = "PaveFiller algorithm failed";
319 setError(aFeatureError);
322 if(aFillerAlgo.shape()->isNull()) {
323 static const std::string aShapeError = "Resulting shape is Null";
324 setError(aShapeError);
327 if(!aFillerAlgo.isValid()) {
328 std::string aFeatureError = "Warning: resulting shape is not valid";
329 setError(aFeatureError);
333 aShape = aFillerAlgo.shape();
334 aMakeShapeList.append(aFillerAlgo.makeShape());
335 aMapOfShapes.merge(aFillerAlgo.mapOfShapes());
338 std::shared_ptr<ModelAPI_ResultBody> aResultBody = document()->createBody(data(), aResultIndex);
339 loadNamingDS(aResultBody, anOriginalSolids.front(), anOriginalSolids, aShape, aMakeShapeList, aMapOfShapes);
340 setResult(aResultBody, aResultIndex);
345 std::string anOperationError = "Error: wrong type of operation";
346 setError(anOperationError);
350 // remove the rest results if there were produced in the previous pass
351 removeResults(aResultIndex);
354 //=================================================================================================
355 void FeaturesPlugin_Boolean::loadNamingDS(std::shared_ptr<ModelAPI_ResultBody> theResultBody,
356 const std::shared_ptr<GeomAPI_Shape> theBaseShape,
357 const ListOfShape& theTools,
358 const std::shared_ptr<GeomAPI_Shape> theResultShape,
359 GeomAlgoAPI_MakeShape& theMakeShape,
360 GeomAPI_DataMapOfShapeShape& theMapOfShapes)
363 if(theBaseShape->isEqual(theResultShape)) {
364 theResultBody->store(theResultShape);
366 const int aModifyTag = 1;
367 const int aDeletedTag = 2;
368 const int aSubsolidsTag = 3; /// sub solids will be placed at labels 3, 4, etc. if result is compound of solids
370 theResultBody->storeModified(theBaseShape, theResultShape, aSubsolidsTag);
372 std::string aModName = "Modified";
373 theResultBody->loadAndOrientModifiedShapes(&theMakeShape, theBaseShape, GeomAPI_Shape::FACE,
374 aModifyTag, aModName, theMapOfShapes);
375 theResultBody->loadDeletedShapes(&theMakeShape, theBaseShape, GeomAPI_Shape::FACE, aDeletedTag);
377 for(ListOfShape::const_iterator anIter = theTools.begin(); anIter != theTools.end(); anIter++) {
378 theResultBody->loadAndOrientModifiedShapes(&theMakeShape, *anIter, GeomAPI_Shape::FACE,
379 aModifyTag, aModName, theMapOfShapes);
380 theResultBody->loadDeletedShapes(&theMakeShape, *anIter, GeomAPI_Shape::FACE, aDeletedTag);