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