Salome HOME
bos #26449: SHAPER: save imported images
[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     const ResultPtr& theTextureSource)
209 {
210   // Store and name the result.
211   ResultBodyPtr aResultBody = document()->createBody(data(), theResultIndex);
212   FeaturesPlugin_Tools::loadModifiedShapes(aResultBody, theOriginalShapes, ListOfShape(),
213                                            theAlgo, theTargetShape, "Symmetried");
214   // Copy image data, if any
215   ModelAPI_Tools::copyImageAttribute(theTextureSource, aResultBody);
216   setResult(aResultBody, theResultIndex++);
217 }
218
219 //=================================================================================================
220 void FeaturesPlugin_Symmetry::buildResult(ResultPartPtr theOriginal,
221                                           std::shared_ptr<GeomAPI_Trsf> theTrsf,
222                                           int& theResultIndex)
223 {
224   if (boolean(KEEP_ORIGINAL_RESULT())->value()) {
225     std::shared_ptr<GeomAPI_Trsf> anIdentity(new GeomAPI_Trsf());
226     ResultPartPtr aCopy = document()->copyPart(theOriginal, data(), theResultIndex);
227     aCopy->setTrsf(theOriginal, anIdentity);
228     setResult(aCopy, theResultIndex++);
229   }
230
231   ResultPartPtr aResultPart = document()->copyPart(theOriginal, data(), theResultIndex);
232   aResultPart->setTrsf(theOriginal, theTrsf);
233   setResult(aResultPart, theResultIndex++);
234 }
235
236 //=================================================================================================
237 static bool performShapeSymmetry(std::shared_ptr<GeomAlgoAPI_MakeShapeList>& theAlgoList,
238                                  GeomAPI_ShapeHierarchy& theHierarchy,
239                                  GeomShapePtr theBaseShape,
240                                  GeomTrsfPtr theTrsf,
241                                  bool isKeepOriginalResult,
242                                  const std::string& theFeatureKind,
243                                  std::string& theError)
244 {
245   std::shared_ptr<GeomAlgoAPI_Transform> aSymmetryAlgo(
246       new GeomAlgoAPI_Transform(theBaseShape, theTrsf));
247
248   // Checking that the algorithm worked properly.
249   if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aSymmetryAlgo, theFeatureKind, theError))
250     return false;
251
252   theAlgoList->appendAlgo(aSymmetryAlgo);
253
254   // Compose source shape and the result of symmetry.
255   GeomShapePtr aCompound;
256   if (isKeepOriginalResult) {
257     ListOfShape aShapes;
258     // add a copy of a base shape otherwise selection of this base shape is bad (2592)
259     std::shared_ptr<GeomAlgoAPI_Copy> aCopyAlgo(new GeomAlgoAPI_Copy(theBaseShape));
260     aShapes.push_back(aCopyAlgo->shape());
261     theAlgoList->appendAlgo(aCopyAlgo);
262
263     aShapes.push_back(aSymmetryAlgo->shape());
264     aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
265   }
266   else
267     aCompound = aSymmetryAlgo->shape();
268
269   theHierarchy.markModified(theBaseShape, aCompound);
270   return true;
271 }
272
273 void FeaturesPlugin_Symmetry::performSymmetry(GeomTrsfPtr theTrsf)
274 {
275   if (!theTrsf) {
276     setError("Invalid transformation.");
277     return;
278   }
279
280   bool isKeepOriginal = boolean(KEEP_ORIGINAL_RESULT())->value();
281   bool isKeepSubShapes = data()->version() == SYMMETRY_VERSION_1;
282
283   // Getting objects.
284   GeomAPI_ShapeHierarchy anObjects;
285   std::list<ResultPtr> aParts;
286   ResultPtr aTextureSource;
287   AttributeSelectionListPtr anObjSelList = selectionList(OBJECTS_LIST_ID());
288   if (!FeaturesPlugin_Tools::shapesFromSelectionList(
289        anObjSelList, isKeepSubShapes, anObjects, aParts, aTextureSource))
290     return;
291
292   std::string anError;
293   int aResultIndex = 0;
294   // Symmetrying parts.
295   for (std::list<ResultPtr>::iterator aPRes = aParts.begin(); aPRes != aParts.end(); ++aPRes) {
296     ResultPartPtr anOriginal = std::dynamic_pointer_cast<ModelAPI_ResultPart>(*aPRes);
297     buildResult(anOriginal, theTrsf, aResultIndex);
298   }
299
300   // Collect transformations for each object in a part.
301   std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeShapeList(new GeomAlgoAPI_MakeShapeList);
302   for (GeomAPI_ShapeHierarchy::iterator anObjectsIt = anObjects.begin();
303        anObjectsIt != anObjects.end(); ++anObjectsIt) {
304     std::shared_ptr<GeomAPI_Shape> aBaseShape = *anObjectsIt;
305     if (!performShapeSymmetry(aMakeShapeList, anObjects, aBaseShape, theTrsf,
306                               isKeepOriginal, getKind(), anError)) {
307       setError(anError);
308       break;
309     }
310   }
311
312   // Build results of the rotation.
313   const ListOfShape& anOriginalShapes = anObjects.objects();
314   ListOfShape aTopLevel;
315   anObjects.topLevelObjects(aTopLevel);
316   for (ListOfShape::iterator anIt = aTopLevel.begin(); anIt != aTopLevel.end(); ++anIt)
317     buildResult(aMakeShapeList, anOriginalShapes, *anIt, aResultIndex, aTextureSource);
318
319   // Remove the rest results if there were produced in the previous pass.
320   removeResults(aResultIndex);
321 }