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