Salome HOME
Issue #1860: fix end lines with spaces
[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 <GeomAlgoAPI_ShapeTools.h>
19 #include <GeomAPI_PlanarEdges.h>
20 #include <GeomAPI_ShapeExplorer.h>
21
22 #include <map>
23 #include <sstream>
24
25 static void storeSubShape(ResultBodyPtr theResultBody,
26                           const GeomShapePtr theShape,
27                           const GeomAPI_Shape::ShapeType theType,
28                           const std::shared_ptr<GeomAPI_DataMapOfShapeShape> theMapOfSubShapes,
29                           const std::string theName,
30                           int& theShapeIndex,
31                           int& theTag);
32
33 //==================================================================================================
34 FeaturesPlugin_Pipe::FeaturesPlugin_Pipe()
35 {
36 }
37
38 //==================================================================================================
39 void FeaturesPlugin_Pipe::initAttributes()
40 {
41   data()->addAttribute(CREATION_METHOD(), ModelAPI_AttributeString::typeId());
42
43   data()->addAttribute(BASE_OBJECTS_ID(), ModelAPI_AttributeSelectionList::typeId());
44   data()->addAttribute(PATH_OBJECT_ID(), ModelAPI_AttributeSelection::typeId());
45
46   data()->addAttribute(BINORMAL_ID(), ModelAPI_AttributeSelection::typeId());
47
48   data()->addAttribute(LOCATIONS_ID(), ModelAPI_AttributeSelectionList::typeId());
49   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), LOCATIONS_ID());
50 }
51
52 //==================================================================================================
53 void FeaturesPlugin_Pipe::execute()
54 {
55   // Getting creation method.
56   std::string aCreationMethod = string(CREATION_METHOD())->value();
57
58   // Getting base objects.
59   ListOfShape aBaseShapesList, aBaseFacesList;
60   std::map<ResultConstructionPtr, ListOfShape> aSketchWiresMap;
61   AttributeSelectionListPtr aBaseObjectsSelectionList = selectionList(BASE_OBJECTS_ID());
62   if(!aBaseObjectsSelectionList.get()) {
63     setError("Error: Could not get base objects selection list.");
64     return;
65   }
66   if(aBaseObjectsSelectionList->size() == 0) {
67     setError("Error: Base objects list is empty.");
68     return;
69   }
70   for(int anIndex = 0; anIndex < aBaseObjectsSelectionList->size(); anIndex++) {
71     AttributeSelectionPtr aBaseObjectSelection = aBaseObjectsSelectionList->value(anIndex);
72     if(!aBaseObjectSelection.get()) {
73       setError("Error: One of the selected base objects is empty.");
74       return;
75     }
76     std::shared_ptr<GeomAPI_Shape> aBaseShape = aBaseObjectSelection->value();
77     if(aBaseShape.get() && !aBaseShape->isNull()) {
78       GeomAPI_Shape::ShapeType aST = aBaseShape->shapeType();
79       ResultConstructionPtr aConstruction =
80         std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aBaseObjectSelection->context());
81       if(aConstruction.get() && !aBaseShape->isEqual(aConstruction->shape()) &&
82           aST == GeomAPI_Shape::WIRE) {
83         // It is a wire on the sketch, store it to make face later.
84         aSketchWiresMap[aConstruction].push_back(aBaseShape);
85         continue;
86       } else {
87       aST == GeomAPI_Shape::FACE ? aBaseFacesList.push_back(aBaseShape) :
88                                    aBaseShapesList.push_back(aBaseShape);
89       }
90     } else {
91       // This may be the whole sketch result selected, check and get faces.
92       ResultConstructionPtr aConstruction =
93         std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aBaseObjectSelection->context());
94       if(!aConstruction.get()) {
95         setError("Error: One of selected sketches does not have results.");
96         return;
97       }
98       int aFacesNum = aConstruction->facesNum();
99       if(aFacesNum == 0) {
100         // Probably it can be construction.
101         aBaseShape = aConstruction->shape();
102         if(aBaseShape.get() && !aBaseShape->isNull()) {
103           aBaseShape->shapeType() == GeomAPI_Shape::FACE ? aBaseFacesList.push_back(aBaseShape) :
104                                                            aBaseShapesList.push_back(aBaseShape);
105         }
106       } else {
107         for(int aFaceIndex = 0; aFaceIndex < aFacesNum; aFaceIndex++) {
108           std::shared_ptr<GeomAPI_Shape> aBaseFace =
109             std::dynamic_pointer_cast<GeomAPI_Shape>(aConstruction->face(aFaceIndex));
110           if(!aBaseFace.get() || aBaseFace->isNull()) {
111             setError("Error: One of the faces on selected sketch is Null.");
112             return;
113           }
114           aBaseFacesList.push_back(aBaseFace);
115         }
116       }
117     }
118   }
119
120   // Make faces from sketch wires.
121   for(std::map<ResultConstructionPtr, ListOfShape>::const_iterator anIt = aSketchWiresMap.cbegin();
122       anIt != aSketchWiresMap.cend(); ++anIt) {
123     const std::shared_ptr<GeomAPI_PlanarEdges> aSketchPlanarEdges =
124       std::dynamic_pointer_cast<GeomAPI_PlanarEdges>((*anIt).first->shape());
125     const ListOfShape& aWiresList = (*anIt).second;
126     ListOfShape aFaces;
127     GeomAlgoAPI_ShapeTools::makeFacesWithHoles(aSketchPlanarEdges->origin(),
128                                                aSketchPlanarEdges->norm(),
129                                                aWiresList,
130                                                aFaces);
131     aBaseFacesList.insert(aBaseFacesList.end(), aFaces.begin(), aFaces.end());
132   }
133
134   // Searching faces with common edges.
135   if(aCreationMethod == CREATION_METHOD_SIMPLE()) {
136     ListOfShape aShells;
137     ListOfShape aFreeFaces;
138     std::shared_ptr<GeomAPI_Shape> aFacesCompound =
139       GeomAlgoAPI_CompoundBuilder::compound(aBaseFacesList);
140     GeomAlgoAPI_ShapeTools::combineShapes(aFacesCompound, GeomAPI_Shape::SHELL,
141                                           aShells, aFreeFaces);
142     aBaseShapesList.insert(aBaseShapesList.end(), aFreeFaces.begin(), aFreeFaces.end());
143     aBaseShapesList.insert(aBaseShapesList.end(), aShells.begin(), aShells.end());
144   } else {
145     aBaseShapesList.insert(aBaseShapesList.end(), aBaseFacesList.begin(), aBaseFacesList.end());
146   }
147
148   // Getting path.
149   AttributeSelectionPtr aPathSelection = selection(PATH_OBJECT_ID());
150   if(!aPathSelection.get()) {
151     setError("Error: Path selection is empty.");
152     return;
153   }
154   std::shared_ptr<GeomAPI_Shape> aPathShape =
155     std::dynamic_pointer_cast<GeomAPI_Shape>(aPathSelection->value());
156   if(!aPathShape.get()) {
157     // Probaply it is a construction.
158     aPathShape = aPathSelection->context()->shape();
159   }
160   if(!aPathShape.get() || aPathShape->isNull()) {
161     setError("Error: Path shape is null.");
162     return;
163   }
164
165   // Getting Bi-Normal
166   std::shared_ptr<GeomAPI_Shape> aBiNormal;
167   if(aCreationMethod == CREATION_METHOD_BINORMAL()) {
168     AttributeSelectionPtr aBiNormalSelection = selection(BINORMAL_ID());
169     if(!aBiNormalSelection.get()) {
170       setError("Error: Bi-Normal selection is empty.");
171       return;
172     }
173     aBiNormal = std::dynamic_pointer_cast<GeomAPI_Shape>(aBiNormalSelection->value());
174     if(!aBiNormal.get()) {
175       // Probably it is a construction.
176       aBiNormal = aBiNormalSelection->context()->shape();
177     }
178     if(!aBiNormal.get() || aBiNormal->isNull()) {
179       setError("Error: Bi-Normal shape is null.");
180       return;
181     }
182   }
183
184   // Getting locations.
185   ListOfShape aLocations;
186   if(aCreationMethod == CREATION_METHOD_LOCATIONS()) {
187     AttributeSelectionListPtr aLocationsSelectionList = selectionList(LOCATIONS_ID());
188     if(!aLocationsSelectionList.get()) {
189       setError("Error: Could not get locations selection list.");
190       return;
191     }
192     for(int anIndex = 0; anIndex < aLocationsSelectionList->size(); anIndex++) {
193       AttributeSelectionPtr aLocationSelection = aLocationsSelectionList->value(anIndex);
194       if(!aLocationSelection.get()) {
195         setError("Error: One of the selected location is empty.");
196         return;
197       }
198       std::shared_ptr<GeomAPI_Shape> aLocationShape = aLocationSelection->value();
199       if(!aLocationShape.get()) {
200         // Probably it is a construction.
201         aLocationShape = aLocationSelection->context()->shape();
202       }
203       if(!aLocationShape.get() || aLocationShape->isNull()) {
204         setError("Error: One of the selected location shape is null.");
205         return;
206       }
207       aLocations.push_back(aLocationShape);
208     }
209   }
210
211   // Generating result for each object.
212   int aResultIndex = 0;
213   if(aCreationMethod == CREATION_METHOD_SIMPLE() ||
214       aCreationMethod == CREATION_METHOD_BINORMAL()) {
215     for(ListOfShape::const_iterator
216         anIter = aBaseShapesList.cbegin(); anIter != aBaseShapesList.cend(); anIter++) {
217       std::shared_ptr<GeomAPI_Shape> aBaseShape = *anIter;
218
219       GeomAlgoAPI_Pipe aPipeAlgo = aCreationMethod ==
220         CREATION_METHOD_SIMPLE() ? GeomAlgoAPI_Pipe(aBaseShape, aPathShape) :
221                                    GeomAlgoAPI_Pipe(aBaseShape, aPathShape, aBiNormal);
222
223       if(!aPipeAlgo.isDone()) {
224         setError("Error: Pipe algorithm failed.");
225         aResultIndex = 0;
226         break;
227       }
228
229       // Check if shape is valid
230       if(!aPipeAlgo.shape().get() || aPipeAlgo.shape()->isNull()) {
231         setError("Error: Resulting shape is Null.");
232         aResultIndex = 0;
233         break;
234       }
235       if(!aPipeAlgo.isValid()) {
236         setError("Error: Resulting shape is not valid.");
237         aResultIndex = 0;
238         break;
239       }
240
241       storeResult(aBaseShape, aPipeAlgo, aResultIndex++);
242     }
243   } else if(aCreationMethod == CREATION_METHOD_LOCATIONS()) {
244     GeomAlgoAPI_Pipe aPipeAlgo = GeomAlgoAPI_Pipe(aBaseShapesList, aLocations, aPathShape);
245
246     if(!aPipeAlgo.isDone()) {
247       setError("Error: Pipe algorithm failed.");
248       removeResults(0);
249       return;
250     }
251
252     // Check if shape is valid
253     if(!aPipeAlgo.shape().get() || aPipeAlgo.shape()->isNull()) {
254       setError("Error: Resulting shape is Null.");
255       removeResults(0);
256       return;
257     }
258     if(!aPipeAlgo.isValid()) {
259       setError("Error: Resulting shape is not valid.");
260       removeResults(0);
261       return;
262     }
263
264     storeResult(aBaseShapesList, aPipeAlgo, aResultIndex++);
265   } else {
266     setError("Error: Wrong creation method.");
267     return;
268   }
269
270   removeResults(aResultIndex);
271 }
272
273 //==================================================================================================
274 void FeaturesPlugin_Pipe::storeResult(const std::shared_ptr<GeomAPI_Shape> theBaseShape,
275                                       GeomAlgoAPI_Pipe& thePipeAlgo,
276                                       const int theResultIndex)
277 {
278   // Create result body.
279   ResultBodyPtr aResultBody = document()->createBody(data(), theResultIndex);
280
281   // Store generated shape.
282   aResultBody->storeGenerated(theBaseShape, thePipeAlgo.shape());
283
284   // Store generated edges/faces.
285   GeomAPI_Shape::ShapeType aBaseShapeType = theBaseShape->shapeType();
286   GeomAPI_Shape::ShapeType aShapeTypeToExplode;
287   int aGenTag = 1;
288   std::string aGenName = "Generated_";
289
290   std::shared_ptr<GeomAPI_DataMapOfShapeShape> aMapOfSubShapes = thePipeAlgo.mapOfSubShapes();
291   switch(aBaseShapeType) {
292     case GeomAPI_Shape::VERTEX: {
293       aShapeTypeToExplode = GeomAPI_Shape::VERTEX;
294       break;
295     }
296     case GeomAPI_Shape::EDGE:
297     case GeomAPI_Shape::WIRE: {
298       std::shared_ptr<GeomAPI_Vertex> aV1, aV2;
299       GeomAlgoAPI_ShapeTools::findBounds(theBaseShape, aV1, aV2);
300       ListOfShape aV1History, aV2History;
301       thePipeAlgo.generated(aV1, aV1History);
302       thePipeAlgo.generated(aV2, aV2History);
303       if(!aV1History.empty()) {
304         aResultBody->generated(aV1, aV1History.front(), aGenName + "Edge_1", aGenTag++);
305       }
306       if(!aV2History.empty()) {
307         aResultBody->generated(aV2, aV2History.front(), aGenName + "Edge_2", aGenTag++);
308       }
309     }
310     case GeomAPI_Shape::FACE:
311     case GeomAPI_Shape::SHELL: {
312       aShapeTypeToExplode = GeomAPI_Shape::EDGE;
313       break;
314     }
315     case GeomAPI_Shape::COMPOUND: {
316       aShapeTypeToExplode = GeomAPI_Shape::COMPOUND;
317     }
318   }
319
320   if(aShapeTypeToExplode == GeomAPI_Shape::VERTEX ||
321       aShapeTypeToExplode == GeomAPI_Shape::COMPOUND) {
322     aResultBody->loadAndOrientGeneratedShapes(&thePipeAlgo, theBaseShape, GeomAPI_Shape::VERTEX,
323                                            aGenTag++, aGenName + "Edge", *aMapOfSubShapes.get());
324   }
325   if(aShapeTypeToExplode == GeomAPI_Shape::EDGE ||
326       aShapeTypeToExplode == GeomAPI_Shape::COMPOUND) {
327     aResultBody->loadAndOrientGeneratedShapes(&thePipeAlgo, theBaseShape, GeomAPI_Shape::EDGE,
328                                            aGenTag++, aGenName + "Face", *aMapOfSubShapes.get());
329   }
330
331   aResultBody->loadAndOrientGeneratedShapes(&thePipeAlgo, theBaseShape, aShapeTypeToExplode,
332                                             aGenTag++, aGenName, *aMapOfSubShapes.get());
333
334   // Store from shapes.
335   int aFromTag = aGenTag;
336   storeShapes(aResultBody, aBaseShapeType, aMapOfSubShapes,
337               thePipeAlgo.fromShapes(), "From_", aFromTag);
338
339   // Store to shapes.
340   int aToTag = aFromTag;
341   storeShapes(aResultBody, aBaseShapeType, aMapOfSubShapes, thePipeAlgo.toShapes(), "To_", aToTag);
342
343   setResult(aResultBody, theResultIndex);
344 }
345
346 //==================================================================================================
347 void FeaturesPlugin_Pipe::storeResult(const ListOfShape& theBaseShapes,
348                                       GeomAlgoAPI_Pipe& thePipeAlgo,
349                                       const int theResultIndex)
350 {
351   // Create result body.
352   ResultBodyPtr aResultBody = document()->createBody(data(), theResultIndex);
353
354   // Store generated shape.
355   aResultBody->storeGenerated(theBaseShapes.front(), thePipeAlgo.shape());
356
357   // Store generated edges/faces.
358   int aGenTag = 1;
359   std::shared_ptr<GeomAPI_DataMapOfShapeShape> aMapOfSubShapes = thePipeAlgo.mapOfSubShapes();
360
361   for(ListOfShape::const_iterator
362       anIter = theBaseShapes.cbegin(); anIter != theBaseShapes.cend(); anIter++) {
363     GeomShapePtr aBaseShape = *anIter;
364     GeomAPI_Shape::ShapeType aBaseShapeType = aBaseShape->shapeType();
365     GeomAPI_Shape::ShapeType aShapeTypeToExplode;
366     std::string aGenName = "Generated_";
367     switch(aBaseShapeType) {
368       case GeomAPI_Shape::VERTEX: {
369         aShapeTypeToExplode = GeomAPI_Shape::VERTEX;
370         aGenName += "Edge";
371         break;
372       }
373       case GeomAPI_Shape::EDGE:
374       case GeomAPI_Shape::WIRE: {
375         std::shared_ptr<GeomAPI_Vertex> aV1, aV2;
376         GeomAlgoAPI_ShapeTools::findBounds(aBaseShape, aV1, aV2);
377         ListOfShape aV1History, aV2History;
378         thePipeAlgo.generated(aV1, aV1History);
379         thePipeAlgo.generated(aV2, aV2History);
380         aResultBody->generated(aV1, aV1History.front(), aGenName + "Edge_1", aGenTag++);
381         aResultBody->generated(aV2, aV2History.front(), aGenName + "Edge_2", aGenTag++);
382       }
383       case GeomAPI_Shape::FACE:
384       case GeomAPI_Shape::SHELL: {
385         aShapeTypeToExplode = GeomAPI_Shape::EDGE;
386         aGenName += "Face";
387         break;
388       }
389     }
390     aResultBody->loadAndOrientGeneratedShapes(&thePipeAlgo, aBaseShape, aShapeTypeToExplode,
391                                               aGenTag++, aGenName, *aMapOfSubShapes.get());
392   }
393
394   // Store from shapes.
395   int aFromTag = aGenTag;
396   storeShapes(aResultBody, theBaseShapes.front()->shapeType(), aMapOfSubShapes,
397               thePipeAlgo.fromShapes(), "From", aFromTag);
398
399   // Store to shapes.
400   int aToTag = aFromTag;
401   storeShapes(aResultBody, theBaseShapes.back()->shapeType(),
402               aMapOfSubShapes, thePipeAlgo.toShapes(), "To", aToTag);
403
404
405   setResult(aResultBody, theResultIndex);
406 }
407
408 //==================================================================================================
409 void FeaturesPlugin_Pipe::storeShapes(ResultBodyPtr theResultBody,
410                               const GeomAPI_Shape::ShapeType theBaseShapeType,
411                               const std::shared_ptr<GeomAPI_DataMapOfShapeShape> theMapOfSubShapes,
412                               const ListOfShape& theShapes,
413                               const std::string theName,
414                               int& theTag)
415 {
416   GeomAPI_Shape::ShapeType aShapeTypeToExplore = GeomAPI_Shape::FACE;
417   std::string aShapeTypeStr = "Face";
418   switch(theBaseShapeType) {
419     case GeomAPI_Shape::VERTEX: {
420       aShapeTypeToExplore = GeomAPI_Shape::VERTEX;
421       aShapeTypeStr = "Vertex";
422       break;
423     }
424     case GeomAPI_Shape::EDGE:
425     case GeomAPI_Shape::WIRE: {
426       aShapeTypeToExplore = GeomAPI_Shape::EDGE;
427       aShapeTypeStr = "Edge";
428       break;
429     }
430     case GeomAPI_Shape::FACE:
431     case GeomAPI_Shape::SHELL: {
432       aShapeTypeToExplore = GeomAPI_Shape::FACE;
433       aShapeTypeStr = "Face";
434       break;
435     }
436     case GeomAPI_Shape::COMPOUND: {
437       aShapeTypeToExplore = GeomAPI_Shape::COMPOUND;
438       break;
439     }
440   }
441
442   // Store shapes.
443   int aShapeIndex = 1;
444   int aFaceIndex = 1;
445   for(ListOfShape::const_iterator anIt = theShapes.cbegin(); anIt != theShapes.cend(); ++anIt) {
446     GeomShapePtr aShape = *anIt;
447
448     if(aShapeTypeToExplore == GeomAPI_Shape::COMPOUND) {
449       std::string aName = theName + (aShape->shapeType() == GeomAPI_Shape::EDGE ? "Edge" : "Face");
450       storeSubShape(theResultBody,
451                     aShape,
452                     aShape->shapeType(),
453                     theMapOfSubShapes,
454                     aName,
455                     aShape->shapeType() == GeomAPI_Shape::EDGE ? aShapeIndex : aFaceIndex,
456                     theTag);
457     } else {
458       std::string aName = theName + aShapeTypeStr;
459       storeSubShape(theResultBody, aShape, aShapeTypeToExplore,
460                     theMapOfSubShapes, aName, aShapeIndex, theTag);
461     }
462   }
463 }
464
465 //==================================================================================================
466 void storeSubShape(ResultBodyPtr theResultBody,
467                    const GeomShapePtr theShape,
468                    const GeomAPI_Shape::ShapeType theType,
469                    const std::shared_ptr<GeomAPI_DataMapOfShapeShape> theMapOfSubShapes,
470                    const std::string theName,
471                    int& theShapeIndex,
472                    int& theTag)
473 {
474   for(GeomAPI_ShapeExplorer anExp(theShape, theType); anExp.more(); anExp.next()) {
475     GeomShapePtr aSubShape = anExp.current();
476     if(theMapOfSubShapes->isBound(aSubShape)) {
477       aSubShape = theMapOfSubShapes->find(aSubShape);
478     }
479     std::ostringstream aStr;
480     aStr << theName << "_" << theShapeIndex++;
481     theResultBody->generated(aSubShape, aStr.str(), theTag++);
482   }
483 }