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