Salome HOME
Merge branch 'Dev_1.3.0' of newgeom:newgeom into Dev_1.3.0
[modules/shaper.git] / src / FeaturesPlugin / FeaturesPlugin_Boolean.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
2
3 // File:        FeaturesPlugin_Boolean.cpp
4 // Created:     02 Sept 2014
5 // Author:      Vitaly SMETANNIKOV
6
7 #include "FeaturesPlugin_Boolean.h"
8
9 #include <ModelAPI_Data.h>
10 #include <ModelAPI_Document.h>
11 #include <ModelAPI_AttributeReference.h>
12 #include <ModelAPI_AttributeInteger.h>
13 #include <ModelAPI_ResultBody.h>
14 #include <ModelAPI_AttributeSelectionList.h>
15 #include <ModelAPI_Session.h>
16 #include <ModelAPI_Validator.h>
17
18 #include <GeomAlgoAPI_Boolean.h>
19 #include <GeomAlgoAPI_MakeShapeList.h>
20 #include <GeomAlgoAPI_ShapeProps.h>
21
22 #define FACE 4
23 #define _MODIFY_TAG 1
24 #define _DELETED_TAG 2
25 #define _SUBSOLIDS_TAG 3 /// sub solids will be placed at labels 3, 4, etc. if result is compound of solids
26
27 //=================================================================================================
28 FeaturesPlugin_Boolean::FeaturesPlugin_Boolean()
29 {
30 }
31
32 //=================================================================================================
33 void FeaturesPlugin_Boolean::initAttributes()
34 {
35   data()->addAttribute(FeaturesPlugin_Boolean::TYPE_ID(), ModelAPI_AttributeInteger::typeId());
36
37   AttributeSelectionListPtr aSelection = 
38     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(data()->addAttribute(
39     FeaturesPlugin_Boolean::OBJECT_LIST_ID(), ModelAPI_AttributeSelectionList::typeId()));
40   // extrusion works with faces always
41   aSelection->setSelectionType("SOLID");
42
43   aSelection = std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(data()->addAttribute(
44     FeaturesPlugin_Boolean::TOOL_LIST_ID(), ModelAPI_AttributeSelectionList::typeId()));
45   // extrusion works with faces always
46   aSelection->setSelectionType("SOLID");
47
48   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), OBJECT_LIST_ID());
49   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), TOOL_LIST_ID());
50 }
51
52 //=================================================================================================
53 std::shared_ptr<GeomAPI_Shape> FeaturesPlugin_Boolean::getShape(const std::string& theAttrName)
54 {
55   std::shared_ptr<ModelAPI_AttributeReference> aObjRef = std::dynamic_pointer_cast<
56       ModelAPI_AttributeReference>(data()->attribute(theAttrName));
57   if (aObjRef) {
58     std::shared_ptr<ModelAPI_ResultBody> aConstr = std::dynamic_pointer_cast<
59         ModelAPI_ResultBody>(aObjRef->value());
60     if (aConstr)
61       return aConstr->shape();
62   }
63   return std::shared_ptr<GeomAPI_Shape>();
64 }
65
66 //=================================================================================================
67 void FeaturesPlugin_Boolean::execute()
68 {
69   // Getting operation type.
70   std::shared_ptr<ModelAPI_AttributeInteger> aTypeAttr = std::dynamic_pointer_cast<
71       ModelAPI_AttributeInteger>(data()->attribute(FeaturesPlugin_Boolean::TYPE_ID()));
72   if (!aTypeAttr)
73     return;
74   GeomAlgoAPI_Boolean::OperationType aType = (GeomAlgoAPI_Boolean::OperationType)aTypeAttr->value();
75
76   ListOfShape anObjects, aTools;
77
78   // Getting objects.
79   AttributeSelectionListPtr anObjectsSelList = selectionList(FeaturesPlugin_Boolean::OBJECT_LIST_ID());
80   for(int anObjectsIndex = 0; anObjectsIndex < anObjectsSelList->size(); anObjectsIndex++) {
81     std::shared_ptr<ModelAPI_AttributeSelection> anObjectAttr = anObjectsSelList->value(anObjectsIndex);
82     std::shared_ptr<GeomAPI_Shape> anObject = anObjectAttr->value();
83     if(!anObject.get()) {
84       return;
85     }
86     anObjects.push_back(anObject);
87   }
88
89   // Getting tools.
90   AttributeSelectionListPtr aToolsSelList = selectionList(FeaturesPlugin_Boolean::TOOL_LIST_ID());
91   for(int aToolsIndex = 0; aToolsIndex < aToolsSelList->size(); aToolsIndex++) {
92     std::shared_ptr<ModelAPI_AttributeSelection> aToolAttr = aToolsSelList->value(aToolsIndex);
93     std::shared_ptr<GeomAPI_Shape> aTool = aToolAttr->value();
94     if(!aTool.get()) {
95       return;
96     }
97     aTools.push_back(aTool);
98   }
99
100   int aResultIndex = 0;
101
102   switch(aType) {
103     case GeomAlgoAPI_Boolean::BOOL_CUT:
104     case GeomAlgoAPI_Boolean::BOOL_COMMON:{
105       if(anObjects.empty() || aTools.empty()) {
106         std::string aFeatureError = "Not enough objects for boolean operation";
107         setError(aFeatureError);
108         return;
109       }
110
111       // Cut each object with all tools
112       for(ListOfShape::iterator anObjectsIt = anObjects.begin(); anObjectsIt != anObjects.end(); anObjectsIt++) {
113         std::shared_ptr<GeomAPI_Shape> anObject = *anObjectsIt;
114         ListOfShape aListWithObject;
115         aListWithObject.push_back(anObject);
116         GeomAlgoAPI_Boolean aBoolAlgo(aListWithObject, aTools, aType);
117
118         // Checking that the algorithm worked properly.
119         if(!aBoolAlgo.isDone()) {
120           static const std::string aFeatureError = "Boolean algorithm failed";
121           setError(aFeatureError);
122           return;
123         }
124         if(aBoolAlgo.shape()->isNull()) {
125           static const std::string aShapeError = "Resulting shape is Null";
126           setError(aShapeError);
127           return;
128         }
129         if(!aBoolAlgo.isValid()) {
130           std::string aFeatureError = "Warning: resulting shape is not valid";
131           setError(aFeatureError);
132           return;
133         }
134
135         if(GeomAlgoAPI_ShapeProps::volume(aBoolAlgo.shape()) > 1.e-7) {
136           std::shared_ptr<ModelAPI_ResultBody> aResultBody = document()->createBody(data(), aResultIndex);
137           LoadNamingDS(aResultBody, anObject, aTools, aBoolAlgo);
138           setResult(aResultBody, aResultIndex);
139           aResultIndex++;
140         }
141       }
142       break;
143     }
144     case GeomAlgoAPI_Boolean::BOOL_FUSE: {
145       if(anObjects.empty() && aTools.size() > 1) {
146         anObjects.push_back(aTools.back());
147         aTools.pop_back();
148       }else if(aTools.empty() && anObjects.size() > 1) {
149         aTools.push_back(anObjects.back());
150         anObjects.pop_back();
151       }
152
153       if(anObjects.empty() || aTools.empty()) {
154         std::string aFeatureError = "Not enough objects for boolean operation";
155         setError(aFeatureError);
156         return;
157       }
158
159       // Fuse all objects and all tools.
160       GeomAlgoAPI_Boolean aBoolAlgo(anObjects, aTools, aType);
161
162       // Checking that the algorithm worked properly.
163       if(!aBoolAlgo.isDone()) {
164         static const std::string aFeatureError = "Boolean algorithm failed";
165         setError(aFeatureError);
166         return;
167       }
168       if(aBoolAlgo.shape()->isNull()) {
169         static const std::string aShapeError = "Resulting shape is Null";
170         setError(aShapeError);
171         return;
172       }
173       if(!aBoolAlgo.isValid()) {
174         std::string aFeatureError = "Warning: resulting shape is not valid";
175         setError(aFeatureError);
176         return;
177       }
178
179       std::shared_ptr<ModelAPI_ResultBody> aResultBody = document()->createBody(data(), aResultIndex);
180       LoadNamingDS(aResultBody, anObjects.front(), aTools, aBoolAlgo);
181       setResult(aResultBody, aResultIndex);
182       aResultIndex++;
183       break;
184     }
185     default: {
186       std::string anOperationError = "Error: wrong type of operation";
187       setError(anOperationError);
188       return;
189     }
190   }
191   // remove the rest results if there were produced in the previous pass
192   removeResults(aResultIndex);
193 }
194
195 //=================================================================================================
196 void FeaturesPlugin_Boolean::LoadNamingDS(std::shared_ptr<ModelAPI_ResultBody> theResultBody,
197                                           const std::shared_ptr<GeomAPI_Shape>& theBaseShape,
198                                           const ListOfShape& theTools,
199                                           const GeomAlgoAPI_Boolean& theAlgo)
200 {
201   //load result
202   if(theBaseShape->isEqual(theAlgo.shape())) {
203     theResultBody->store(theAlgo.shape());
204   } else {
205     theResultBody->storeModified(theBaseShape, theAlgo.shape(), _SUBSOLIDS_TAG);
206
207     GeomAPI_DataMapOfShapeShape* aSubShapes = new GeomAPI_DataMapOfShapeShape();
208
209     std::string aModName = "Modified";
210     theResultBody->loadAndOrientModifiedShapes(theAlgo.makeShape().get(), theBaseShape, FACE,
211                                                _MODIFY_TAG, aModName, *theAlgo.mapOfShapes().get());
212     theResultBody->loadDeletedShapes(theAlgo.makeShape().get(), theBaseShape, FACE, _DELETED_TAG);
213
214     for(ListOfShape::const_iterator anIter = theTools.begin(); anIter != theTools.end(); anIter++) {
215       theResultBody->loadAndOrientModifiedShapes(theAlgo.makeShape().get(), *anIter, FACE,
216                                                  _MODIFY_TAG, aModName, *theAlgo.mapOfShapes().get());
217       theResultBody->loadDeletedShapes(theAlgo.makeShape().get(), *anIter, FACE, _DELETED_TAG);
218     }
219   }
220 }