Salome HOME
Issue #1343 Fixes for creating extrusion on vertex
[modules/shaper.git] / src / FeaturesPlugin / FeaturesPlugin_Pipe.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
2
3 // File:        FeaturesPlugin_Pipe.cpp
4 // Created:     16 March 2016
5 // Author:      Dmitry Bobylev
6
7 #include "FeaturesPlugin_Pipe.h"
8
9 #include <ModelAPI_AttributeSelection.h>
10 #include <ModelAPI_AttributeSelectionList.h>
11 #include <ModelAPI_AttributeString.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_Pipe.h>
18 #include <GeomAPI_ShapeExplorer.h>
19 #include <GeomAlgoAPI_ShapeTools.h>
20
21 #include <sstream>
22
23 //=================================================================================================
24 FeaturesPlugin_Pipe::FeaturesPlugin_Pipe()
25 {
26 }
27
28 //=================================================================================================
29 void FeaturesPlugin_Pipe::initAttributes()
30 {
31   data()->addAttribute(CREATION_METHOD(), ModelAPI_AttributeString::typeId());
32
33   data()->addAttribute(BASE_OBJECTS_ID(), ModelAPI_AttributeSelectionList::typeId());
34   data()->addAttribute(PATH_OBJECT_ID(), ModelAPI_AttributeSelection::typeId());
35
36   data()->addAttribute(BINORMAL_ID(), ModelAPI_AttributeSelection::typeId());
37
38   data()->addAttribute(LOCATIONS_ID(), ModelAPI_AttributeSelectionList::typeId());
39   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), LOCATIONS_ID());
40 }
41
42 //=================================================================================================
43 void FeaturesPlugin_Pipe::execute()
44 {
45   // Getting creation method.
46   std::string aCreationMethod = string(CREATION_METHOD())->value();
47
48   // Getting base objects.
49   ListOfShape aBaseShapesList, aBaseFacesList;
50   AttributeSelectionListPtr aBaseObjectsSelectionList = selectionList(BASE_OBJECTS_ID());
51   if(!aBaseObjectsSelectionList.get()) {
52     setError("Error: Could not get base objects selection list.");
53     return;
54   }
55   if(aBaseObjectsSelectionList->size() == 0) {
56     setError("Error: Base objects list is empty.");
57     return;
58   }
59   for(int anIndex = 0; anIndex < aBaseObjectsSelectionList->size(); anIndex++) {
60     AttributeSelectionPtr aBaseObjectSelection = aBaseObjectsSelectionList->value(anIndex);
61     if(!aBaseObjectSelection.get()) {
62       setError("Error: One of the selected base objects is empty.");
63       return;
64     }
65     std::shared_ptr<GeomAPI_Shape> aBaseShape = aBaseObjectSelection->value();
66     if(aBaseShape.get() && !aBaseShape->isNull()) {
67       aBaseShape->shapeType() == GeomAPI_Shape::FACE ? aBaseFacesList.push_back(aBaseShape) :
68                                                        aBaseShapesList.push_back(aBaseShape);
69     } else {
70       // This may be the whole sketch result selected, check and get faces.
71       ResultConstructionPtr aConstruction = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aBaseObjectSelection->context());
72       if(!aConstruction.get()) {
73         setError("Error: One of selected sketches does not have results.");
74         return;
75       }
76       int aFacesNum = aConstruction->facesNum();
77       if(aFacesNum == 0) {
78         // Probably it can be construction.
79         aBaseShape = aConstruction->shape();
80         if(aBaseShape.get() && !aBaseShape->isNull()) {
81           aBaseShape->shapeType() == GeomAPI_Shape::FACE ? aBaseFacesList.push_back(aBaseShape) :
82                                                            aBaseShapesList.push_back(aBaseShape);
83         }
84       } else {
85         for(int aFaceIndex = 0; aFaceIndex < aFacesNum; aFaceIndex++) {
86           std::shared_ptr<GeomAPI_Shape> aBaseFace = std::dynamic_pointer_cast<GeomAPI_Shape>(aConstruction->face(aFaceIndex));
87           if(!aBaseFace.get() || aBaseFace->isNull()) {
88             setError("Error: One of the faces on selected sketch is Null.");
89             return;
90           }
91           aBaseFacesList.push_back(aBaseFace);
92         }
93       }
94     }
95   }
96
97   // Searching faces with common edges.
98   if(aCreationMethod == "simple") {
99     ListOfShape aShells;
100     ListOfShape aFreeFaces;
101     std::shared_ptr<GeomAPI_Shape> aFacesCompound = GeomAlgoAPI_CompoundBuilder::compound(aBaseFacesList);
102     GeomAlgoAPI_ShapeTools::combineShapes(aFacesCompound, GeomAPI_Shape::SHELL, aShells, aFreeFaces);
103     aBaseShapesList.insert(aBaseShapesList.end(), aFreeFaces.begin(), aFreeFaces.end());
104     aBaseShapesList.insert(aBaseShapesList.end(), aShells.begin(), aShells.end());
105   } else {
106     aBaseShapesList.insert(aBaseShapesList.end(), aBaseFacesList.begin(), aBaseFacesList.end());
107   }
108
109   // Getting path.
110   AttributeSelectionPtr aPathSelection = selection(PATH_OBJECT_ID());
111   if(!aPathSelection.get()) {
112     setError("Error: Path selection is empty.");
113     return;
114   }
115   std::shared_ptr<GeomAPI_Shape> aPathShape = std::dynamic_pointer_cast<GeomAPI_Shape>(aPathSelection->value());
116   if(!aPathShape.get()) {
117     // Probaply it is a construction.
118     aPathShape = aPathSelection->context()->shape();
119   }
120   if(!aPathShape.get() || aPathShape->isNull()) {
121     setError("Error: Path shape is null.");
122     return;
123   }
124
125   // Getting Bi-Normal
126   std::shared_ptr<GeomAPI_Shape> aBiNormal;
127   if(aCreationMethod == "binormal") {
128     AttributeSelectionPtr aBiNormalSelection = selection(BINORMAL_ID());
129     if(!aBiNormalSelection.get()) {
130       setError("Error: Bi-Normal selection is empty.");
131       return;
132     }
133     aBiNormal = std::dynamic_pointer_cast<GeomAPI_Shape>(aBiNormalSelection->value());
134     if(!aBiNormal.get()) {
135       // Probably it is a construction.
136       aBiNormal = aBiNormalSelection->context()->shape();
137     }
138     if(!aBiNormal.get() || aBiNormal->isNull()) {
139       setError("Error: Bi-Normal shape is null.");
140       return;
141     }
142   }
143
144   // Getting locations.
145   ListOfShape aLocations;
146   if(aCreationMethod == "locations") {
147     AttributeSelectionListPtr aLocationsSelectionList = selectionList(LOCATIONS_ID());
148     if(!aLocationsSelectionList.get()) {
149       setError("Error: Could not get locations selection list.");
150       return;
151     }
152     for(int anIndex = 0; anIndex < aLocationsSelectionList->size(); anIndex++) {
153       AttributeSelectionPtr aLocationSelection = aLocationsSelectionList->value(anIndex);
154       if(!aLocationSelection.get()) {
155         setError("Error: One of the selected location is empty.");
156         return;
157       }
158       std::shared_ptr<GeomAPI_Shape> aLocationShape = aLocationSelection->value();
159       if(!aLocationShape.get()) {
160         // Probably it is a construction.
161         aLocationShape = aLocationSelection->context()->shape();
162       }
163       if(!aLocationShape.get() || aLocationShape->isNull()) {
164         setError("Error: One of the selected location shape is null.");
165         return;
166       }
167       aLocations.push_back(aLocationShape);
168     }
169   }
170
171   // Generating result for each object.
172   int aResultIndex = 0;
173   if(aCreationMethod == "simple" || aCreationMethod == "binormal") {
174     for(ListOfShape::const_iterator anIter = aBaseShapesList.cbegin(); anIter != aBaseShapesList.cend(); anIter++) {
175       std::shared_ptr<GeomAPI_Shape> aBaseShape = *anIter;
176
177       GeomAlgoAPI_Pipe aPipeAlgo = aCreationMethod == "simple" ? GeomAlgoAPI_Pipe(aBaseShape, aPathShape) :
178                                                                  GeomAlgoAPI_Pipe(aBaseShape, aPathShape, aBiNormal);
179
180       if(!aPipeAlgo.isDone()) {
181         setError("Error: Pipe algorithm failed.");
182         aResultIndex = 0;
183         break;
184       }
185
186       // Check if shape is valid
187       if(!aPipeAlgo.shape().get() || aPipeAlgo.shape()->isNull()) {
188         setError("Error: Resulting shape is Null.");
189         aResultIndex = 0;
190         break;
191       }
192       if(!aPipeAlgo.isValid()) {
193         setError("Error: Resulting shape is not valid.");
194         aResultIndex = 0;
195         break;
196       }
197
198       storeResult(aBaseShape, aPipeAlgo, aResultIndex++);
199     }
200   } else if(aCreationMethod == "locations") {
201     GeomAlgoAPI_Pipe aPipeAlgo = GeomAlgoAPI_Pipe(aBaseShapesList, aLocations, aPathShape);
202
203     if(!aPipeAlgo.isDone()) {
204       setError("Error: Pipe algorithm failed.");
205       removeResults(0);
206       return;
207     }
208
209     // Check if shape is valid
210     if(!aPipeAlgo.shape().get() || aPipeAlgo.shape()->isNull()) {
211       setError("Error: Resulting shape is Null.");
212       removeResults(0);
213       return;
214     }
215     if(!aPipeAlgo.isValid()) {
216       setError("Error: Resulting shape is not valid.");
217       removeResults(0);
218       return;
219     }
220
221     storeResult(aBaseShapesList, aPipeAlgo, aResultIndex++);
222   } else {
223     setError("Error: Wrong creation method.");
224     return;
225   }
226
227   removeResults(aResultIndex);
228 }
229
230 //=================================================================================================
231 void FeaturesPlugin_Pipe::storeResult(const std::shared_ptr<GeomAPI_Shape> theBaseShape,
232                                       GeomAlgoAPI_Pipe& thePipeAlgo,
233                                       const int theResultIndex)
234 {
235   // Create result body.
236   ResultBodyPtr aResultBody = document()->createBody(data(), theResultIndex);
237
238   // Store generated shape.
239   aResultBody->storeGenerated(theBaseShape, thePipeAlgo.shape());
240
241   // Store generated edges/faces.
242   GeomAPI_Shape::ShapeType aBaseShapeType = theBaseShape->shapeType();
243   GeomAPI_Shape::ShapeType aShapeTypeToExplode;
244   int aGenTag = 1;
245   std::string aGenName = "Generated_";
246
247   std::shared_ptr<GeomAPI_DataMapOfShapeShape> aMapOfSubShapes = thePipeAlgo.mapOfSubShapes();
248   switch(aBaseShapeType) {
249     case GeomAPI_Shape::VERTEX: {
250       aShapeTypeToExplode = GeomAPI_Shape::VERTEX;
251       aGenName += "Edge";
252       break;
253     }
254     case GeomAPI_Shape::EDGE:
255     case GeomAPI_Shape::WIRE: {
256       std::shared_ptr<GeomAPI_Vertex> aV1, aV2;
257       GeomAlgoAPI_ShapeTools::findBounds(theBaseShape, aV1, aV2);
258       ListOfShape aV1History, aV2History;
259       thePipeAlgo.generated(aV1, aV1History);
260       thePipeAlgo.generated(aV2, aV2History);
261       aResultBody->generated(aV1, aV1History.front(), aGenName + "Edge_1", aGenTag++);
262       aResultBody->generated(aV2, aV2History.front(), aGenName + "Edge_2", aGenTag++);
263     }
264     case GeomAPI_Shape::FACE:
265     case GeomAPI_Shape::SHELL: {
266       aShapeTypeToExplode = GeomAPI_Shape::EDGE;
267       aGenName += "Face";
268       break;
269     }
270   }
271   aResultBody->loadAndOrientGeneratedShapes(&thePipeAlgo, theBaseShape, aShapeTypeToExplode, aGenTag++, aGenName, *aMapOfSubShapes.get());
272
273   // Store from shapes.
274   int aFromTag = aGenTag;
275   storeShapes(aResultBody, aBaseShapeType, aMapOfSubShapes, thePipeAlgo.fromShapes(), "From_", aFromTag);
276
277   // Store to shapes.
278   int aToTag = aFromTag;
279   storeShapes(aResultBody, aBaseShapeType, aMapOfSubShapes, thePipeAlgo.toShapes(), "To_", aToTag);
280
281   setResult(aResultBody, theResultIndex);
282 }
283
284 //=================================================================================================
285 void FeaturesPlugin_Pipe::storeResult(const ListOfShape& theBaseShapes,
286                                       GeomAlgoAPI_Pipe& thePipeAlgo,
287                                       const int theResultIndex)
288 {
289   // Create result body.
290   ResultBodyPtr aResultBody = document()->createBody(data(), theResultIndex);
291
292   // Store generated shape.
293   aResultBody->storeGenerated(theBaseShapes.front(), thePipeAlgo.shape());
294
295   // Store generated edges/faces.
296   int aGenTag = 1;
297   std::shared_ptr<GeomAPI_DataMapOfShapeShape> aMapOfSubShapes = thePipeAlgo.mapOfSubShapes();
298
299   for(ListOfShape::const_iterator anIter = theBaseShapes.cbegin(); anIter != theBaseShapes.cend(); anIter++) {
300     GeomShapePtr aBaseShape = *anIter;
301     GeomAPI_Shape::ShapeType aBaseShapeType = aBaseShape->shapeType();
302     GeomAPI_Shape::ShapeType aShapeTypeToExplode;
303     std::string aGenName = "Generated_";
304     switch(aBaseShapeType) {
305       case GeomAPI_Shape::VERTEX: {
306         aShapeTypeToExplode = GeomAPI_Shape::VERTEX;
307         aGenName += "Edge";
308         break;
309       }
310       case GeomAPI_Shape::EDGE:
311       case GeomAPI_Shape::WIRE: {
312         std::shared_ptr<GeomAPI_Vertex> aV1, aV2;
313         GeomAlgoAPI_ShapeTools::findBounds(aBaseShape, aV1, aV2);
314         ListOfShape aV1History, aV2History;
315         thePipeAlgo.generated(aV1, aV1History);
316         thePipeAlgo.generated(aV2, aV2History);
317         aResultBody->generated(aV1, aV1History.front(), aGenName + "Edge_1", aGenTag++);
318         aResultBody->generated(aV2, aV2History.front(), aGenName + "Edge_2", aGenTag++);
319       }
320       case GeomAPI_Shape::FACE:
321       case GeomAPI_Shape::SHELL: {
322         aShapeTypeToExplode = GeomAPI_Shape::EDGE;
323         aGenName += "Face";
324         break;
325       }
326     }
327     aResultBody->loadAndOrientGeneratedShapes(&thePipeAlgo, aBaseShape, aShapeTypeToExplode, aGenTag++, aGenName, *aMapOfSubShapes.get());
328   }
329
330   // Store from shapes.
331   int aFromTag = aGenTag;
332   storeShapes(aResultBody, theBaseShapes.front()->shapeType(), aMapOfSubShapes, thePipeAlgo.fromShapes(), "From", aFromTag);
333
334   // Store to shapes.
335   int aToTag = aFromTag;
336   storeShapes(aResultBody, theBaseShapes.back()->shapeType(), aMapOfSubShapes, thePipeAlgo.toShapes(), "To", aToTag);
337
338
339   setResult(aResultBody, theResultIndex);
340 }
341
342 //=================================================================================================
343 void FeaturesPlugin_Pipe::storeShapes(ResultBodyPtr theResultBody,
344                                       const GeomAPI_Shape::ShapeType theBaseShapeType,
345                                       const std::shared_ptr<GeomAPI_DataMapOfShapeShape> theMapOfSubShapes,
346                                       const ListOfShape& theShapes,
347                                       const std::string theName,
348                                       int& theTag)
349 {
350   GeomAPI_Shape::ShapeType aShapeTypeToExplore = GeomAPI_Shape::FACE;
351   std::string aShapeTypeStr = "Face";
352   switch(theBaseShapeType) {
353     case GeomAPI_Shape::VERTEX: {
354       aShapeTypeToExplore = GeomAPI_Shape::VERTEX;
355       aShapeTypeStr = "Vertex";
356       break;
357     }
358     case GeomAPI_Shape::EDGE:
359     case GeomAPI_Shape::WIRE: {
360       aShapeTypeToExplore = GeomAPI_Shape::EDGE;
361       aShapeTypeStr = "Edge";
362       break;
363     }
364     case GeomAPI_Shape::FACE:
365     case GeomAPI_Shape::SHELL: {
366       aShapeTypeToExplore = GeomAPI_Shape::FACE;
367       aShapeTypeStr = "Face";
368       break;
369     }
370   }
371
372   // Store shapes.
373   int aShapeIndex = 1;
374   std::string aName = theName + aShapeTypeStr;
375   for(ListOfShape::const_iterator anIt = theShapes.cbegin(); anIt != theShapes.cend(); ++anIt) {
376     std::shared_ptr<GeomAPI_Shape> aShape = *anIt;
377     for(GeomAPI_ShapeExplorer anExp(aShape, aShapeTypeToExplore); anExp.more(); anExp.next()) {
378       std::shared_ptr<GeomAPI_Shape> aSubShape = anExp.current();
379       if(theMapOfSubShapes->isBound(aSubShape)) {
380         aSubShape = theMapOfSubShapes->find(aSubShape);
381       }
382       std::ostringstream aStr;
383       aStr << aName << "_" << aShapeIndex++;
384       theResultBody->generated(aSubShape, aStr.str(), theTag++);
385     }
386   }
387 }