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