Salome HOME
Fix for the problem if disappeared sketch elements (on Apply) inside of sketch in...
[modules/shaper.git] / src / FeaturesPlugin / FeaturesPlugin_CompositeSketch.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:        FeaturesPlugin_CompositeSketch.cpp
4 // Created:     11 September 2015
5 // Author:      Dmitry Bobylev
6
7 #include <FeaturesPlugin_CompositeSketch.h>
8
9 #include <ModelAPI_AttributeSelectionList.h>
10 #include <ModelAPI_AttributeReference.h>
11 #include <ModelAPI_BodyBuilder.h>
12 #include <ModelAPI_ResultConstruction.h>
13 #include <ModelAPI_Session.h>
14 #include <ModelAPI_Validator.h>
15
16 #include <GeomAlgoAPI_CompoundBuilder.h>
17 #include <GeomAlgoAPI_Prism.h>
18 #include <GeomAlgoAPI_Revolution.h>
19 #include <GeomAlgoAPI_ShapeTools.h>
20 #include <GeomAlgoAPI_SketchBuilder.h>
21
22 #include <GeomAPI_PlanarEdges.h>
23 #include <GeomAPI_ShapeExplorer.h>
24
25 #include <map>
26 #include <sstream>
27
28 //=================================================================================================
29 void FeaturesPlugin_CompositeSketch::initCompositeSketchAttribtues(const int theInitFlags)
30 {
31   // Initialize sketch launcher.
32   if(theInitFlags & InitSketchLauncher) {
33     data()->addAttribute(SKETCH_ID(), ModelAPI_AttributeReference::typeId());
34     ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), SKETCH_ID());
35   }
36
37   // Initialize selection list.
38   if(theInitFlags & InitBaseObjectsList) {
39     data()->addAttribute(BASE_OBJECTS_ID(), ModelAPI_AttributeSelectionList::typeId());
40   }
41 }
42
43 //=================================================================================================
44 std::shared_ptr<ModelAPI_Feature> FeaturesPlugin_CompositeSketch::addFeature(std::string theID)
45 {
46   FeaturePtr aNew = document()->addFeature(theID, false);
47   if(aNew) {
48     data()->reference(SKETCH_ID())->setValue(aNew);
49   }
50
51   // Set as current also after it becomes sub to set correctly enabled for other sketch subs.
52   document()->setCurrentFeature(aNew, false);
53   return aNew;
54 }
55
56 //=================================================================================================
57 int FeaturesPlugin_CompositeSketch::numberOfSubs(bool forTree) const
58 {
59   ObjectPtr aObj = data()->reference(SKETCH_ID())->value();
60   return aObj.get() ? 1 : 0;
61 }
62
63 //=================================================================================================
64 std::shared_ptr<ModelAPI_Feature> FeaturesPlugin_CompositeSketch::subFeature(const int theIndex, bool forTree)
65 {
66   if(theIndex == 0) {
67     return std::dynamic_pointer_cast<ModelAPI_Feature>(data()->reference(SKETCH_ID())->value());
68   }
69
70   return std::shared_ptr<ModelAPI_Feature>();
71 }
72
73 //=================================================================================================
74 int FeaturesPlugin_CompositeSketch::subFeatureId(const int theIndex) const
75 {
76   if(theIndex == 0) {
77     FeaturePtr aFeature =
78       std::dynamic_pointer_cast<ModelAPI_Feature>(data()->reference(SKETCH_ID())->value());
79     if(aFeature.get()) {
80       return aFeature->data()->featureId();
81     }
82   }
83
84   return -1;
85 }
86
87 //=================================================================================================
88 bool FeaturesPlugin_CompositeSketch::isSub(ObjectPtr theObject) const
89 {
90   // Check is this feature of result
91   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theObject);
92   if(!aFeature.get()) {
93     return false;
94   }
95
96   ObjectPtr aSub = data()->reference(SKETCH_ID())->value();
97   return aSub == theObject;
98 }
99
100 //=================================================================================================
101 void FeaturesPlugin_CompositeSketch::removeFeature(std::shared_ptr<ModelAPI_Feature> theFeature)
102 {
103   AttributeSelectionListPtr aBaseObjectsSelectionList = selectionList(BASE_OBJECTS_ID());
104   if(aBaseObjectsSelectionList.get() && aBaseObjectsSelectionList->size() > 0) {
105     aBaseObjectsSelectionList->clear();
106   }
107
108   reference(SKETCH_ID())->setValue(ObjectPtr());
109 }
110
111 //=================================================================================================
112 void FeaturesPlugin_CompositeSketch::getBaseShapes(ListOfShape& theBaseShapesList,
113                                                    const bool theIsMakeShells)
114 {
115   theBaseShapesList.clear();
116
117   ListOfShape aBaseFacesList;
118   std::map<ResultConstructionPtr, ListOfShape> aSketchWiresMap;
119   AttributeSelectionListPtr aBaseObjectsSelectionList = selectionList(BASE_OBJECTS_ID());
120   if(!aBaseObjectsSelectionList.get()) {
121     setError("Error: Could not get base objects selection list.");
122     return;
123   }
124   if(aBaseObjectsSelectionList->size() == 0) {
125     setError("Error: Base objects list is empty.");
126     return;
127   }
128   for(int anIndex = 0; anIndex < aBaseObjectsSelectionList->size(); anIndex++) {
129     AttributeSelectionPtr aBaseObjectSelection = aBaseObjectsSelectionList->value(anIndex);
130     if(!aBaseObjectSelection.get()) {
131       setError("Error: Selected base object is empty.");
132       return;
133     }
134     GeomShapePtr aBaseShape = aBaseObjectSelection->value();
135     if(aBaseShape.get() && !aBaseShape->isNull()) {
136       GeomAPI_Shape::ShapeType aST = aBaseShape->shapeType();
137       if(aST != GeomAPI_Shape::VERTEX && aST != GeomAPI_Shape::EDGE && aST != GeomAPI_Shape::WIRE &&
138          aST != GeomAPI_Shape::FACE && aST != GeomAPI_Shape::SHELL) {
139         setError("Error: Selected shapes has unsupported type.");
140         return;
141       }
142       ResultConstructionPtr aConstruction =
143         std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aBaseObjectSelection->context());
144       if(aConstruction.get() && !aBaseShape->isEqual(aConstruction->shape()) && aST == GeomAPI_Shape::WIRE) {
145         // It is a wire on the sketch, store it to make face later.
146         aSketchWiresMap[aConstruction].push_back(aBaseShape);
147         continue;
148       } else {
149       aST == GeomAPI_Shape::FACE ? aBaseFacesList.push_back(aBaseShape) :
150                                    theBaseShapesList.push_back(aBaseShape);
151       }
152     } else {
153       // This may be the whole sketch result selected, check and get faces.
154       ResultConstructionPtr aConstruction =
155         std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aBaseObjectSelection->context());
156       if(!aConstruction.get()) {
157         setError("Error: Selected sketches does not have results.");
158         return;
159       }
160       int aFacesNum = aConstruction->facesNum();
161       if(aFacesNum == 0) {
162         // Probably it can be construction.
163         aBaseShape = aConstruction->shape();
164         if(aBaseShape.get() && !aBaseShape->isNull()) {
165           GeomAPI_Shape::ShapeType aST = aBaseShape->shapeType();
166           if(aST != GeomAPI_Shape::VERTEX && aST != GeomAPI_Shape::EDGE && aST != GeomAPI_Shape::WIRE &&
167              aST != GeomAPI_Shape::FACE && aST != GeomAPI_Shape::SHELL) {
168             setError("Error: Selected shapes has unsupported type.");
169             return;
170           }
171           aST == GeomAPI_Shape::FACE ? aBaseFacesList.push_back(aBaseShape) :
172                                        theBaseShapesList.push_back(aBaseShape);
173         }
174       } else {
175         for(int aFaceIndex = 0; aFaceIndex < aFacesNum; aFaceIndex++) {
176           GeomShapePtr aBaseFace = aConstruction->face(aFaceIndex);
177           if(!aBaseFace.get() || aBaseFace->isNull()) {
178             setError("Error: One of the faces on selected sketch is null.");
179             return;
180           }
181           aBaseFacesList.push_back(aBaseFace);
182         }
183       }
184     }
185   }
186
187   // Make faces from sketch wires.
188   for(std::map<ResultConstructionPtr, ListOfShape>::const_iterator anIt = aSketchWiresMap.cbegin();
189       anIt != aSketchWiresMap.cend(); ++anIt) {
190     const std::shared_ptr<GeomAPI_PlanarEdges> aSketchPlanarEdges =
191       std::dynamic_pointer_cast<GeomAPI_PlanarEdges>((*anIt).first->shape());
192     const ListOfShape& aWiresList = (*anIt).second;
193     ListOfShape aFaces;
194     GeomAlgoAPI_ShapeTools::makeFacesWithHoles(aSketchPlanarEdges->origin(),
195                                                aSketchPlanarEdges->norm(),
196                                                aWiresList,
197                                                aFaces);
198     aBaseFacesList.insert(aBaseFacesList.end(), aFaces.begin(), aFaces.end());
199   }
200
201   // Searching faces with common edges.
202   if(theIsMakeShells) {
203     ListOfShape aShells;
204     ListOfShape aFreeFaces;
205     GeomShapePtr aFacesCompound = GeomAlgoAPI_CompoundBuilder::compound(aBaseFacesList);
206     GeomAlgoAPI_ShapeTools::combineShapes(aFacesCompound, GeomAPI_Shape::SHELL, aShells, aFreeFaces);
207     theBaseShapesList.insert(theBaseShapesList.end(), aFreeFaces.begin(), aFreeFaces.end());
208     theBaseShapesList.insert(theBaseShapesList.end(), aShells.begin(), aShells.end());
209   } else {
210     theBaseShapesList.insert(theBaseShapesList.end(), aBaseFacesList.begin(), aBaseFacesList.end());
211   }
212 }
213
214 //=================================================================================================
215 bool FeaturesPlugin_CompositeSketch::isMakeShapeValid(const std::shared_ptr<GeomAlgoAPI_MakeShape> theMakeShape)
216 {
217   // Check that algo is done.
218   if(!theMakeShape->isDone()) {
219     setError("Error: " + getKind() + " algorithm failed.");
220     return false;
221   }
222
223   // Check if shape is not null.
224   if(!theMakeShape->shape().get() || theMakeShape->shape()->isNull()) {
225     setError("Error: Resulting shape is null.");
226     return false;
227   }
228
229   // Check that resulting shape is valid.
230   if(!theMakeShape->isValid()) {
231     setError("Error: Resulting shape is not valid.");
232     return false;
233   }
234
235   return true;
236 }
237
238 //=================================================================================================
239 void FeaturesPlugin_CompositeSketch::storeResult(const GeomShapePtr theBaseShape,
240                                                  const std::shared_ptr<GeomAlgoAPI_MakeShape> theMakeShape,
241                                                  const int theResultIndex)
242 {
243   // Create result body.
244   ResultBodyPtr aResultBody = document()->createBody(data(), theResultIndex);
245
246   // Store generated shape.
247   aResultBody->storeGenerated(theBaseShape, theMakeShape->shape());
248
249   // Store generated edges/faces.
250   int aGenTag = 1;
251   storeGenerationHistory(aResultBody, theBaseShape, theMakeShape, aGenTag);
252
253   setResult(aResultBody, theResultIndex);
254 }
255
256 //=================================================================================================
257 void FeaturesPlugin_CompositeSketch::storeGenerationHistory(ResultBodyPtr theResultBody,
258                                                             const GeomShapePtr theBaseShape,
259                                                             const std::shared_ptr<GeomAlgoAPI_MakeShape> theMakeShape,
260                                                             int& theTag)
261 {
262   GeomAPI_Shape::ShapeType aBaseShapeType = theBaseShape->shapeType();
263   GeomAPI_Shape::ShapeType aShapeTypeToExplode;
264   std::string aGenName = "Generated_";
265
266   std::shared_ptr<GeomAPI_DataMapOfShapeShape> aMapOfSubShapes = theMakeShape->mapOfSubShapes();
267   switch(aBaseShapeType) {
268     case GeomAPI_Shape::VERTEX: {
269       aShapeTypeToExplode = GeomAPI_Shape::VERTEX;
270       aGenName += "Edge";
271       break;
272     }
273     case GeomAPI_Shape::EDGE:
274     case GeomAPI_Shape::WIRE: {
275       std::shared_ptr<GeomAPI_Vertex> aV1, aV2;
276       GeomAlgoAPI_ShapeTools::findBounds(theBaseShape, aV1, aV2);
277       ListOfShape aV1History, aV2History;
278       theMakeShape->generated(aV1, aV1History);
279       theMakeShape->generated(aV2, aV2History);
280       if(!aV1History.empty()) {
281         theResultBody->generated(aV1, aV1History.front(), aGenName + "Edge_1", theTag++);
282       }
283       if(!aV2History.empty()) {
284         theResultBody->generated(aV2, aV2History.front(), aGenName + "Edge_2", theTag++);
285       }
286     }
287     case GeomAPI_Shape::FACE:
288     case GeomAPI_Shape::SHELL: {
289       aShapeTypeToExplode = GeomAPI_Shape::EDGE;
290       aGenName += "Face";
291       break;
292     }
293   }
294   theResultBody->loadAndOrientGeneratedShapes(theMakeShape.get(), theBaseShape, aShapeTypeToExplode,
295                                               theTag++, aGenName, *aMapOfSubShapes.get());
296
297   std::shared_ptr<GeomAlgoAPI_MakeSweep> aMakeSweep = std::dynamic_pointer_cast<GeomAlgoAPI_MakeSweep>(theMakeShape);
298   if(aMakeSweep.get()) {
299     // Store from shapes.
300     storeShapes(theResultBody, aBaseShapeType, aMapOfSubShapes, aMakeSweep->fromShapes(), "From_", theTag);
301
302     // Store to shapes.
303     storeShapes(theResultBody, aBaseShapeType, aMapOfSubShapes, aMakeSweep->toShapes(), "To_", theTag);
304   }
305 }
306
307 //=================================================================================================
308 void FeaturesPlugin_CompositeSketch::storeShapes(ResultBodyPtr theResultBody,
309                                                  const GeomAPI_Shape::ShapeType theBaseShapeType,
310                                                  const std::shared_ptr<GeomAPI_DataMapOfShapeShape> theMapOfSubShapes,
311                                                  const ListOfShape& theShapes,
312                                                  const std::string theName,
313                                                  int& theTag)
314 {
315   GeomAPI_Shape::ShapeType aShapeTypeToExplore = GeomAPI_Shape::FACE;
316   std::string aShapeTypeStr = "Face";
317   switch(theBaseShapeType) {
318     case GeomAPI_Shape::VERTEX: {
319       aShapeTypeToExplore = GeomAPI_Shape::VERTEX;
320       aShapeTypeStr = "Vertex";
321       break;
322     }
323     case GeomAPI_Shape::EDGE:
324     case GeomAPI_Shape::WIRE: {
325       aShapeTypeToExplore = GeomAPI_Shape::EDGE;
326       aShapeTypeStr = "Edge";
327       break;
328     }
329     case GeomAPI_Shape::FACE:
330     case GeomAPI_Shape::SHELL: {
331       aShapeTypeToExplore = GeomAPI_Shape::FACE;
332       aShapeTypeStr = "Face";
333       break;
334     }
335   }
336
337   // Store shapes.
338   int aShapeIndex = 1;
339   std::string aName = theName + aShapeTypeStr;
340   for(ListOfShape::const_iterator anIt = theShapes.cbegin(); anIt != theShapes.cend(); ++anIt) {
341     GeomShapePtr aShape = *anIt;
342     for(GeomAPI_ShapeExplorer anExp(aShape, aShapeTypeToExplore); anExp.more(); anExp.next()) {
343       GeomShapePtr aSubShape = anExp.current();
344       if(theMapOfSubShapes->isBound(aSubShape)) {
345         aSubShape = theMapOfSubShapes->find(aSubShape);
346       }
347       std::ostringstream aStr;
348       aStr << aName << "_" << aShapeIndex++;
349       theResultBody->generated(aSubShape, aStr.str(), theTag++);
350     }
351   }
352 }