Salome HOME
Merge branch 'BR_EDF_2018_Lot1'
[modules/shaper.git] / src / FeaturesPlugin / FeaturesPlugin_Symmetry.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_Symmetry.h>
22
23 #include <GeomAlgoAPI_CompoundBuilder.h>
24 #include <GeomAlgoAPI_PointBuilder.h>
25 #include <GeomAlgoAPI_FaceBuilder.h>
26
27 #include <GeomAPI_Edge.h>
28 #include <GeomAPI_Face.h>
29 #include <GeomAPI_Lin.h>
30 #include <GeomAPI_Pln.h>
31 #include <GeomAPI_Trsf.h>
32
33 #include <ModelAPI_AttributeBoolean.h>
34 #include <ModelAPI_AttributeSelectionList.h>
35 #include <ModelAPI_AttributeString.h>
36 #include <ModelAPI_ResultBody.h>
37 #include <ModelAPI_ResultPart.h>
38
39 #include <FeaturesPlugin_Tools.h>
40
41 //=================================================================================================
42 FeaturesPlugin_Symmetry::FeaturesPlugin_Symmetry()
43 {
44 }
45
46 //=================================================================================================
47 void FeaturesPlugin_Symmetry::initAttributes()
48 {
49   data()->addAttribute(FeaturesPlugin_Symmetry::CREATION_METHOD(),
50                        ModelAPI_AttributeString::typeId());
51
52   AttributeSelectionListPtr aSelection =
53     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(data()->addAttribute(
54     FeaturesPlugin_Symmetry::OBJECTS_LIST_ID(), ModelAPI_AttributeSelectionList::typeId()));
55
56   data()->addAttribute(FeaturesPlugin_Symmetry::POINT_OBJECT_ID(),
57                        ModelAPI_AttributeSelection::typeId());
58
59   data()->addAttribute(FeaturesPlugin_Symmetry::AXIS_OBJECT_ID(),
60                        ModelAPI_AttributeSelection::typeId());
61
62   data()->addAttribute(FeaturesPlugin_Symmetry::PLANE_OBJECT_ID(),
63                        ModelAPI_AttributeSelection::typeId());
64
65   data()->addAttribute(FeaturesPlugin_Symmetry::KEEP_ORIGINAL_RESULT(),
66                        ModelAPI_AttributeBoolean::typeId());
67 }
68
69 //=================================================================================================
70 void FeaturesPlugin_Symmetry::execute()
71 {
72   AttributeStringPtr aMethodTypeAttr = string(FeaturesPlugin_Symmetry::CREATION_METHOD());
73   std::string aMethodType = aMethodTypeAttr->value();
74
75   if (aMethodType == CREATION_METHOD_BY_POINT()) {
76     performSymmetryByPoint();
77   }
78
79   if (aMethodType == CREATION_METHOD_BY_AXIS()) {
80     performSymmetryByAxis();
81   }
82
83   if (aMethodType == CREATION_METHOD_BY_PLANE()) {
84     performSymmetryByPlane();
85   }
86 }
87
88 //=================================================================================================
89 bool FeaturesPlugin_Symmetry::collectSourceObjects(ListOfShape& theSourceShapes,
90                                                    std::list<ResultPtr>& theSourceResults)
91 {
92   AttributeSelectionListPtr anObjectsSelList =
93     selectionList(FeaturesPlugin_Symmetry::OBJECTS_LIST_ID());
94   if (anObjectsSelList->size() == 0) {
95     return false;
96   }
97   for (int anObjectsIndex = 0; anObjectsIndex < anObjectsSelList->size(); anObjectsIndex++) {
98     std::shared_ptr<ModelAPI_AttributeSelection> anObjectAttr =
99       anObjectsSelList->value(anObjectsIndex);
100     std::shared_ptr<GeomAPI_Shape> anObject = anObjectAttr->value();
101     if (!anObject.get()) { // may be for not-activated parts
102       eraseResults();
103       return false;
104     }
105     theSourceShapes.push_back(anObject);
106     theSourceResults.push_back(anObjectAttr->context());
107   }
108   return true;
109 }
110
111 //=================================================================================================
112 void FeaturesPlugin_Symmetry::performSymmetryByPoint()
113 {
114   // Getting objects.
115   ListOfShape anObjects;
116   std::list<ResultPtr> aContextes;
117   if (!collectSourceObjects(anObjects, aContextes))
118     return;
119
120   //Getting point.
121   std::shared_ptr<GeomAPI_Pnt> aPoint;
122   std::shared_ptr<ModelAPI_AttributeSelection> anObjRef =
123     selection(FeaturesPlugin_Symmetry::POINT_OBJECT_ID());
124   if (anObjRef.get() != NULL) {
125     GeomShapePtr aShape1 = anObjRef->value();
126     if (!aShape1.get()) {
127       aShape1 = anObjRef->context()->shape();
128     }
129     if (aShape1) {
130       aPoint = GeomAlgoAPI_PointBuilder::point(aShape1);
131     }
132   }
133
134   // Moving each object.
135   int aResultIndex = 0;
136   std::list<ResultPtr>::iterator aContext = aContextes.begin();
137   for(ListOfShape::iterator anObjectsIt = anObjects.begin(); anObjectsIt != anObjects.end();
138         anObjectsIt++, aContext++) {
139     std::shared_ptr<GeomAPI_Shape> aBaseShape = *anObjectsIt;
140     bool isPart = (*aContext)->groupName() == ModelAPI_ResultPart::group();
141
142     // Setting result.
143     if (isPart) {
144       std::shared_ptr<GeomAPI_Trsf> aTrsf(new GeomAPI_Trsf());
145       aTrsf->setSymmetry(aPoint);
146       ResultPartPtr anOrigin = std::dynamic_pointer_cast<ModelAPI_ResultPart>(*aContext);
147       buildResult(anOrigin, aTrsf, aResultIndex);
148     }
149     else {
150       GeomAlgoAPI_Symmetry aSymmetryAlgo(aBaseShape, aPoint);
151
152       if (!aSymmetryAlgo.check()) {
153         setError(aSymmetryAlgo.getError());
154         return;
155       }
156
157       aSymmetryAlgo.build();
158
159       // Checking that the algorithm worked properly.
160       if(!aSymmetryAlgo.isDone()) {
161         static const std::string aFeatureError = "Error: Symmetry algorithm failed.";
162         setError(aFeatureError);
163         break;
164       }
165       if(aSymmetryAlgo.shape()->isNull()) {
166         static const std::string aShapeError = "Error: Resulting shape is Null.";
167         setError(aShapeError);
168         break;
169       }
170       if(!aSymmetryAlgo.isValid()) {
171         std::string aFeatureError = "Error: Resulting shape is not valid.";
172         setError(aFeatureError);
173         break;
174       }
175
176       buildResult(aSymmetryAlgo, aBaseShape, aResultIndex);
177     }
178     aResultIndex++;
179   }
180
181   // Remove the rest results if there were produced in the previous pass.
182   removeResults(aResultIndex);
183 }
184
185 //=================================================================================================
186 void FeaturesPlugin_Symmetry::performSymmetryByAxis()
187 {
188   // Getting objects.
189   ListOfShape anObjects;
190   std::list<ResultPtr> aContextes;
191   if (!collectSourceObjects(anObjects, aContextes))
192     return;
193
194   //Getting axis.
195   std::shared_ptr<GeomAPI_Ax1> anAxis;
196   std::shared_ptr<GeomAPI_Edge> anEdge;
197   std::shared_ptr<ModelAPI_AttributeSelection> anObjRef =
198     selection(FeaturesPlugin_Symmetry::AXIS_OBJECT_ID());
199   if(anObjRef && anObjRef->value() && anObjRef->value()->isEdge()) {
200     anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(anObjRef->value()));
201   } else if (anObjRef && !anObjRef->value() && anObjRef->context() &&
202              anObjRef->context()->shape() && anObjRef->context()->shape()->isEdge()) {
203     anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(anObjRef->context()->shape()));
204   }
205   if(anEdge) {
206     anAxis = std::shared_ptr<GeomAPI_Ax1>(new GeomAPI_Ax1(anEdge->line()->location(),
207                                                           anEdge->line()->direction()));
208   }
209
210   // Moving each object.
211   int aResultIndex = 0;
212   std::list<ResultPtr>::iterator aContext = aContextes.begin();
213   for(ListOfShape::iterator anObjectsIt = anObjects.begin(); anObjectsIt != anObjects.end();
214         anObjectsIt++, aContext++) {
215     std::shared_ptr<GeomAPI_Shape> aBaseShape = *anObjectsIt;
216     bool isPart = (*aContext)->groupName() == ModelAPI_ResultPart::group();
217
218     // Setting result.
219     if (isPart) {
220       std::shared_ptr<GeomAPI_Trsf> aTrsf(new GeomAPI_Trsf());
221       aTrsf->setSymmetry(anAxis);
222       ResultPartPtr anOrigin = std::dynamic_pointer_cast<ModelAPI_ResultPart>(*aContext);
223       buildResult(anOrigin, aTrsf, aResultIndex);
224     }
225     else {
226       GeomAlgoAPI_Symmetry aSymmetryAlgo(aBaseShape, anAxis);
227
228       if (!aSymmetryAlgo.check()) {
229         setError(aSymmetryAlgo.getError());
230         return;
231       }
232
233       aSymmetryAlgo.build();
234
235       // Checking that the algorithm worked properly.
236       if(!aSymmetryAlgo.isDone()) {
237         static const std::string aFeatureError = "Error: Symmetry algorithm failed.";
238         setError(aFeatureError);
239         break;
240       }
241       if(aSymmetryAlgo.shape()->isNull()) {
242         static const std::string aShapeError = "Error: Resulting shape is Null.";
243         setError(aShapeError);
244         break;
245       }
246       if(!aSymmetryAlgo.isValid()) {
247         std::string aFeatureError = "Error: Resulting shape is not valid.";
248         setError(aFeatureError);
249         break;
250       }
251
252       buildResult(aSymmetryAlgo, aBaseShape, aResultIndex);
253     }
254     aResultIndex++;
255   }
256
257   // Remove the rest results if there were produced in the previous pass.
258   removeResults(aResultIndex);
259 }
260
261 //=================================================================================================
262 void FeaturesPlugin_Symmetry::performSymmetryByPlane()
263 {
264   // Getting objects.
265   ListOfShape anObjects;
266   std::list<ResultPtr> aContextes;
267   if (!collectSourceObjects(anObjects, aContextes))
268     return;
269
270   //Getting axis.
271   std::shared_ptr<GeomAPI_Ax2> aPlane;
272   std::shared_ptr<GeomAPI_Pln> aPln;
273   std::shared_ptr<ModelAPI_AttributeSelection> anObjRef =
274     selection(FeaturesPlugin_Symmetry::PLANE_OBJECT_ID());
275   if (anObjRef && anObjRef->value() && anObjRef->value()->isFace()) {
276     aPln = std::shared_ptr<GeomAPI_Face>(new GeomAPI_Face(anObjRef->value()))->getPlane();
277   }
278   else if (anObjRef && !anObjRef->value() && anObjRef->context() &&
279              anObjRef->context()->shape() && anObjRef->context()->shape()->isFace()) {
280     aPln =
281       std::shared_ptr<GeomAPI_Face>(new GeomAPI_Face(anObjRef->context()->shape()))->getPlane();
282   }
283   if (aPln) {
284     aPlane = std::shared_ptr<GeomAPI_Ax2>(new GeomAPI_Ax2(aPln->location(),
285                                                           aPln->direction()));
286   }
287
288   // Moving each object.
289   int aResultIndex = 0;
290   std::list<ResultPtr>::iterator aContext = aContextes.begin();
291   for(ListOfShape::iterator anObjectsIt = anObjects.begin(); anObjectsIt != anObjects.end();
292         anObjectsIt++, aContext++) {
293     std::shared_ptr<GeomAPI_Shape> aBaseShape = *anObjectsIt;
294     bool isPart = (*aContext)->groupName() == ModelAPI_ResultPart::group();
295
296     // Setting result.
297     if (isPart) {
298       std::shared_ptr<GeomAPI_Trsf> aTrsf(new GeomAPI_Trsf());
299       aTrsf->setSymmetry(aPlane);
300       ResultPartPtr anOrigin = std::dynamic_pointer_cast<ModelAPI_ResultPart>(*aContext);
301       buildResult(anOrigin, aTrsf, aResultIndex);
302     } else {
303       GeomAlgoAPI_Symmetry aSymmetryAlgo(aBaseShape, aPlane);
304
305       if (!aSymmetryAlgo.check()) {
306         setError(aSymmetryAlgo.getError());
307         return;
308       }
309
310       aSymmetryAlgo.build();
311
312       // Checking that the algorithm worked properly.
313       if(!aSymmetryAlgo.isDone()) {
314         static const std::string aFeatureError = "Error: Symmetry algorithm failed.";
315         setError(aFeatureError);
316         break;
317       }
318       if(aSymmetryAlgo.shape()->isNull()) {
319         static const std::string aShapeError = "Error: Resulting shape is Null.";
320         setError(aShapeError);
321         break;
322       }
323       if(!aSymmetryAlgo.isValid()) {
324         std::string aFeatureError = "Error: Resulting shape is not valid.";
325         setError(aFeatureError);
326         break;
327       }
328
329       buildResult(aSymmetryAlgo, aBaseShape, aResultIndex);
330     }
331     aResultIndex++;
332   }
333
334   // Remove the rest results if there were produced in the previous pass.
335   removeResults(aResultIndex);
336 }
337
338 //=================================================================================================
339 void FeaturesPlugin_Symmetry::buildResult(GeomAlgoAPI_Symmetry& theSymmetryAlgo,
340                                           std::shared_ptr<GeomAPI_Shape> theBaseShape,
341                                           int theResultIndex)
342 {
343   // Compose source shape and the result of symmetry.
344   GeomShapePtr aCompound;
345   if (boolean(KEEP_ORIGINAL_RESULT())->value()) {
346     ListOfShape aShapes;
347     aShapes.push_back(theBaseShape);
348     aShapes.push_back(theSymmetryAlgo.shape());
349     aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
350   } else
351     aCompound = theSymmetryAlgo.shape();
352
353   // Store and name the result.
354   ResultBodyPtr aResultBody = document()->createBody(data(), theResultIndex);
355   aResultBody->storeModified(theBaseShape, aCompound);
356   loadNamingDS(theSymmetryAlgo, aResultBody, theBaseShape);
357   setResult(aResultBody, theResultIndex);
358 }
359
360 //=================================================================================================
361 void FeaturesPlugin_Symmetry::buildResult(ResultPartPtr theOriginal,
362                                           std::shared_ptr<GeomAPI_Trsf> theTrsf,
363                                           int& theResultIndex)
364 {
365   if (boolean(KEEP_ORIGINAL_RESULT())->value()) {
366     std::shared_ptr<GeomAPI_Trsf> anIdentity(new GeomAPI_Trsf());
367     ResultPartPtr aCopy = document()->copyPart(theOriginal, data(), theResultIndex);
368     aCopy->setTrsf(theOriginal, anIdentity);
369     setResult(aCopy, theResultIndex);
370     ++theResultIndex;
371   }
372
373   ResultPartPtr aResultPart = document()->copyPart(theOriginal, data(), theResultIndex);
374   aResultPart->setTrsf(theOriginal, theTrsf);
375   setResult(aResultPart, theResultIndex);
376 }
377
378 //=================================================================================================
379 void FeaturesPlugin_Symmetry::loadNamingDS(GeomAlgoAPI_Symmetry& theSymmetryAlgo,
380                                            std::shared_ptr<ModelAPI_ResultBody> theResultBody,
381                                            std::shared_ptr<GeomAPI_Shape> theBaseShape)
382 {
383   // Name the faces
384   std::shared_ptr<GeomAPI_DataMapOfShapeShape> aSubShapes = theSymmetryAlgo.mapOfSubShapes();
385   std::string aReflectedName = "Symmetried";
386   FeaturesPlugin_Tools::storeModifiedShapes(theSymmetryAlgo, theResultBody,
387                                             theBaseShape, 1, 2, 3, aReflectedName,
388                                             *aSubShapes.get());
389 }