Salome HOME
Naming functions were from FeaturesPlugin_Tools to ModelAPI_Tools
[modules/shaper.git] / src / FeaturesPlugin / FeaturesPlugin_Symmetry.cpp
1 // Copyright (C) 2014-2021  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_Symmetry.h>
21
22 #include <GeomAlgoAPI_CompoundBuilder.h>
23 #include <GeomAlgoAPI_PointBuilder.h>
24 #include <GeomAlgoAPI_FaceBuilder.h>
25 #include <GeomAlgoAPI_Copy.h>
26 #include <GeomAlgoAPI_MakeShapeList.h>
27 #include <GeomAlgoAPI_Tools.h>
28 #include <GeomAlgoAPI_Transform.h>
29
30 #include <GeomAPI_Ax1.h>
31 #include <GeomAPI_Ax2.h>
32 #include <GeomAPI_Edge.h>
33 #include <GeomAPI_Face.h>
34 #include <GeomAPI_Lin.h>
35 #include <GeomAPI_Pln.h>
36 #include <GeomAPI_ShapeIterator.h>
37 #include <GeomAPI_Trsf.h>
38
39 #include <ModelAPI_AttributeBoolean.h>
40 #include <ModelAPI_AttributeSelectionList.h>
41 #include <ModelAPI_AttributeString.h>
42 #include <ModelAPI_ResultBody.h>
43 #include <ModelAPI_ResultPart.h>
44 #include <ModelAPI_Tools.h>
45
46 #include <FeaturesPlugin_Tools.h>
47
48 static const std::string SYMMETRY_VERSION_1("v9.5");
49
50 //=================================================================================================
51 FeaturesPlugin_Symmetry::FeaturesPlugin_Symmetry()
52 {
53 }
54
55 //=================================================================================================
56 void FeaturesPlugin_Symmetry::initAttributes()
57 {
58   data()->addAttribute(FeaturesPlugin_Symmetry::CREATION_METHOD(),
59                        ModelAPI_AttributeString::typeId());
60
61   AttributeSelectionListPtr aSelection =
62     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(data()->addAttribute(
63     FeaturesPlugin_Symmetry::OBJECTS_LIST_ID(), ModelAPI_AttributeSelectionList::typeId()));
64
65   data()->addAttribute(FeaturesPlugin_Symmetry::POINT_OBJECT_ID(),
66                        ModelAPI_AttributeSelection::typeId());
67
68   data()->addAttribute(FeaturesPlugin_Symmetry::AXIS_OBJECT_ID(),
69                        ModelAPI_AttributeSelection::typeId());
70
71   data()->addAttribute(FeaturesPlugin_Symmetry::PLANE_OBJECT_ID(),
72                        ModelAPI_AttributeSelection::typeId());
73
74   data()->addAttribute(FeaturesPlugin_Symmetry::KEEP_ORIGINAL_RESULT(),
75                        ModelAPI_AttributeBoolean::typeId());
76
77   if (!aSelection->isInitialized()) {
78     // new feature, not read from file
79     data()->setVersion(SYMMETRY_VERSION_1);
80   }
81 }
82
83 //=================================================================================================
84 void FeaturesPlugin_Symmetry::execute()
85 {
86   AttributeStringPtr aMethodTypeAttr = string(FeaturesPlugin_Symmetry::CREATION_METHOD());
87   std::string aMethodType = aMethodTypeAttr->value();
88
89   GeomTrsfPtr aTrsf;
90   if (aMethodType == CREATION_METHOD_BY_POINT())
91     aTrsf = symmetryByPoint();
92   else if (aMethodType == CREATION_METHOD_BY_AXIS())
93     aTrsf = symmetryByAxis();
94   else if (aMethodType == CREATION_METHOD_BY_PLANE())
95     aTrsf = symmetryByPlane();
96
97   performSymmetry(aTrsf);
98 }
99
100 //=================================================================================================
101 GeomTrsfPtr FeaturesPlugin_Symmetry::symmetryByPoint()
102 {
103   //Getting point.
104   std::shared_ptr<GeomAPI_Pnt> aPoint;
105   AttributeSelectionPtr anObjRef = selection(FeaturesPlugin_Symmetry::POINT_OBJECT_ID());
106   if (anObjRef.get() != NULL) {
107     GeomShapePtr aShape1 = anObjRef->value();
108     if (!aShape1.get()) {
109       aShape1 = anObjRef->context()->shape();
110     }
111     if (aShape1) {
112       aPoint = GeomAlgoAPI_PointBuilder::point(aShape1);
113     }
114   }
115
116   GeomTrsfPtr aTrsf(new GeomAPI_Trsf);
117   aTrsf->setSymmetry(aPoint);
118   return aTrsf;
119 }
120
121 //=================================================================================================
122 GeomTrsfPtr FeaturesPlugin_Symmetry::symmetryByAxis()
123 {
124   //Getting axis.
125   static const std::string aSelectionError = "Error: The axis shape selection is bad.";
126   AttributeSelectionPtr anObjRef = selection(AXIS_OBJECT_ID());
127   GeomShapePtr aShape = anObjRef->value();
128   if (!aShape.get()) {
129     if (anObjRef->context().get()) {
130       aShape = anObjRef->context()->shape();
131     }
132   }
133   if (!aShape.get()) {
134     setError(aSelectionError);
135     return GeomTrsfPtr();
136   }
137
138   GeomEdgePtr anEdge;
139   if (aShape->isEdge())
140   {
141     anEdge = aShape->edge();
142   }
143   else if (aShape->isCompound())
144   {
145     GeomAPI_ShapeIterator anIt(aShape);
146     anEdge = anIt.current()->edge();
147   }
148
149   if (!anEdge.get())
150   {
151     setError(aSelectionError);
152     return GeomTrsfPtr();
153   }
154
155   std::shared_ptr<GeomAPI_Ax1> anAxis (new GeomAPI_Ax1(anEdge->line()->location(),
156                                                        anEdge->line()->direction()));
157   GeomTrsfPtr aTrsf(new GeomAPI_Trsf);
158   aTrsf->setSymmetry(anAxis);
159   return aTrsf;
160 }
161
162 //=================================================================================================
163 GeomTrsfPtr FeaturesPlugin_Symmetry::symmetryByPlane()
164 {
165   //Getting plane.
166   static const std::string aSelectionError = "Error: The plane shape selection is bad.";
167   AttributeSelectionPtr anObjRef = selection(PLANE_OBJECT_ID());
168   GeomShapePtr aShape = anObjRef->value();
169   if (!aShape.get()) {
170     if (anObjRef->context().get()) {
171       aShape = anObjRef->context()->shape();
172     }
173   }
174   if (!aShape.get()) {
175     setError(aSelectionError);
176     return GeomTrsfPtr();
177   }
178
179   GeomFacePtr aFace;
180   if (aShape->isFace())
181   {
182     aFace = aShape->face();
183   }
184   else if (aShape->isCompound())
185   {
186     GeomAPI_ShapeIterator anIt(aShape);
187     aFace = anIt.current()->face();
188   }
189
190   if (!aFace.get())
191   {
192     setError(aSelectionError);
193     return GeomTrsfPtr();
194   }
195
196   std::shared_ptr<GeomAPI_Ax2> aPlane(new GeomAPI_Ax2(aFace->getPlane()->location(),
197                                                       aFace->getPlane()->direction()));
198   GeomTrsfPtr aTrsf(new GeomAPI_Trsf);
199   aTrsf->setSymmetry(aPlane);
200   return aTrsf;
201 }
202
203 //=================================================================================================
204 void FeaturesPlugin_Symmetry::buildResult(
205     const std::shared_ptr<GeomAlgoAPI_MakeShapeList>& theAlgo,
206     const std::list<std::shared_ptr<GeomAPI_Shape> >& theOriginalShapes,
207     std::shared_ptr<GeomAPI_Shape> theTargetShape, int& theResultIndex,
208     std::string & theTextureFile)
209 {
210   // Store and name the result.
211   ResultBodyPtr aResultBody = document()->createBody(data(), theResultIndex);
212   ModelAPI_Tools::loadModifiedShapes(aResultBody, theOriginalShapes, ListOfShape(),
213                                      theAlgo, theTargetShape, "Symmetried");
214   aResultBody->setTextureFile(theTextureFile);
215   setResult(aResultBody, theResultIndex++);
216 }
217
218 //=================================================================================================
219 void FeaturesPlugin_Symmetry::buildResult(ResultPartPtr theOriginal,
220                                           std::shared_ptr<GeomAPI_Trsf> theTrsf,
221                                           int& theResultIndex)
222 {
223   if (boolean(KEEP_ORIGINAL_RESULT())->value()) {
224     std::shared_ptr<GeomAPI_Trsf> anIdentity(new GeomAPI_Trsf());
225     ResultPartPtr aCopy = document()->copyPart(theOriginal, data(), theResultIndex);
226     aCopy->setTrsf(theOriginal, anIdentity);
227     setResult(aCopy, theResultIndex++);
228   }
229
230   ResultPartPtr aResultPart = document()->copyPart(theOriginal, data(), theResultIndex);
231   aResultPart->setTrsf(theOriginal, theTrsf);
232   setResult(aResultPart, theResultIndex++);
233 }
234
235 //=================================================================================================
236 static bool performShapeSymmetry(std::shared_ptr<GeomAlgoAPI_MakeShapeList>& theAlgoList,
237                                  GeomAPI_ShapeHierarchy& theHierarchy,
238                                  GeomShapePtr theBaseShape,
239                                  GeomTrsfPtr theTrsf,
240                                  bool isKeepOriginalResult,
241                                  const std::string& theFeatureKind,
242                                  std::string& theError)
243 {
244   std::shared_ptr<GeomAlgoAPI_Transform> aSymmetryAlgo(
245       new GeomAlgoAPI_Transform(theBaseShape, theTrsf));
246
247   // Checking that the algorithm worked properly.
248   if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aSymmetryAlgo, theFeatureKind, theError))
249     return false;
250
251   theAlgoList->appendAlgo(aSymmetryAlgo);
252
253   // Compose source shape and the result of symmetry.
254   GeomShapePtr aCompound;
255   if (isKeepOriginalResult) {
256     ListOfShape aShapes;
257     // add a copy of a base shape otherwise selection of this base shape is bad (2592)
258     std::shared_ptr<GeomAlgoAPI_Copy> aCopyAlgo(new GeomAlgoAPI_Copy(theBaseShape));
259     aShapes.push_back(aCopyAlgo->shape());
260     theAlgoList->appendAlgo(aCopyAlgo);
261
262     aShapes.push_back(aSymmetryAlgo->shape());
263     aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
264   }
265   else
266     aCompound = aSymmetryAlgo->shape();
267
268   theHierarchy.markModified(theBaseShape, aCompound);
269   return true;
270 }
271
272 void FeaturesPlugin_Symmetry::performSymmetry(GeomTrsfPtr theTrsf)
273 {
274   if (!theTrsf) {
275     setError("Invalid transformation.");
276     return;
277   }
278
279   bool isKeepOriginal = boolean(KEEP_ORIGINAL_RESULT())->value();
280   bool isKeepSubShapes = data()->version() == SYMMETRY_VERSION_1;
281
282   // Getting objects.
283   GeomAPI_ShapeHierarchy anObjects;
284   std::list<ResultPtr> aParts;
285   std::string theTextureFile;
286   AttributeSelectionListPtr anObjSelList = selectionList(OBJECTS_LIST_ID());
287   if (!FeaturesPlugin_Tools::shapesFromSelectionList(
288        anObjSelList, isKeepSubShapes, anObjects, aParts, theTextureFile))
289     return;
290
291   std::string anError;
292   int aResultIndex = 0;
293   // Symmetrying parts.
294   for (std::list<ResultPtr>::iterator aPRes = aParts.begin(); aPRes != aParts.end(); ++aPRes) {
295     ResultPartPtr anOriginal = std::dynamic_pointer_cast<ModelAPI_ResultPart>(*aPRes);
296     buildResult(anOriginal, theTrsf, aResultIndex);
297   }
298
299   // Collect transformations for each object in a part.
300   std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeShapeList(new GeomAlgoAPI_MakeShapeList);
301   for (GeomAPI_ShapeHierarchy::iterator anObjectsIt = anObjects.begin();
302        anObjectsIt != anObjects.end(); ++anObjectsIt) {
303     std::shared_ptr<GeomAPI_Shape> aBaseShape = *anObjectsIt;
304     if (!performShapeSymmetry(aMakeShapeList, anObjects, aBaseShape, theTrsf,
305                               isKeepOriginal, getKind(), anError)) {
306       setError(anError);
307       break;
308     }
309   }
310
311   // Build results of the rotation.
312   const ListOfShape& anOriginalShapes = anObjects.objects();
313   ListOfShape aTopLevel;
314   anObjects.topLevelObjects(aTopLevel);
315   for (ListOfShape::iterator anIt = aTopLevel.begin(); anIt != aTopLevel.end(); ++anIt)
316     buildResult(aMakeShapeList, anOriginalShapes, *anIt, aResultIndex, theTextureFile);
317
318   // Remove the rest results if there were produced in the previous pass.
319   removeResults(aResultIndex);
320 }