Salome HOME
689e0d39b9f8076745f2bfe075dde2dcab6075b9
[modules/shaper.git] / src / FeaturesPlugin / FeaturesPlugin_CompositeSketch.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 email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
18 //
19
20 #include <FeaturesPlugin_CompositeSketch.h>
21
22 #include <ModelAPI_AttributeSelectionList.h>
23 #include <ModelAPI_AttributeReference.h>
24 #include <ModelAPI_BodyBuilder.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_Prism.h>
31 #include <GeomAlgoAPI_Revolution.h>
32 #include <GeomAlgoAPI_ShapeTools.h>
33 #include <GeomAlgoAPI_SketchBuilder.h>
34
35 #include <GeomAPI_PlanarEdges.h>
36 #include <GeomAPI_ShapeExplorer.h>
37
38 #include <map>
39 #include <sstream>
40
41 static void storeSubShape(ResultBodyPtr theResultBody,
42                           const GeomShapePtr theShape,
43                           const GeomAPI_Shape::ShapeType theType,
44                           const std::shared_ptr<GeomAPI_DataMapOfShapeShape> theMapOfSubShapes,
45                           const std::string theName,
46                           int& theShapeIndex,
47                           int& theTag);
48
49 //=================================================================================================
50 void FeaturesPlugin_CompositeSketch::initCompositeSketchAttribtues(const int theInitFlags)
51 {
52   // Initialize sketch launcher.
53   if(theInitFlags & InitSketchLauncher) {
54     data()->addAttribute(SKETCH_ID(), ModelAPI_AttributeReference::typeId());
55     ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), SKETCH_ID());
56   }
57
58   // Initialize selection list.
59   if(theInitFlags & InitBaseObjectsList) {
60     data()->addAttribute(BASE_OBJECTS_ID(), ModelAPI_AttributeSelectionList::typeId());
61   }
62 }
63
64 //=================================================================================================
65 std::shared_ptr<ModelAPI_Feature> FeaturesPlugin_CompositeSketch::addFeature(std::string theID)
66 {
67   FeaturePtr aNew = document()->addFeature(theID, false);
68   if(aNew) {
69     data()->reference(SKETCH_ID())->setValue(aNew);
70   }
71
72   // Set as current also after it becomes sub to set correctly enabled for other sketch subs.
73   document()->setCurrentFeature(aNew, false);
74   return aNew;
75 }
76
77 //=================================================================================================
78 int FeaturesPlugin_CompositeSketch::numberOfSubs(bool forTree) const
79 {
80   ObjectPtr aObj = data()->reference(SKETCH_ID())->value();
81   return aObj.get() ? 1 : 0;
82 }
83
84 //=================================================================================================
85 std::shared_ptr<ModelAPI_Feature> FeaturesPlugin_CompositeSketch::subFeature(const int theIndex,
86                                                                              bool forTree)
87 {
88   if(theIndex == 0) {
89     return std::dynamic_pointer_cast<ModelAPI_Feature>(data()->reference(SKETCH_ID())->value());
90   }
91
92   return std::shared_ptr<ModelAPI_Feature>();
93 }
94
95 //=================================================================================================
96 int FeaturesPlugin_CompositeSketch::subFeatureId(const int theIndex) const
97 {
98   if(theIndex == 0) {
99     FeaturePtr aFeature =
100       std::dynamic_pointer_cast<ModelAPI_Feature>(data()->reference(SKETCH_ID())->value());
101     if(aFeature.get()) {
102       return aFeature->data()->featureId();
103     }
104   }
105
106   return -1;
107 }
108
109 //=================================================================================================
110 bool FeaturesPlugin_CompositeSketch::isSub(ObjectPtr theObject) const
111 {
112   // Check is this feature of result
113   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theObject);
114   if(!aFeature.get()) {
115     return false;
116   }
117
118   ObjectPtr aSub = data()->reference(SKETCH_ID())->value();
119   return aSub == theObject;
120 }
121
122 //=================================================================================================
123 void FeaturesPlugin_CompositeSketch::removeFeature(std::shared_ptr<ModelAPI_Feature> theFeature)
124 {
125   AttributeSelectionListPtr aBaseObjectsSelectionList = selectionList(BASE_OBJECTS_ID());
126   if(aBaseObjectsSelectionList.get() && aBaseObjectsSelectionList->size() > 0) {
127     aBaseObjectsSelectionList->clear();
128   }
129
130   reference(SKETCH_ID())->setValue(ObjectPtr());
131 }
132
133 //=================================================================================================
134 void FeaturesPlugin_CompositeSketch::getBaseShapes(ListOfShape& theBaseShapesList,
135                                                    const bool theIsMakeShells)
136 {
137   theBaseShapesList.clear();
138
139   ListOfShape aBaseFacesList;
140   std::map<ResultConstructionPtr, ListOfShape> aSketchWiresMap;
141   AttributeSelectionListPtr aBaseObjectsSelectionList = selectionList(BASE_OBJECTS_ID());
142   if(!aBaseObjectsSelectionList.get()) {
143     setError("Error: Could not get base objects selection list.");
144     return;
145   }
146   if(aBaseObjectsSelectionList->size() == 0) {
147     setError("Error: Base objects list is empty.");
148     return;
149   }
150   for(int anIndex = 0; anIndex < aBaseObjectsSelectionList->size(); anIndex++) {
151     AttributeSelectionPtr aBaseObjectSelection = aBaseObjectsSelectionList->value(anIndex);
152     if(!aBaseObjectSelection.get()) {
153       setError("Error: Selected base object is empty.");
154       return;
155     }
156     GeomShapePtr aBaseShape = aBaseObjectSelection->value();
157     if(aBaseShape.get() && !aBaseShape->isNull()) {
158       GeomAPI_Shape::ShapeType aST = aBaseShape->shapeType();
159       if(aST == GeomAPI_Shape::SOLID || aST == GeomAPI_Shape::COMPSOLID) {
160         setError("Error: Selected shapes has unsupported type.");
161         return;
162       }
163       ResultConstructionPtr aConstruction =
164         std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aBaseObjectSelection->context());
165       if(aConstruction.get() && !aBaseShape->isEqual(aConstruction->shape()) &&
166           aST == GeomAPI_Shape::WIRE) {
167         // It is a wire on the sketch, store it to make face later.
168         aSketchWiresMap[aConstruction].push_back(aBaseShape);
169         continue;
170       } else {
171       aST == GeomAPI_Shape::FACE ? aBaseFacesList.push_back(aBaseShape) :
172                                    theBaseShapesList.push_back(aBaseShape);
173       }
174     } else {
175       // This may be the whole sketch result selected, check and get faces.
176       ResultConstructionPtr aConstruction =
177         std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aBaseObjectSelection->context());
178       if(!aConstruction.get()) {
179         setError("Error: Selected sketches does not have results.");
180         return;
181       }
182       int aFacesNum = aConstruction->facesNum();
183       if(aFacesNum == 0) {
184         // Probably it can be construction.
185         aBaseShape = aConstruction->shape();
186         if(aBaseShape.get() && !aBaseShape->isNull()) {
187           GeomAPI_Shape::ShapeType aST = aBaseShape->shapeType();
188           if(aST != GeomAPI_Shape::VERTEX && aST != GeomAPI_Shape::EDGE &&
189              aST != GeomAPI_Shape::WIRE &&
190              aST != GeomAPI_Shape::FACE && aST != GeomAPI_Shape::SHELL) {
191             setError("Error: Selected shapes has unsupported type.");
192             return;
193           }
194           aST == GeomAPI_Shape::FACE ? aBaseFacesList.push_back(aBaseShape) :
195                                        theBaseShapesList.push_back(aBaseShape);
196         }
197       } else {
198         for(int aFaceIndex = 0; aFaceIndex < aFacesNum; aFaceIndex++) {
199           GeomShapePtr aBaseFace = aConstruction->face(aFaceIndex);
200           if(!aBaseFace.get() || aBaseFace->isNull()) {
201             setError("Error: One of the faces on selected sketch is null.");
202             return;
203           }
204           aBaseFacesList.push_back(aBaseFace);
205         }
206       }
207     }
208   }
209
210   // Make faces from sketch wires.
211   for(std::map<ResultConstructionPtr, ListOfShape>::const_iterator anIt = aSketchWiresMap.cbegin();
212       anIt != aSketchWiresMap.cend(); ++anIt) {
213     const std::shared_ptr<GeomAPI_PlanarEdges> aSketchPlanarEdges =
214       std::dynamic_pointer_cast<GeomAPI_PlanarEdges>((*anIt).first->shape());
215     const ListOfShape& aWiresList = (*anIt).second;
216     ListOfShape aFaces;
217     GeomAlgoAPI_ShapeTools::makeFacesWithHoles(aSketchPlanarEdges->origin(),
218                                                aSketchPlanarEdges->norm(),
219                                                aWiresList,
220                                                aFaces);
221     aBaseFacesList.insert(aBaseFacesList.end(), aFaces.begin(), aFaces.end());
222   }
223
224   // Searching faces with common edges.
225   if(theIsMakeShells && aBaseFacesList.size() > 1) {
226     ListOfShape aShells;
227     ListOfShape aFreeFaces;
228     GeomShapePtr aFacesCompound = GeomAlgoAPI_CompoundBuilder::compound(aBaseFacesList);
229     GeomAlgoAPI_ShapeTools::combineShapes(aFacesCompound, GeomAPI_Shape::SHELL,
230                                           aShells, aFreeFaces);
231     theBaseShapesList.insert(theBaseShapesList.end(), aFreeFaces.begin(), aFreeFaces.end());
232     theBaseShapesList.insert(theBaseShapesList.end(), aShells.begin(), aShells.end());
233   } else {
234     theBaseShapesList.insert(theBaseShapesList.end(), aBaseFacesList.begin(),
235                              aBaseFacesList.end());
236   }
237 }
238
239 //=================================================================================================
240 bool FeaturesPlugin_CompositeSketch::isMakeShapeValid(
241   const std::shared_ptr<GeomAlgoAPI_MakeShape> theMakeShape)
242 {
243   // Check that algo is done.
244   if(!theMakeShape->isDone()) {
245     setError("Error: " + getKind() + " algorithm failed.");
246     return false;
247   }
248
249   // Check if shape is not null.
250   if(!theMakeShape->shape().get() || theMakeShape->shape()->isNull()) {
251     setError("Error: Resulting shape is null.");
252     return false;
253   }
254
255   // Check that resulting shape is valid.
256   if(!theMakeShape->isValid()) {
257     setError("Error: Resulting shape is not valid.");
258     return false;
259   }
260
261   return true;
262 }
263
264 //=================================================================================================
265 void FeaturesPlugin_CompositeSketch::storeResult(const GeomShapePtr theBaseShape,
266                                         const std::shared_ptr<GeomAlgoAPI_MakeShape> theMakeShape,
267                                         const int theIndex)
268 {
269   // Create result body.
270   ResultBodyPtr aResultBody = document()->createBody(data(), theIndex);
271
272   // Store generated shape.
273   aResultBody->storeGenerated(theBaseShape, theMakeShape->shape());
274
275   // Store generated edges/faces.
276   int aGenTag = 1;
277   storeGenerationHistory(aResultBody, theBaseShape, theMakeShape, aGenTag);
278
279   setResult(aResultBody, theIndex);
280 }
281
282 //=================================================================================================
283 void FeaturesPlugin_CompositeSketch::storeGenerationHistory(ResultBodyPtr theResultBody,
284                                         const GeomShapePtr theBaseShape,
285                                         const std::shared_ptr<GeomAlgoAPI_MakeShape> theMakeShape,
286                                         int& theTag)
287 {
288   GeomAPI_Shape::ShapeType aBaseShapeType = theBaseShape->shapeType();
289   GeomAPI_Shape::ShapeType aShapeTypeToExplode = GeomAPI_Shape::SHAPE;
290   std::string aGenName = "Generated_";
291
292   std::shared_ptr<GeomAPI_DataMapOfShapeShape> aMapOfSubShapes = theMakeShape->mapOfSubShapes();
293   switch(aBaseShapeType) {
294     case GeomAPI_Shape::EDGE: {
295             aShapeTypeToExplode = GeomAPI_Shape::VERTEX;
296       break;
297     }
298     case GeomAPI_Shape::WIRE: {
299       //std::shared_ptr<GeomAPI_Vertex> aV1, aV2;
300       //GeomAlgoAPI_ShapeTools::findBounds(theBaseShape, aV1, aV2);
301       //ListOfShape aV1History, aV2History;
302       //theMakeShape->generated(aV1, aV1History);
303       //theMakeShape->generated(aV2, aV2History);
304       //if(!aV1History.empty()) {
305       //  theResultBody->generated(aV1, aV1History.front(), aGenName + "Edge_1", theTag++);
306       //}
307       //if(!aV2History.empty()) {
308       //  theResultBody->generated(aV2, aV2History.front(), aGenName + "Edge_2", theTag++);
309       //}
310       aShapeTypeToExplode = GeomAPI_Shape::COMPOUND;
311       break;
312     }
313     case GeomAPI_Shape::FACE:
314     case GeomAPI_Shape::SHELL: {
315       aShapeTypeToExplode = GeomAPI_Shape::EDGE;
316       break;
317     }
318     case GeomAPI_Shape::COMPOUND: {
319       aShapeTypeToExplode = GeomAPI_Shape::COMPOUND;
320     }
321   }
322
323   if(aShapeTypeToExplode == GeomAPI_Shape::VERTEX ||
324       aShapeTypeToExplode == GeomAPI_Shape::COMPOUND) {
325     theResultBody->loadAndOrientGeneratedShapes(theMakeShape.get(), theBaseShape,
326                                                 GeomAPI_Shape::VERTEX,
327                                                 theTag++, aGenName + "Edge",
328                                                 *aMapOfSubShapes.get());
329   }
330   if(aShapeTypeToExplode == GeomAPI_Shape::EDGE ||
331       aShapeTypeToExplode == GeomAPI_Shape::COMPOUND) {
332     theResultBody->loadAndOrientGeneratedShapes(theMakeShape.get(),
333                                                 theBaseShape, GeomAPI_Shape::EDGE,
334                                                 theTag++, aGenName + "Face",
335                                                 *aMapOfSubShapes.get());
336   }
337
338   std::shared_ptr<GeomAlgoAPI_MakeSweep> aMakeSweep =
339     std::dynamic_pointer_cast<GeomAlgoAPI_MakeSweep>(theMakeShape);
340   if(aMakeSweep.get()) {
341     // Store from shapes.
342     storeShapes(theResultBody, aBaseShapeType, aMapOfSubShapes,
343                 aMakeSweep->fromShapes(), "From_", theTag);
344
345     // Store to shapes.
346     storeShapes(theResultBody, aBaseShapeType, aMapOfSubShapes,
347                 aMakeSweep->toShapes(), "To_", theTag);
348   }
349 }
350
351 //=================================================================================================
352 void FeaturesPlugin_CompositeSketch::storeShapes(ResultBodyPtr theResultBody,
353                               const GeomAPI_Shape::ShapeType theBaseShapeType,
354                               const std::shared_ptr<GeomAPI_DataMapOfShapeShape> theMapOfSubShapes,
355                               const ListOfShape& theShapes,
356                               const std::string theName,
357                               int& theTag)
358 {
359   GeomAPI_Shape::ShapeType aShapeTypeToExplore = GeomAPI_Shape::FACE;
360   std::string aShapeTypeStr = "Face";
361   switch(theBaseShapeType) {
362     case GeomAPI_Shape::VERTEX: {
363       aShapeTypeToExplore = GeomAPI_Shape::VERTEX;
364       aShapeTypeStr = "Vertex";
365       break;
366     }
367     case GeomAPI_Shape::EDGE:
368     case GeomAPI_Shape::WIRE: {
369       aShapeTypeToExplore = GeomAPI_Shape::EDGE;
370       aShapeTypeStr = "Edge";
371       break;
372     }
373     case GeomAPI_Shape::FACE:
374     case GeomAPI_Shape::SHELL: {
375       aShapeTypeToExplore = GeomAPI_Shape::FACE;
376       aShapeTypeStr = "Face";
377       break;
378     }
379     case GeomAPI_Shape::COMPOUND: {
380       aShapeTypeToExplore = GeomAPI_Shape::COMPOUND;
381       break;
382     }
383   }
384
385   // Store shapes.
386   int aShapeIndex = 1;
387   int aFaceIndex = 1;
388   for(ListOfShape::const_iterator anIt = theShapes.cbegin(); anIt != theShapes.cend(); ++anIt) {
389     GeomShapePtr aShape = *anIt;
390
391     if(aShapeTypeToExplore == GeomAPI_Shape::COMPOUND) {
392       std::string aName = theName + (aShape->shapeType() == GeomAPI_Shape::EDGE ? "Edge" : "Face");
393       storeSubShape(theResultBody,
394                     aShape,
395                     aShape->shapeType(),
396                     theMapOfSubShapes,
397                     aName,
398                     aShape->shapeType() == GeomAPI_Shape::EDGE ? aShapeIndex : aFaceIndex,
399                     theTag);
400     } else {
401       std::string aName = theName + aShapeTypeStr;
402       storeSubShape(theResultBody, aShape, aShapeTypeToExplore,
403                     theMapOfSubShapes, aName, aShapeIndex, theTag);
404     }
405   }
406 }
407
408 void storeSubShape(ResultBodyPtr theResultBody,
409                    const GeomShapePtr theShape,
410                    const GeomAPI_Shape::ShapeType theType,
411                    const std::shared_ptr<GeomAPI_DataMapOfShapeShape> theMapOfSubShapes,
412                    const std::string theName,
413                    int& theShapeIndex,
414                    int& theTag)
415 {
416   for(GeomAPI_ShapeExplorer anExp(theShape, theType); anExp.more(); anExp.next()) {
417     GeomShapePtr aSubShape = anExp.current();
418     if(theMapOfSubShapes->isBound(aSubShape)) {
419       aSubShape = theMapOfSubShapes->find(aSubShape);
420     }
421     std::ostringstream aStr;
422     aStr << theName << "_" << theShapeIndex++;
423     theResultBody->generated(aSubShape, aStr.str(), theTag++);
424   }
425 }