Salome HOME
c5c279f09f5e9297387ad206dd6437ffe4400fb3
[modules/shaper.git] / src / FeaturesPlugin / FeaturesPlugin_Pipe.cpp
1 // Copyright (C) 2014-2022  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "FeaturesPlugin_Pipe.h"
21
22 #include <ModelAPI_AttributeSelection.h>
23 #include <ModelAPI_AttributeSelectionList.h>
24 #include <ModelAPI_AttributeString.h>
25 #include <ModelAPI_ResultConstruction.h>
26 #include <ModelAPI_Session.h>
27 #include <ModelAPI_Validator.h>
28
29 #include <GeomAlgoAPI_CompoundBuilder.h>
30 #include <GeomAlgoAPI_Pipe.h>
31 #include <GeomAlgoAPI_ShapeTools.h>
32 #include <GeomAlgoAPI_Tools.h>
33
34 #include <GeomAPI_PlanarEdges.h>
35 #include <GeomAPI_ShapeExplorer.h>
36
37 #include <map>
38 #include <sstream>
39
40 static void storeSubShape(ResultBodyPtr theResultBody,
41                           const GeomShapePtr theShape,
42                           const GeomAPI_Shape::ShapeType theType,
43                           const std::string theName,
44                           int& theShapeIndex);
45
46 //==================================================================================================
47 FeaturesPlugin_Pipe::FeaturesPlugin_Pipe()
48 {
49 }
50
51 //==================================================================================================
52 void FeaturesPlugin_Pipe::initAttributes()
53 {
54   data()->addAttribute(CREATION_METHOD(), ModelAPI_AttributeString::typeId());
55
56   data()->addAttribute(BASE_OBJECTS_ID(), ModelAPI_AttributeSelectionList::typeId());
57   data()->addAttribute(PATH_OBJECT_ID(), ModelAPI_AttributeSelection::typeId());
58
59   data()->addAttribute(BINORMAL_ID(), ModelAPI_AttributeSelection::typeId());
60
61   data()->addAttribute(LOCATIONS_ID(), ModelAPI_AttributeSelectionList::typeId());
62   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), LOCATIONS_ID());
63 }
64
65 //==================================================================================================
66 void FeaturesPlugin_Pipe::execute()
67 {
68   // Getting creation method.
69   std::string aCreationMethod = string(CREATION_METHOD())->value();
70
71   // Getting base objects.
72   ListOfShape aBaseShapesList, aBaseFacesList;
73   std::map<ResultConstructionPtr, ListOfShape> aSketchWiresMap;
74   AttributeSelectionListPtr aBaseObjectsSelectionList = selectionList(BASE_OBJECTS_ID());
75   if(!aBaseObjectsSelectionList.get()) {
76     setError("Error: Could not get base objects selection list.");
77     return;
78   }
79   if(aBaseObjectsSelectionList->size() == 0) {
80     setError("Error: Base objects list is empty.");
81     return;
82   }
83   for(int anIndex = 0; anIndex < aBaseObjectsSelectionList->size(); anIndex++) {
84     AttributeSelectionPtr aBaseObjectSelection = aBaseObjectsSelectionList->value(anIndex);
85     if(!aBaseObjectSelection.get()) {
86       setError("Error: One of the selected base objects is empty.");
87       return;
88     }
89     std::shared_ptr<GeomAPI_Shape> aBaseShape = aBaseObjectSelection->value();
90     if(aBaseShape.get() && !aBaseShape->isNull()) {
91       GeomAPI_Shape::ShapeType aST = aBaseShape->shapeType();
92       ResultConstructionPtr aConstruction =
93         std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aBaseObjectSelection->context());
94       if(aConstruction.get() && !aBaseShape->isEqual(aConstruction->shape()) &&
95           aST == GeomAPI_Shape::WIRE) {
96         // It is a wire on the sketch, store it to make face later.
97         aSketchWiresMap[aConstruction].push_back(aBaseShape);
98         continue;
99       } else {
100       aST == GeomAPI_Shape::FACE ? aBaseFacesList.push_back(aBaseShape) :
101                                    aBaseShapesList.push_back(aBaseShape);
102       }
103     } else {
104       // This may be the whole sketch result selected, check and get faces.
105       ResultConstructionPtr aConstruction =
106         std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aBaseObjectSelection->context());
107       if(!aConstruction.get()) {
108         setError("Error: One of selected sketches does not have results.");
109         return;
110       }
111       int aFacesNum = aConstruction->facesNum();
112       if(aFacesNum == 0) {
113         // Probably it can be construction.
114         aBaseShape = aConstruction->shape();
115         if(aBaseShape.get() && !aBaseShape->isNull()) {
116           aBaseShape->shapeType() == GeomAPI_Shape::FACE ? aBaseFacesList.push_back(aBaseShape) :
117                                                            aBaseShapesList.push_back(aBaseShape);
118         }
119       } else {
120         for(int aFaceIndex = 0; aFaceIndex < aFacesNum; aFaceIndex++) {
121           std::shared_ptr<GeomAPI_Shape> aBaseFace =
122             std::dynamic_pointer_cast<GeomAPI_Shape>(aConstruction->face(aFaceIndex));
123           if(!aBaseFace.get() || aBaseFace->isNull()) {
124             setError("Error: One of the faces on selected sketch is Null.");
125             return;
126           }
127           aBaseFacesList.push_back(aBaseFace);
128         }
129       }
130     }
131   }
132
133   // Make faces from sketch wires.
134   for(std::map<ResultConstructionPtr, ListOfShape>::const_iterator anIt = aSketchWiresMap.cbegin();
135       anIt != aSketchWiresMap.cend(); ++anIt) {
136     const std::shared_ptr<GeomAPI_PlanarEdges> aSketchPlanarEdges =
137       std::dynamic_pointer_cast<GeomAPI_PlanarEdges>((*anIt).first->shape());
138     const ListOfShape& aWiresList = (*anIt).second;
139     ListOfShape aFaces;
140     GeomAlgoAPI_ShapeTools::makeFacesWithHoles(aSketchPlanarEdges->origin(),
141                                                aSketchPlanarEdges->norm(),
142                                                aWiresList,
143                                                aFaces);
144     aBaseFacesList.insert(aBaseFacesList.end(), aFaces.begin(), aFaces.end());
145   }
146
147   // Searching faces with common edges.
148   if(aCreationMethod == CREATION_METHOD_SIMPLE()) {
149     std::shared_ptr<GeomAPI_Shape> aFacesCompound =
150       GeomAlgoAPI_CompoundBuilder::compound(aBaseFacesList);
151     GeomAlgoAPI_ShapeTools::combineShapes(aFacesCompound, GeomAPI_Shape::SHELL, aBaseShapesList);
152   } else {
153     aBaseShapesList.insert(aBaseShapesList.end(), aBaseFacesList.begin(), aBaseFacesList.end());
154   }
155
156   // Getting path.
157   AttributeSelectionPtr aPathSelection = selection(PATH_OBJECT_ID());
158   if(!aPathSelection.get()) {
159     setError("Error: Path selection is empty.");
160     return;
161   }
162   std::shared_ptr<GeomAPI_Shape> aPathShape =
163     std::dynamic_pointer_cast<GeomAPI_Shape>(aPathSelection->value());
164   if(!aPathShape.get() && aPathSelection->context().get()) {
165     // Probably it is a construction.
166     aPathShape = aPathSelection->context()->shape();
167   }
168   if(!aPathShape.get() || aPathShape->isNull()) {
169     setError("Error: Path shape is null.");
170     return;
171   }
172
173   // Getting Bi-Normal
174   std::shared_ptr<GeomAPI_Shape> aBiNormal;
175   if(aCreationMethod == CREATION_METHOD_BINORMAL()) {
176     AttributeSelectionPtr aBiNormalSelection = selection(BINORMAL_ID());
177     if(!aBiNormalSelection.get()) {
178       setError("Error: Bi-Normal selection is empty.");
179       return;
180     }
181     aBiNormal = std::dynamic_pointer_cast<GeomAPI_Shape>(aBiNormalSelection->value());
182     if(!aBiNormal.get() && aBiNormalSelection->context().get()) {
183       // Probably it is a construction.
184       aBiNormal = aBiNormalSelection->context()->shape();
185     }
186     if(!aBiNormal.get() || aBiNormal->isNull()) {
187       setError("Error: Bi-Normal shape is null.");
188       return;
189     }
190   }
191
192   // Getting locations.
193   ListOfShape aLocations;
194   if(aCreationMethod == CREATION_METHOD_LOCATIONS()) {
195     AttributeSelectionListPtr aLocationsSelectionList = selectionList(LOCATIONS_ID());
196     if(!aLocationsSelectionList.get()) {
197       setError("Error: Could not get locations selection list.");
198       return;
199     }
200     for(int anIndex = 0; anIndex < aLocationsSelectionList->size(); anIndex++) {
201       AttributeSelectionPtr aLocationSelection = aLocationsSelectionList->value(anIndex);
202       if(!aLocationSelection.get()) {
203         setError("Error: One of the selected location is empty.");
204         return;
205       }
206       std::shared_ptr<GeomAPI_Shape> aLocationShape = aLocationSelection->value();
207       if(!aLocationShape.get() && aLocationSelection->context().get()) {
208         // Probably it is a construction.
209         aLocationShape = aLocationSelection->context()->shape();
210       }
211       if(!aLocationShape.get() || aLocationShape->isNull()) {
212         setError("Error: One of the selected location shape is null.");
213         return;
214       }
215       aLocations.push_back(aLocationShape);
216     }
217   }
218
219   // Generating result for each object.
220   int aResultIndex = 0;
221   std::string anError;
222   if(aCreationMethod == CREATION_METHOD_SIMPLE() ||
223       aCreationMethod == CREATION_METHOD_BINORMAL()) {
224     for(ListOfShape::const_iterator
225         anIter = aBaseShapesList.cbegin(); anIter != aBaseShapesList.cend(); anIter++) {
226       std::shared_ptr<GeomAPI_Shape> aBaseShape = *anIter;
227
228       std::shared_ptr<GeomAlgoAPI_Pipe> aPipeAlgo(
229         aCreationMethod == CREATION_METHOD_SIMPLE() ? new GeomAlgoAPI_Pipe(aBaseShape,
230                                                                            aPathShape)
231                                                     : new GeomAlgoAPI_Pipe(aBaseShape,
232                                                                            aPathShape,
233                                                                            aBiNormal));
234
235       if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aPipeAlgo, getKind(), anError)) {
236         setError(anError);
237         aResultIndex = 0;
238         break;
239       }
240
241       storeResult(aBaseShape, aPathShape, aPipeAlgo, aResultIndex++);
242     }
243   } else if(aCreationMethod == CREATION_METHOD_LOCATIONS()) {
244     std::shared_ptr<GeomAlgoAPI_Pipe> aPipeAlgo(new GeomAlgoAPI_Pipe(aBaseShapesList,
245                                                                      aLocations,
246                                                                      aPathShape));
247
248     if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aPipeAlgo, getKind(), anError)) {
249       setError(anError);
250       removeResults(0);
251       return;
252     }
253
254     storeResult(aBaseShapesList, aPathShape, aPipeAlgo, aResultIndex++);
255   } else {
256     setError("Error: Wrong creation method.");
257     return;
258   }
259
260   removeResults(aResultIndex);
261 }
262
263 //==================================================================================================
264 void FeaturesPlugin_Pipe::storeResult(const std::shared_ptr<GeomAPI_Shape> theBaseShape,
265                                       const std::shared_ptr<GeomAPI_Shape> thePathShape,
266                                       const std::shared_ptr<GeomAlgoAPI_Pipe> thePipeAlgo,
267                                       const int theResultIndex)
268 {
269   // Create result body.
270   ResultBodyPtr aResultBody = document()->createBody(data(), theResultIndex);
271
272   // Store generated shape.
273   aResultBody->storeGenerated(theBaseShape, thePipeAlgo->shape());
274
275   // Store generated edges/faces.
276   GeomAPI_Shape::ShapeType aBaseShapeType = theBaseShape->shapeType();
277   GeomAPI_Shape::ShapeType aShapeTypeToExplode = GeomAPI_Shape::SHAPE;
278
279   switch(aBaseShapeType) {
280     case GeomAPI_Shape::VERTEX: {
281       aShapeTypeToExplode = GeomAPI_Shape::VERTEX;
282       break;
283     }
284     case GeomAPI_Shape::EDGE:
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       thePipeAlgo->generated(aV1, aV1History);
290       thePipeAlgo->generated(aV2, aV2History);
291       if(!aV1History.empty()) {
292         aResultBody->generated(aV1, aV1History.front());
293       }
294       if(!aV2History.empty()) {
295         aResultBody->generated(aV2, aV2History.front());
296       }
297     }
298     case GeomAPI_Shape::FACE:
299     case GeomAPI_Shape::SHELL: {
300       aShapeTypeToExplode = GeomAPI_Shape::EDGE;
301       break;
302     }
303     case GeomAPI_Shape::COMPOUND: {
304       aShapeTypeToExplode = GeomAPI_Shape::COMPOUND;
305       break;
306     }
307     default:
308       return; // unsupported type of shape
309   }
310
311   if(aShapeTypeToExplode == GeomAPI_Shape::VERTEX ||
312       aShapeTypeToExplode == GeomAPI_Shape::COMPOUND) {
313     aResultBody->loadGeneratedShapes(thePipeAlgo, theBaseShape, GeomAPI_Shape::VERTEX);
314   }
315   if(aShapeTypeToExplode == GeomAPI_Shape::EDGE ||
316       aShapeTypeToExplode == GeomAPI_Shape::COMPOUND) {
317     aResultBody->loadGeneratedShapes(thePipeAlgo, theBaseShape, GeomAPI_Shape::EDGE);
318   }
319   if (thePathShape.get())
320     aResultBody->loadGeneratedShapes(thePipeAlgo, thePathShape, GeomAPI_Shape::EDGE);
321
322   // Store from shapes.
323   storeShapes(aResultBody, aBaseShapeType, thePipeAlgo->fromShapes(), "From_");
324
325   // Store to shapes.
326   storeShapes(aResultBody, aBaseShapeType, thePipeAlgo->toShapes(), "To_");
327
328   setResult(aResultBody, theResultIndex);
329 }
330
331 //==================================================================================================
332 void FeaturesPlugin_Pipe::storeResult(const ListOfShape& theBaseShapes,
333                                       const std::shared_ptr<GeomAPI_Shape> thePathShape,
334                                       const std::shared_ptr<GeomAlgoAPI_Pipe> thePipeAlgo,
335                                       const int theResultIndex)
336 {
337   // Create result body.
338   ResultBodyPtr aResultBody = document()->createBody(data(), theResultIndex);
339
340   // Store generated shape.
341   aResultBody->storeGenerated(theBaseShapes.front(), thePipeAlgo->shape());
342
343   // Store generated edges/faces.
344   for(ListOfShape::const_iterator anIter = theBaseShapes.cbegin();
345       anIter != theBaseShapes.cend();
346       ++anIter)
347   {
348     GeomShapePtr aBaseShape = *anIter;
349     GeomAPI_Shape::ShapeType aBaseShapeType = aBaseShape->shapeType();
350     GeomAPI_Shape::ShapeType aShapeTypeToExplode = GeomAPI_Shape::SHAPE;
351     switch(aBaseShapeType) {
352       case GeomAPI_Shape::VERTEX: {
353         aShapeTypeToExplode = GeomAPI_Shape::VERTEX;
354         break;
355       }
356       case GeomAPI_Shape::EDGE:
357       case GeomAPI_Shape::WIRE: {
358         std::shared_ptr<GeomAPI_Vertex> aV1, aV2;
359         GeomAlgoAPI_ShapeTools::findBounds(aBaseShape, aV1, aV2);
360         ListOfShape aV1History, aV2History;
361         thePipeAlgo->generated(aV1, aV1History);
362         thePipeAlgo->generated(aV2, aV2History);
363         if (!aV1History.empty())
364           aResultBody->generated(aV1, aV1History.front());
365         if (!aV2History.empty())
366           aResultBody->generated(aV2, aV2History.front());
367       }
368       case GeomAPI_Shape::FACE:
369       case GeomAPI_Shape::SHELL: {
370         aShapeTypeToExplode = GeomAPI_Shape::EDGE;
371         break;
372       }
373       default:
374         return; // unsupported type of shape
375     }
376     aResultBody->loadGeneratedShapes(thePipeAlgo, aBaseShape, aShapeTypeToExplode);
377   }
378
379   if (thePathShape.get())
380     aResultBody->loadGeneratedShapes(thePipeAlgo, thePathShape, GeomAPI_Shape::EDGE);
381
382   // Store from shapes.
383   storeShapes(aResultBody, theBaseShapes.front()->shapeType(), thePipeAlgo->fromShapes(), "From_");
384
385   // Store to shapes.
386   storeShapes(aResultBody, theBaseShapes.back()->shapeType(), thePipeAlgo->toShapes(), "To_");
387
388
389   setResult(aResultBody, theResultIndex);
390 }
391
392 //==================================================================================================
393 void FeaturesPlugin_Pipe::storeShapes(ResultBodyPtr theResultBody,
394                                       const GeomAPI_Shape::ShapeType theBaseShapeType,
395                                       const ListOfShape& theShapes,
396                                       const std::string theName)
397 {
398   GeomAPI_Shape::ShapeType aShapeTypeToExplore = GeomAPI_Shape::FACE;
399   std::string aShapeTypeStr = "Face";
400   switch(theBaseShapeType) {
401     case GeomAPI_Shape::VERTEX: {
402       aShapeTypeToExplore = GeomAPI_Shape::VERTEX;
403       aShapeTypeStr = "Vertex";
404       break;
405     }
406     case GeomAPI_Shape::EDGE:
407     case GeomAPI_Shape::WIRE: {
408       aShapeTypeToExplore = GeomAPI_Shape::EDGE;
409       aShapeTypeStr = "Edge";
410       break;
411     }
412     case GeomAPI_Shape::FACE:
413     case GeomAPI_Shape::SHELL: {
414       aShapeTypeToExplore = GeomAPI_Shape::FACE;
415       aShapeTypeStr = "Face";
416       break;
417     }
418     case GeomAPI_Shape::COMPOUND: {
419       aShapeTypeToExplore = GeomAPI_Shape::COMPOUND;
420       break;
421     }
422     default:
423       return; // unsupported type of shape
424   }
425
426   // Store shapes.
427   int aShapeIndex = 1;
428   int aFaceIndex = 1;
429   for(ListOfShape::const_iterator anIt = theShapes.cbegin(); anIt != theShapes.cend(); ++anIt) {
430     GeomShapePtr aShape = *anIt;
431
432     if(aShapeTypeToExplore == GeomAPI_Shape::COMPOUND) {
433       std::string aName = theName + (aShape->shapeType() == GeomAPI_Shape::EDGE ? "Edge" : "Face");
434       storeSubShape(theResultBody, aShape,
435                     aShape->shapeType(),
436                     aName,
437                     aShape->shapeType() == GeomAPI_Shape::EDGE ? aShapeIndex : aFaceIndex);
438     } else {
439       std::string aName = theName + aShapeTypeStr;
440       storeSubShape(theResultBody, aShape, aShapeTypeToExplore, aName, aShapeIndex);
441     }
442   }
443 }
444
445 //==================================================================================================
446 void storeSubShape(ResultBodyPtr theResultBody,
447                    const GeomShapePtr theShape,
448                    const GeomAPI_Shape::ShapeType theType,
449                    const std::string theName,
450                    int& theShapeIndex)
451 {
452   for(GeomAPI_ShapeExplorer anExp(theShape, theType); anExp.more(); anExp.next()) {
453     GeomShapePtr aSubShape = anExp.current();
454     std::ostringstream aStr;
455     aStr << theName << "_" << theShapeIndex++;
456     theResultBody->generated(aSubShape, aStr.str());
457   }
458 }