Salome HOME
Update copyrights
[modules/shaper.git] / src / FeaturesPlugin / FeaturesPlugin_Pipe.cpp
1 // Copyright (C) 2014-2019  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, 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, 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<GeomAlgoAPI_Pipe> thePipeAlgo,
266                                       const int theResultIndex)
267 {
268   // Create result body.
269   ResultBodyPtr aResultBody = document()->createBody(data(), theResultIndex);
270
271   // Store generated shape.
272   aResultBody->storeGenerated(theBaseShape, thePipeAlgo->shape());
273
274   // Store generated edges/faces.
275   GeomAPI_Shape::ShapeType aBaseShapeType = theBaseShape->shapeType();
276   GeomAPI_Shape::ShapeType aShapeTypeToExplode;
277
278   switch(aBaseShapeType) {
279     case GeomAPI_Shape::VERTEX: {
280       aShapeTypeToExplode = GeomAPI_Shape::VERTEX;
281       break;
282     }
283     case GeomAPI_Shape::EDGE:
284     case GeomAPI_Shape::WIRE: {
285       std::shared_ptr<GeomAPI_Vertex> aV1, aV2;
286       GeomAlgoAPI_ShapeTools::findBounds(theBaseShape, aV1, aV2);
287       ListOfShape aV1History, aV2History;
288       thePipeAlgo->generated(aV1, aV1History);
289       thePipeAlgo->generated(aV2, aV2History);
290       if(!aV1History.empty()) {
291         aResultBody->generated(aV1, aV1History.front());
292       }
293       if(!aV2History.empty()) {
294         aResultBody->generated(aV2, aV2History.front());
295       }
296     }
297     case GeomAPI_Shape::FACE:
298     case GeomAPI_Shape::SHELL: {
299       aShapeTypeToExplode = GeomAPI_Shape::EDGE;
300       break;
301     }
302     case GeomAPI_Shape::COMPOUND: {
303       aShapeTypeToExplode = GeomAPI_Shape::COMPOUND;
304     }
305   }
306
307   if(aShapeTypeToExplode == GeomAPI_Shape::VERTEX ||
308       aShapeTypeToExplode == GeomAPI_Shape::COMPOUND) {
309     aResultBody->loadGeneratedShapes(thePipeAlgo, theBaseShape, GeomAPI_Shape::VERTEX);
310   }
311   if(aShapeTypeToExplode == GeomAPI_Shape::EDGE ||
312       aShapeTypeToExplode == GeomAPI_Shape::COMPOUND) {
313     aResultBody->loadGeneratedShapes(thePipeAlgo, theBaseShape, GeomAPI_Shape::EDGE);
314   }
315
316   // Store from shapes.
317   storeShapes(aResultBody, aBaseShapeType, thePipeAlgo->fromShapes(), "From_");
318
319   // Store to shapes.
320   storeShapes(aResultBody, aBaseShapeType, thePipeAlgo->toShapes(), "To_");
321
322   setResult(aResultBody, theResultIndex);
323 }
324
325 //==================================================================================================
326 void FeaturesPlugin_Pipe::storeResult(const ListOfShape& theBaseShapes,
327                                       const std::shared_ptr<GeomAlgoAPI_Pipe> thePipeAlgo,
328                                       const int theResultIndex)
329 {
330   // Create result body.
331   ResultBodyPtr aResultBody = document()->createBody(data(), theResultIndex);
332
333   // Store generated shape.
334   aResultBody->storeGenerated(theBaseShapes.front(), thePipeAlgo->shape());
335
336   // Store generated edges/faces.
337   for(ListOfShape::const_iterator anIter = theBaseShapes.cbegin();
338       anIter != theBaseShapes.cend();
339       ++anIter)
340   {
341     GeomShapePtr aBaseShape = *anIter;
342     GeomAPI_Shape::ShapeType aBaseShapeType = aBaseShape->shapeType();
343     GeomAPI_Shape::ShapeType aShapeTypeToExplode;
344     switch(aBaseShapeType) {
345       case GeomAPI_Shape::VERTEX: {
346         aShapeTypeToExplode = GeomAPI_Shape::VERTEX;
347         break;
348       }
349       case GeomAPI_Shape::EDGE:
350       case GeomAPI_Shape::WIRE: {
351         std::shared_ptr<GeomAPI_Vertex> aV1, aV2;
352         GeomAlgoAPI_ShapeTools::findBounds(aBaseShape, aV1, aV2);
353         ListOfShape aV1History, aV2History;
354         thePipeAlgo->generated(aV1, aV1History);
355         thePipeAlgo->generated(aV2, aV2History);
356         aResultBody->generated(aV1, aV1History.front());
357         aResultBody->generated(aV2, aV2History.front());
358       }
359       case GeomAPI_Shape::FACE:
360       case GeomAPI_Shape::SHELL: {
361         aShapeTypeToExplode = GeomAPI_Shape::EDGE;
362         break;
363       }
364     }
365     aResultBody->loadGeneratedShapes(thePipeAlgo, aBaseShape, aShapeTypeToExplode);
366   }
367
368   // Store from shapes.
369   storeShapes(aResultBody, theBaseShapes.front()->shapeType(), thePipeAlgo->fromShapes(), "From_");
370
371   // Store to shapes.
372   storeShapes(aResultBody, theBaseShapes.back()->shapeType(), thePipeAlgo->toShapes(), "To_");
373
374
375   setResult(aResultBody, theResultIndex);
376 }
377
378 //==================================================================================================
379 void FeaturesPlugin_Pipe::storeShapes(ResultBodyPtr theResultBody,
380                                       const GeomAPI_Shape::ShapeType theBaseShapeType,
381                                       const ListOfShape& theShapes,
382                                       const std::string theName)
383 {
384   GeomAPI_Shape::ShapeType aShapeTypeToExplore = GeomAPI_Shape::FACE;
385   std::string aShapeTypeStr = "Face";
386   switch(theBaseShapeType) {
387     case GeomAPI_Shape::VERTEX: {
388       aShapeTypeToExplore = GeomAPI_Shape::VERTEX;
389       aShapeTypeStr = "Vertex";
390       break;
391     }
392     case GeomAPI_Shape::EDGE:
393     case GeomAPI_Shape::WIRE: {
394       aShapeTypeToExplore = GeomAPI_Shape::EDGE;
395       aShapeTypeStr = "Edge";
396       break;
397     }
398     case GeomAPI_Shape::FACE:
399     case GeomAPI_Shape::SHELL: {
400       aShapeTypeToExplore = GeomAPI_Shape::FACE;
401       aShapeTypeStr = "Face";
402       break;
403     }
404     case GeomAPI_Shape::COMPOUND: {
405       aShapeTypeToExplore = GeomAPI_Shape::COMPOUND;
406       break;
407     }
408   }
409
410   // Store shapes.
411   int aShapeIndex = 1;
412   int aFaceIndex = 1;
413   for(ListOfShape::const_iterator anIt = theShapes.cbegin(); anIt != theShapes.cend(); ++anIt) {
414     GeomShapePtr aShape = *anIt;
415
416     if(aShapeTypeToExplore == GeomAPI_Shape::COMPOUND) {
417       std::string aName = theName + (aShape->shapeType() == GeomAPI_Shape::EDGE ? "Edge" : "Face");
418       storeSubShape(theResultBody, aShape,
419                     aShape->shapeType(),
420                     aName,
421                     aShape->shapeType() == GeomAPI_Shape::EDGE ? aShapeIndex : aFaceIndex);
422     } else {
423       std::string aName = theName + aShapeTypeStr;
424       storeSubShape(theResultBody, aShape, aShapeTypeToExplore, aName, aShapeIndex);
425     }
426   }
427 }
428
429 //==================================================================================================
430 void storeSubShape(ResultBodyPtr theResultBody,
431                    const GeomShapePtr theShape,
432                    const GeomAPI_Shape::ShapeType theType,
433                    const std::string theName,
434                    int& theShapeIndex)
435 {
436   for(GeomAPI_ShapeExplorer anExp(theShape, theType); anExp.more(); anExp.next()) {
437     GeomShapePtr aSubShape = anExp.current();
438     std::ostringstream aStr;
439     aStr << theName << "_" << theShapeIndex++;
440     theResultBody->generated(aSubShape, aStr.str());
441   }
442 }