Salome HOME
Issue #1860: fix end lines with spaces
[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     case GeomAPI_Shape::WIRE: {
283       //std::shared_ptr<GeomAPI_Vertex> aV1, aV2;
284       //GeomAlgoAPI_ShapeTools::findBounds(theBaseShape, aV1, aV2);
285       //ListOfShape aV1History, aV2History;
286       //theMakeShape->generated(aV1, aV1History);
287       //theMakeShape->generated(aV2, aV2History);
288       //if(!aV1History.empty()) {
289       //  theResultBody->generated(aV1, aV1History.front(), aGenName + "Edge_1", theTag++);
290       //}
291       //if(!aV2History.empty()) {
292       //  theResultBody->generated(aV2, aV2History.front(), aGenName + "Edge_2", theTag++);
293       //}
294       aShapeTypeToExplode = GeomAPI_Shape::VERTEX;
295       break;
296     }
297     case GeomAPI_Shape::FACE:
298     case GeomAPI_Shape::SHELL: {
299       aShapeTypeToExplode = GeomAPI_Shape::EDGE;
300       break;
301     }
302     case GeomAPI_Shape::COMPOUND: {
303       aShapeTypeToExplode = GeomAPI_Shape::COMPOUND;
304     }
305   }
306
307   if(aShapeTypeToExplode == GeomAPI_Shape::VERTEX ||
308       aShapeTypeToExplode == GeomAPI_Shape::COMPOUND) {
309     theResultBody->loadAndOrientGeneratedShapes(theMakeShape.get(), theBaseShape,
310                                                 GeomAPI_Shape::VERTEX,
311                                                 theTag++, aGenName + "Edge",
312                                                 *aMapOfSubShapes.get());
313   }
314   if(aShapeTypeToExplode == GeomAPI_Shape::EDGE ||
315       aShapeTypeToExplode == GeomAPI_Shape::COMPOUND) {
316     theResultBody->loadAndOrientGeneratedShapes(theMakeShape.get(),
317                                                 theBaseShape, GeomAPI_Shape::EDGE,
318                                                 theTag++, aGenName + "Face",
319                                                 *aMapOfSubShapes.get());
320   }
321
322   std::shared_ptr<GeomAlgoAPI_MakeSweep> aMakeSweep =
323     std::dynamic_pointer_cast<GeomAlgoAPI_MakeSweep>(theMakeShape);
324   if(aMakeSweep.get()) {
325     // Store from shapes.
326     storeShapes(theResultBody, aBaseShapeType, aMapOfSubShapes,
327                 aMakeSweep->fromShapes(), "From_", theTag);
328
329     // Store to shapes.
330     storeShapes(theResultBody, aBaseShapeType, aMapOfSubShapes,
331                 aMakeSweep->toShapes(), "To_", theTag);
332   }
333 }
334
335 //=================================================================================================
336 void FeaturesPlugin_CompositeSketch::storeShapes(ResultBodyPtr theResultBody,
337                               const GeomAPI_Shape::ShapeType theBaseShapeType,
338                               const std::shared_ptr<GeomAPI_DataMapOfShapeShape> theMapOfSubShapes,
339                               const ListOfShape& theShapes,
340                               const std::string theName,
341                               int& theTag)
342 {
343   GeomAPI_Shape::ShapeType aShapeTypeToExplore = GeomAPI_Shape::FACE;
344   std::string aShapeTypeStr = "Face";
345   switch(theBaseShapeType) {
346     case GeomAPI_Shape::VERTEX: {
347       aShapeTypeToExplore = GeomAPI_Shape::VERTEX;
348       aShapeTypeStr = "Vertex";
349       break;
350     }
351     case GeomAPI_Shape::EDGE:
352     case GeomAPI_Shape::WIRE: {
353       aShapeTypeToExplore = GeomAPI_Shape::EDGE;
354       aShapeTypeStr = "Edge";
355       break;
356     }
357     case GeomAPI_Shape::FACE:
358     case GeomAPI_Shape::SHELL: {
359       aShapeTypeToExplore = GeomAPI_Shape::FACE;
360       aShapeTypeStr = "Face";
361       break;
362     }
363     case GeomAPI_Shape::COMPOUND: {
364       aShapeTypeToExplore = GeomAPI_Shape::COMPOUND;
365       break;
366     }
367   }
368
369   // Store shapes.
370   int aShapeIndex = 1;
371   int aFaceIndex = 1;
372   for(ListOfShape::const_iterator anIt = theShapes.cbegin(); anIt != theShapes.cend(); ++anIt) {
373     GeomShapePtr aShape = *anIt;
374
375     if(aShapeTypeToExplore == GeomAPI_Shape::COMPOUND) {
376       std::string aName = theName + (aShape->shapeType() == GeomAPI_Shape::EDGE ? "Edge" : "Face");
377       storeSubShape(theResultBody,
378                     aShape,
379                     aShape->shapeType(),
380                     theMapOfSubShapes,
381                     aName,
382                     aShape->shapeType() == GeomAPI_Shape::EDGE ? aShapeIndex : aFaceIndex,
383                     theTag);
384     } else {
385       std::string aName = theName + aShapeTypeStr;
386       storeSubShape(theResultBody, aShape, aShapeTypeToExplore,
387                     theMapOfSubShapes, aName, aShapeIndex, theTag);
388     }
389   }
390 }
391
392 void storeSubShape(ResultBodyPtr theResultBody,
393                    const GeomShapePtr theShape,
394                    const GeomAPI_Shape::ShapeType theType,
395                    const std::shared_ptr<GeomAPI_DataMapOfShapeShape> theMapOfSubShapes,
396                    const std::string theName,
397                    int& theShapeIndex,
398                    int& theTag)
399 {
400   for(GeomAPI_ShapeExplorer anExp(theShape, theType); anExp.more(); anExp.next()) {
401     GeomShapePtr aSubShape = anExp.current();
402     if(theMapOfSubShapes->isBound(aSubShape)) {
403       aSubShape = theMapOfSubShapes->find(aSubShape);
404     }
405     std::ostringstream aStr;
406     aStr << theName << "_" << theShapeIndex++;
407     theResultBody->generated(aSubShape, aStr.str(), theTag++);
408   }
409 }