Salome HOME
d8d90cd6efac17b29645cd287ef53584d28358b9
[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::shared_ptr<GeomAPI_DataMapOfShapeShape> theMapOfSubShapes,
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     ListOfShape aShells;
150     ListOfShape aFreeFaces;
151     std::shared_ptr<GeomAPI_Shape> aFacesCompound =
152       GeomAlgoAPI_CompoundBuilder::compound(aBaseFacesList);
153     GeomAlgoAPI_ShapeTools::combineShapes(aFacesCompound, GeomAPI_Shape::SHELL,
154                                           aShells, aFreeFaces);
155     aBaseShapesList.insert(aBaseShapesList.end(), aFreeFaces.begin(), aFreeFaces.end());
156     aBaseShapesList.insert(aBaseShapesList.end(), aShells.begin(), aShells.end());
157   } else {
158     aBaseShapesList.insert(aBaseShapesList.end(), aBaseFacesList.begin(), aBaseFacesList.end());
159   }
160
161   // Getting path.
162   AttributeSelectionPtr aPathSelection = selection(PATH_OBJECT_ID());
163   if(!aPathSelection.get()) {
164     setError("Error: Path selection is empty.");
165     return;
166   }
167   std::shared_ptr<GeomAPI_Shape> aPathShape =
168     std::dynamic_pointer_cast<GeomAPI_Shape>(aPathSelection->value());
169   if(!aPathShape.get()) {
170     // Probaply it is a construction.
171     aPathShape = aPathSelection->context()->shape();
172   }
173   if(!aPathShape.get() || aPathShape->isNull()) {
174     setError("Error: Path shape is null.");
175     return;
176   }
177
178   // Getting Bi-Normal
179   std::shared_ptr<GeomAPI_Shape> aBiNormal;
180   if(aCreationMethod == CREATION_METHOD_BINORMAL()) {
181     AttributeSelectionPtr aBiNormalSelection = selection(BINORMAL_ID());
182     if(!aBiNormalSelection.get()) {
183       setError("Error: Bi-Normal selection is empty.");
184       return;
185     }
186     aBiNormal = std::dynamic_pointer_cast<GeomAPI_Shape>(aBiNormalSelection->value());
187     if(!aBiNormal.get()) {
188       // Probably it is a construction.
189       aBiNormal = aBiNormalSelection->context()->shape();
190     }
191     if(!aBiNormal.get() || aBiNormal->isNull()) {
192       setError("Error: Bi-Normal shape is null.");
193       return;
194     }
195   }
196
197   // Getting locations.
198   ListOfShape aLocations;
199   if(aCreationMethod == CREATION_METHOD_LOCATIONS()) {
200     AttributeSelectionListPtr aLocationsSelectionList = selectionList(LOCATIONS_ID());
201     if(!aLocationsSelectionList.get()) {
202       setError("Error: Could not get locations selection list.");
203       return;
204     }
205     for(int anIndex = 0; anIndex < aLocationsSelectionList->size(); anIndex++) {
206       AttributeSelectionPtr aLocationSelection = aLocationsSelectionList->value(anIndex);
207       if(!aLocationSelection.get()) {
208         setError("Error: One of the selected location is empty.");
209         return;
210       }
211       std::shared_ptr<GeomAPI_Shape> aLocationShape = aLocationSelection->value();
212       if(!aLocationShape.get()) {
213         // Probably it is a construction.
214         aLocationShape = aLocationSelection->context()->shape();
215       }
216       if(!aLocationShape.get() || aLocationShape->isNull()) {
217         setError("Error: One of the selected location shape is null.");
218         return;
219       }
220       aLocations.push_back(aLocationShape);
221     }
222   }
223
224   // Generating result for each object.
225   int aResultIndex = 0;
226   if(aCreationMethod == CREATION_METHOD_SIMPLE() ||
227       aCreationMethod == CREATION_METHOD_BINORMAL()) {
228     for(ListOfShape::const_iterator
229         anIter = aBaseShapesList.cbegin(); anIter != aBaseShapesList.cend(); anIter++) {
230       std::shared_ptr<GeomAPI_Shape> aBaseShape = *anIter;
231
232       GeomAlgoAPI_Pipe aPipeAlgo = aCreationMethod ==
233         CREATION_METHOD_SIMPLE() ? GeomAlgoAPI_Pipe(aBaseShape, aPathShape) :
234                                    GeomAlgoAPI_Pipe(aBaseShape, aPathShape, aBiNormal);
235
236       if(!aPipeAlgo.isDone()) {
237         setError("Error: Pipe algorithm failed.");
238         aResultIndex = 0;
239         break;
240       }
241
242       // Check if shape is valid
243       if(!aPipeAlgo.shape().get() || aPipeAlgo.shape()->isNull()) {
244         setError("Error: Resulting shape is Null.");
245         aResultIndex = 0;
246         break;
247       }
248       if(!aPipeAlgo.isValid()) {
249         setError("Error: Resulting shape is not valid.");
250         aResultIndex = 0;
251         break;
252       }
253
254       storeResult(aBaseShape, aPipeAlgo, aResultIndex++);
255     }
256   } else if(aCreationMethod == CREATION_METHOD_LOCATIONS()) {
257     GeomAlgoAPI_Pipe aPipeAlgo = GeomAlgoAPI_Pipe(aBaseShapesList, aLocations, aPathShape);
258
259     if(!aPipeAlgo.isDone()) {
260       setError("Error: Pipe algorithm failed.");
261       removeResults(0);
262       return;
263     }
264
265     // Check if shape is valid
266     if(!aPipeAlgo.shape().get() || aPipeAlgo.shape()->isNull()) {
267       setError("Error: Resulting shape is Null.");
268       removeResults(0);
269       return;
270     }
271     if(!aPipeAlgo.isValid()) {
272       setError("Error: Resulting shape is not valid.");
273       removeResults(0);
274       return;
275     }
276
277     storeResult(aBaseShapesList, aPipeAlgo, aResultIndex++);
278   } else {
279     setError("Error: Wrong creation method.");
280     return;
281   }
282
283   removeResults(aResultIndex);
284 }
285
286 //==================================================================================================
287 void FeaturesPlugin_Pipe::storeResult(const std::shared_ptr<GeomAPI_Shape> theBaseShape,
288                                       GeomAlgoAPI_Pipe& thePipeAlgo,
289                                       const int theResultIndex)
290 {
291   // Create result body.
292   ResultBodyPtr aResultBody = document()->createBody(data(), theResultIndex);
293
294   // Store generated shape.
295   aResultBody->storeGenerated(theBaseShape, thePipeAlgo.shape());
296
297   // Store generated edges/faces.
298   GeomAPI_Shape::ShapeType aBaseShapeType = theBaseShape->shapeType();
299   GeomAPI_Shape::ShapeType aShapeTypeToExplode;
300   int aGenTag = 1;
301   std::string aGenName = "Generated_";
302
303   std::shared_ptr<GeomAPI_DataMapOfShapeShape> aMapOfSubShapes = thePipeAlgo.mapOfSubShapes();
304   switch(aBaseShapeType) {
305     case GeomAPI_Shape::VERTEX: {
306       aShapeTypeToExplode = GeomAPI_Shape::VERTEX;
307       break;
308     }
309     case GeomAPI_Shape::EDGE:
310     case GeomAPI_Shape::WIRE: {
311       std::shared_ptr<GeomAPI_Vertex> aV1, aV2;
312       GeomAlgoAPI_ShapeTools::findBounds(theBaseShape, aV1, aV2);
313       ListOfShape aV1History, aV2History;
314       thePipeAlgo.generated(aV1, aV1History);
315       thePipeAlgo.generated(aV2, aV2History);
316       if(!aV1History.empty()) {
317         aResultBody->generated(aV1, aV1History.front(), aGenName + "Edge_1");
318       }
319       if(!aV2History.empty()) {
320         aResultBody->generated(aV2, aV2History.front(), aGenName + "Edge_2");
321       }
322     }
323     case GeomAPI_Shape::FACE:
324     case GeomAPI_Shape::SHELL: {
325       aShapeTypeToExplode = GeomAPI_Shape::EDGE;
326       break;
327     }
328     case GeomAPI_Shape::COMPOUND: {
329       aShapeTypeToExplode = GeomAPI_Shape::COMPOUND;
330     }
331   }
332
333   if(aShapeTypeToExplode == GeomAPI_Shape::VERTEX ||
334       aShapeTypeToExplode == GeomAPI_Shape::COMPOUND) {
335     aResultBody->loadAndOrientGeneratedShapes(&thePipeAlgo, theBaseShape, GeomAPI_Shape::VERTEX,
336                                            aGenTag++, aGenName + "Edge", *aMapOfSubShapes.get());
337   }
338   if(aShapeTypeToExplode == GeomAPI_Shape::EDGE ||
339       aShapeTypeToExplode == GeomAPI_Shape::COMPOUND) {
340     aResultBody->loadAndOrientGeneratedShapes(&thePipeAlgo, theBaseShape, GeomAPI_Shape::EDGE,
341                                            aGenTag++, aGenName + "Face", *aMapOfSubShapes.get());
342   }
343
344   // Store from shapes.
345   int aFromTag = aGenTag;
346   storeShapes(aResultBody, aBaseShapeType, aMapOfSubShapes,
347               thePipeAlgo.fromShapes(), "From_", aFromTag);
348
349   // Store to shapes.
350   int aToTag = aFromTag;
351   storeShapes(aResultBody, aBaseShapeType, aMapOfSubShapes, thePipeAlgo.toShapes(), "To_", aToTag);
352
353   setResult(aResultBody, theResultIndex);
354 }
355
356 //==================================================================================================
357 void FeaturesPlugin_Pipe::storeResult(const ListOfShape& theBaseShapes,
358                                       GeomAlgoAPI_Pipe& thePipeAlgo,
359                                       const int theResultIndex)
360 {
361   // Create result body.
362   ResultBodyPtr aResultBody = document()->createBody(data(), theResultIndex);
363
364   // Store generated shape.
365   aResultBody->storeGenerated(theBaseShapes.front(), thePipeAlgo.shape());
366
367   // Store generated edges/faces.
368   int aGenTag = 1;
369   std::shared_ptr<GeomAPI_DataMapOfShapeShape> aMapOfSubShapes = thePipeAlgo.mapOfSubShapes();
370
371   for(ListOfShape::const_iterator
372       anIter = theBaseShapes.cbegin(); anIter != theBaseShapes.cend(); anIter++) {
373     GeomShapePtr aBaseShape = *anIter;
374     GeomAPI_Shape::ShapeType aBaseShapeType = aBaseShape->shapeType();
375     GeomAPI_Shape::ShapeType aShapeTypeToExplode;
376     std::string aGenName = "Generated_";
377     switch(aBaseShapeType) {
378       case GeomAPI_Shape::VERTEX: {
379         aShapeTypeToExplode = GeomAPI_Shape::VERTEX;
380         aGenName += "Edge";
381         break;
382       }
383       case GeomAPI_Shape::EDGE:
384       case GeomAPI_Shape::WIRE: {
385         std::shared_ptr<GeomAPI_Vertex> aV1, aV2;
386         GeomAlgoAPI_ShapeTools::findBounds(aBaseShape, aV1, aV2);
387         ListOfShape aV1History, aV2History;
388         thePipeAlgo.generated(aV1, aV1History);
389         thePipeAlgo.generated(aV2, aV2History);
390         aResultBody->generated(aV1, aV1History.front(), aGenName + "Edge_1");
391         aResultBody->generated(aV2, aV2History.front(), aGenName + "Edge_2");
392       }
393       case GeomAPI_Shape::FACE:
394       case GeomAPI_Shape::SHELL: {
395         aShapeTypeToExplode = GeomAPI_Shape::EDGE;
396         aGenName += "Face";
397         break;
398       }
399     }
400     aResultBody->loadAndOrientGeneratedShapes(&thePipeAlgo, aBaseShape, aShapeTypeToExplode,
401                                               aGenTag++, aGenName, *aMapOfSubShapes.get());
402   }
403
404   // Store from shapes.
405   int aFromTag = aGenTag;
406   storeShapes(aResultBody, theBaseShapes.front()->shapeType(), aMapOfSubShapes,
407               thePipeAlgo.fromShapes(), "From", aFromTag);
408
409   // Store to shapes.
410   int aToTag = aFromTag;
411   storeShapes(aResultBody, theBaseShapes.back()->shapeType(),
412               aMapOfSubShapes, thePipeAlgo.toShapes(), "To", aToTag);
413
414
415   setResult(aResultBody, theResultIndex);
416 }
417
418 //==================================================================================================
419 void FeaturesPlugin_Pipe::storeShapes(ResultBodyPtr theResultBody,
420                               const GeomAPI_Shape::ShapeType theBaseShapeType,
421                               const std::shared_ptr<GeomAPI_DataMapOfShapeShape> theMapOfSubShapes,
422                               const ListOfShape& theShapes,
423                               const std::string theName,
424                               int& theTag)
425 {
426   GeomAPI_Shape::ShapeType aShapeTypeToExplore = GeomAPI_Shape::FACE;
427   std::string aShapeTypeStr = "Face";
428   switch(theBaseShapeType) {
429     case GeomAPI_Shape::VERTEX: {
430       aShapeTypeToExplore = GeomAPI_Shape::VERTEX;
431       aShapeTypeStr = "Vertex";
432       break;
433     }
434     case GeomAPI_Shape::EDGE:
435     case GeomAPI_Shape::WIRE: {
436       aShapeTypeToExplore = GeomAPI_Shape::EDGE;
437       aShapeTypeStr = "Edge";
438       break;
439     }
440     case GeomAPI_Shape::FACE:
441     case GeomAPI_Shape::SHELL: {
442       aShapeTypeToExplore = GeomAPI_Shape::FACE;
443       aShapeTypeStr = "Face";
444       break;
445     }
446     case GeomAPI_Shape::COMPOUND: {
447       aShapeTypeToExplore = GeomAPI_Shape::COMPOUND;
448       break;
449     }
450   }
451
452   // Store shapes.
453   int aShapeIndex = 1;
454   int aFaceIndex = 1;
455   for(ListOfShape::const_iterator anIt = theShapes.cbegin(); anIt != theShapes.cend(); ++anIt) {
456     GeomShapePtr aShape = *anIt;
457
458     if(aShapeTypeToExplore == GeomAPI_Shape::COMPOUND) {
459       std::string aName = theName + (aShape->shapeType() == GeomAPI_Shape::EDGE ? "Edge" : "Face");
460       storeSubShape(theResultBody,
461                     aShape,
462                     aShape->shapeType(),
463                     theMapOfSubShapes,
464                     aName,
465                     aShape->shapeType() == GeomAPI_Shape::EDGE ? aShapeIndex : aFaceIndex);
466     } else {
467       std::string aName = theName + aShapeTypeStr;
468       storeSubShape(theResultBody, aShape, aShapeTypeToExplore,
469                     theMapOfSubShapes, aName, aShapeIndex);
470     }
471   }
472 }
473
474 //==================================================================================================
475 void storeSubShape(ResultBodyPtr theResultBody,
476                    const GeomShapePtr theShape,
477                    const GeomAPI_Shape::ShapeType theType,
478                    const std::shared_ptr<GeomAPI_DataMapOfShapeShape> theMapOfSubShapes,
479                    const std::string theName,
480                    int& theShapeIndex)
481 {
482   for(GeomAPI_ShapeExplorer anExp(theShape, theType); anExp.more(); anExp.next()) {
483     GeomShapePtr aSubShape = anExp.current();
484     if(theMapOfSubShapes->isBound(aSubShape)) {
485       aSubShape = theMapOfSubShapes->find(aSubShape);
486     }
487     std::ostringstream aStr;
488     aStr << theName << "_" << theShapeIndex++;
489     theResultBody->generated(aSubShape, aStr.str());
490   }
491 }