Salome HOME
Merge branch 'master' of https://codev-tuleap.cea.fr/plugins/git/salome/shaper
[modules/shaper.git] / src / FeaturesPlugin / FeaturesPlugin_MultiRotation.cpp
1 // Copyright (C) 2017-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 // File:        FeaturesPlugin_MultiRotation.cpp
21 // Created:     30 Jan 2017
22 // Author:      Clarisse Genrault (CEA)
23
24 #include <FeaturesPlugin_MultiRotation.h>
25 #include <FeaturesPlugin_Tools.h>
26
27 #include <GeomAlgoAPI_CompoundBuilder.h>
28 #include <GeomAlgoAPI_MakeShapeList.h>
29 #include <GeomAlgoAPI_ShapeTools.h>
30 #include <GeomAlgoAPI_Tools.h>
31 #include <GeomAlgoAPI_Translation.h>
32
33 #include <GeomAPI_ShapeExplorer.h>
34
35 #include <GeomAPI_Ax1.h>
36 #include <GeomAPI_Edge.h>
37 #include <GeomAPI_Lin.h>
38 #include <GeomAPI_ShapeIterator.h>
39 #include <GeomAPI_Trsf.h>
40
41 #include <ModelAPI_AttributeDouble.h>
42 #include <ModelAPI_AttributeInteger.h>
43 #include <ModelAPI_AttributeSelectionList.h>
44 #include <ModelAPI_AttributeString.h>
45 #include <ModelAPI_ResultBody.h>
46 #include <ModelAPI_ResultPart.h>
47
48 #include <math.h>
49 #include <iostream>
50
51 static const std::string MULTIROTATION_VERSION_1("v9.5");
52
53 //=================================================================================================
54 FeaturesPlugin_MultiRotation::FeaturesPlugin_MultiRotation()
55 {
56 }
57
58 //=================================================================================================
59 void FeaturesPlugin_MultiRotation::initAttributes()
60 {
61   AttributeSelectionListPtr aSelection =
62     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(data()->addAttribute(
63     FeaturesPlugin_MultiRotation::OBJECTS_LIST_ID(),
64     ModelAPI_AttributeSelectionList::typeId()));
65
66   data()->addAttribute(FeaturesPlugin_MultiRotation::AXIS_ANGULAR_ID(),
67                        ModelAPI_AttributeSelection::typeId());
68   data()->addAttribute(FeaturesPlugin_MultiRotation::USE_ANGULAR_STEP_ID(),
69                        ModelAPI_AttributeString::typeId());
70   data()->addAttribute(FeaturesPlugin_MultiRotation::STEP_ANGULAR_ID(),
71                        ModelAPI_AttributeDouble::typeId());
72   data()->addAttribute(FeaturesPlugin_MultiRotation::NB_COPIES_ANGULAR_ID(),
73                        ModelAPI_AttributeInteger::typeId());
74
75 #ifdef FEATURE_MULTIROTATION_TWO_DIRECTIONS
76   data()->addAttribute(FeaturesPlugin_MultiRotation::USE_RADIAL_DIR_ID(),
77                        ModelAPI_AttributeString::typeId());
78   data()->addAttribute(FeaturesPlugin_MultiRotation::STEP_RADIAL_ID(),
79                        ModelAPI_AttributeDouble::typeId());
80   data()->addAttribute(FeaturesPlugin_MultiRotation::NB_COPIES_RADIAL_ID(),
81                        ModelAPI_AttributeInteger::typeId());
82 #endif
83
84   if (!aSelection->isInitialized()) {
85     // new feature, not read from file
86     data()->setVersion(MULTIROTATION_VERSION_1);
87   }
88 }
89
90 //=================================================================================================
91 void FeaturesPlugin_MultiRotation::execute()
92 {
93 #ifdef FEATURE_MULTIROTATION_TWO_DIRECTIONS
94   std::string useRadialDir = string(FeaturesPlugin_MultiRotation::USE_RADIAL_DIR_ID())->value();
95   if (useRadialDir.empty()) {
96     performRotation1D();
97   } else {
98     performRotation2D();
99   }
100 #else
101   performRotation1D();
102 #endif
103 }
104
105 //=================================================================================================
106 bool FeaturesPlugin_MultiRotation::paramsOfRotation(std::shared_ptr<GeomAPI_Ax1>& theAxis,
107                                                     double& theAngle,
108                                                     int& theQuantity)
109 {
110   //Getting axis.
111   static const std::string aSelectionError = "Error: The axis shape selection is bad.";
112   AttributeSelectionPtr anObjRef = selection(AXIS_ANGULAR_ID());
113   GeomShapePtr aShape = anObjRef->value();
114   if (!aShape.get() && anObjRef->context().get())
115     aShape = anObjRef->context()->shape();
116   if (!aShape.get()) {
117     setError(aSelectionError);
118     return false;
119   }
120
121   GeomEdgePtr anEdge;
122   if (aShape->isEdge())
123     anEdge = aShape->edge();
124   else if (aShape->isCompound()) {
125     GeomAPI_ShapeIterator anIt(aShape);
126     anEdge = anIt.current()->edge();
127   }
128
129   if (!anEdge.get()) {
130     setError(aSelectionError);
131     return false;
132   }
133
134   theAxis.reset(new GeomAPI_Ax1(anEdge->line()->location(), anEdge->line()->direction()));
135
136   // Getting number of copies.
137   theQuantity = integer(FeaturesPlugin_MultiRotation::NB_COPIES_ANGULAR_ID())->value();
138   if (theQuantity <= 0) {
139     std::string aFeatureError = "Multirotation builder ";
140     aFeatureError += ":: the number of copies for the angular direction is null or negative.";
141     setError(aFeatureError);
142     return false;
143   }
144
145   // Getting angle
146   std::string useAngularStep =
147     string(FeaturesPlugin_MultiRotation::USE_ANGULAR_STEP_ID())->value();
148   if (!useAngularStep.empty())
149     theAngle = real(FeaturesPlugin_MultiRotation::STEP_ANGULAR_ID())->value();
150   else
151     theAngle = 360. / theQuantity;
152   return true;
153 }
154
155 //=================================================================================================
156 void FeaturesPlugin_MultiRotation::performRotation1D()
157 {
158   bool isKeepSubShapes = data()->version() == MULTIROTATION_VERSION_1;
159
160   // Getting objects.
161   AttributeSelectionListPtr anObjectsSelList = selectionList(OBJECTS_LIST_ID());
162   if (anObjectsSelList->size() == 0) {
163     setError("Error: empty selection list");
164     return;
165   }
166
167   GeomAPI_ShapeHierarchy anObjects;
168   std::list<ResultPtr> aParts;
169   std::string theTextureFile;
170   if (!FeaturesPlugin_Tools::shapesFromSelectionList(
171        anObjectsSelList, isKeepSubShapes, anObjects, aParts, theTextureFile))
172     return;
173
174   // Parameters of rotation.
175   std::shared_ptr<GeomAPI_Ax1> anAxis;
176   double anAngle = 0.0;
177   int nbCopies = 0;
178   if (!paramsOfRotation(anAxis, anAngle, nbCopies))
179     return;
180
181
182   std::string anError;
183   int aResultIndex = 0;
184   // Moving each part.
185   for (std::list<ResultPtr>::iterator aPRes = aParts.begin(); aPRes != aParts.end(); ++aPRes) {
186     ResultPartPtr anOrigin = std::dynamic_pointer_cast<ModelAPI_ResultPart>(*aPRes);
187     std::shared_ptr<GeomAPI_Trsf> aTrsf(new GeomAPI_Trsf());
188     for (int i = 0; i < nbCopies; ++i) {
189       aTrsf->setRotation(anAxis, i * anAngle);
190       ResultPartPtr aResultPart = document()->copyPart(anOrigin, data(), aResultIndex);
191       aResultPart->setTrsf(anOrigin, aTrsf);
192       setResult(aResultPart, aResultIndex++);
193     }
194   }
195
196   // Collect transformations for each object in a part.
197   std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeShapeList(new GeomAlgoAPI_MakeShapeList);
198   for (GeomAPI_ShapeHierarchy::iterator anObjectsIt = anObjects.begin();
199        anObjectsIt != anObjects.end(); anObjectsIt++) {
200     std::shared_ptr<GeomAPI_Shape> aBaseShape = *anObjectsIt;
201     ListOfShape aListOfShape;
202
203     for (int i = 0; i < nbCopies; i++) {
204       std::shared_ptr<GeomAlgoAPI_Rotation> aRotationnAlgo(
205           new GeomAlgoAPI_Rotation(aBaseShape, anAxis, i * anAngle));
206
207       // Checking that the algorithm worked properly.
208       if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aRotationnAlgo, getKind(), anError)) {
209         setError(anError);
210         break;
211       }
212       aListOfShape.push_back(aRotationnAlgo->shape());
213       aMakeShapeList->appendAlgo(aRotationnAlgo);
214     }
215
216     GeomShapePtr aCompound = GeomAlgoAPI_CompoundBuilder::compound(aListOfShape);
217     anObjects.markModified(aBaseShape, aCompound);
218   }
219
220   // Build results of the operation.
221   const ListOfShape& anOriginalShapes = anObjects.objects();
222   ListOfShape aTopLevel;
223   anObjects.topLevelObjects(aTopLevel);
224   for (ListOfShape::iterator anIt = aTopLevel.begin(); anIt != aTopLevel.end(); ++anIt) {
225     ResultBodyPtr aResultBody = document()->createBody(data(), aResultIndex);
226     FeaturesPlugin_Tools::loadModifiedShapes(aResultBody, anOriginalShapes, ListOfShape(),
227                                              aMakeShapeList, *anIt, "Rotated");
228     aResultBody->setTextureFile(theTextureFile);
229     setResult(aResultBody, aResultIndex++);
230   }
231
232   // Remove the rest results if there were produced in the previous pass.
233   removeResults(aResultIndex);
234 }
235
236 //=================================================================================================
237 #ifdef FEATURE_MULTIROTATION_TWO_DIRECTIONS
238 void FeaturesPlugin_MultiRotation::performRotation2D()
239 {
240   // Getting objects.
241   ListOfShape anObjects;
242   std::list<ResultPtr> aContextes;
243   AttributeSelectionListPtr anObjectsSelList =
244     selectionList(FeaturesPlugin_MultiRotation::OBJECTS_LIST_ID());
245   if (anObjectsSelList->size() == 0) {
246     return;
247   }
248   for(int anObjectsIndex = 0; anObjectsIndex < anObjectsSelList->size(); anObjectsIndex++) {
249     std::shared_ptr<ModelAPI_AttributeSelection> anObjectAttr =
250       anObjectsSelList->value(anObjectsIndex);
251     std::shared_ptr<GeomAPI_Shape> anObject = anObjectAttr->value();
252     if(!anObject.get()) { // may be for not-activated parts
253       return;
254     }
255     anObjects.push_back(anObject);
256     aContextes.push_back(anObjectAttr->context());
257   }
258
259   // Parameters of rotation.
260   std::shared_ptr<GeomAPI_Ax1> anAxis;
261   double anAngle = 0.0;
262   int nbCopies = 0;
263   if (!paramsOfRotation(anAxis, anAngle, nbCopies))
264     return;
265
266
267   // Getting number of copies int he radial direction.
268   int nbRadial =
269     integer(FeaturesPlugin_MultiRotation::NB_COPIES_RADIAL_ID())->value();
270
271   if (nbRadial <=0) {
272     std::string aFeatureError = "Multirotation builder ";
273     aFeatureError+=":: the number of copies for the radial direction is null or negative.";
274     setError(aFeatureError);
275     return;
276   }
277
278   // Getting step
279   double aStep = real(FeaturesPlugin_MultiRotation::STEP_RADIAL_ID())->value();
280
281   // Moving each object.
282   int aResultIndex = 0;
283   std::list<ResultPtr>::iterator aContext = aContextes.begin();
284   for(ListOfShape::iterator anObjectsIt = anObjects.begin(); anObjectsIt != anObjects.end();
285         anObjectsIt++, aContext++) {
286     std::shared_ptr<GeomAPI_Shape> aBaseShape = *anObjectsIt;
287     bool isPart = aContext->get() && (*aContext)->groupName() == ModelAPI_ResultPart::group();
288
289     std::shared_ptr<GeomAPI_Dir> aDir =
290       GeomAlgoAPI_ShapeTools::buildDirFromAxisAndShape(aBaseShape, anAxis);
291     double x = aDir->x();
292     double y = aDir->y();
293     double z = aDir->z();
294     double norm = sqrt(x*x+y*y+z*z);
295
296     // Setting result.
297     if (isPart) {
298       /*ResultPartPtr anOrigin = std::dynamic_pointer_cast<ModelAPI_ResultPart>(*aContext);
299       std::shared_ptr<GeomAPI_Trsf> aTrsf(new GeomAPI_Trsf());
300       for (int j=0; j<aSecondNbCopies; j++) {
301         for (int i=0; i<aFirstNbCopies; i++) {
302           double dx = i*aFirstStep*x1/norm1+j*aSecondStep*x2/norm2;
303           double dy = i*aFirstStep*y1/norm1+j*aSecondStep*y2/norm2;
304           double dz = i*aFirstStep*z1/norm1+j*aSecondStep*z2/norm2;
305           aTrsf->setTranslation(dx, dy, dz);
306           ResultPartPtr aResultPart = document()->copyPart(anOrigin, data(), aResultIndex);
307           aResultPart->setTrsf(*aContext, aTrsf);
308           setResult(aResultPart, aResultIndex);
309           aResultIndex++;
310         }
311       }*/
312     } else {
313       ListOfShape aListOfShape;
314       std::list<std::shared_ptr<GeomAlgoAPI_Translation> > aListOfTranslationAlgo;
315       std::list<std::shared_ptr<GeomAlgoAPI_Rotation> > aListOfRotationAlgo;
316       for (int j=0; j<nbRadial; j++) {
317         // Translation
318         double dx = j*aStep*x/norm;
319         double dy = j*aStep*y/norm;
320         double dz = j*aStep*z/norm;
321         std::shared_ptr<GeomAlgoAPI_Translation> aTranslationAlgo(
322           new GeomAlgoAPI_Translation(aBaseShape, dx, dy, dz));
323
324         if (!aTranslationAlgo->check()) {
325           setError(aTranslationAlgo->getError());
326           break;
327         }
328
329         aTranslationAlgo->build();
330
331         // Checking that the algorithm worked properly.
332         if (!aTranslationAlgo->isDone()) {
333           static const std::string aFeatureError = "Error : Multirotation algorithm failed.";
334           setError(aFeatureError);
335           break;
336         }
337         if (aTranslationAlgo->shape()->isNull()) {
338           static const std::string aShapeError = "Error : Resulting shape is null.";
339           setError(aShapeError);
340           break;
341         }
342         if (!aTranslationAlgo->isValid()) {
343           static const std::string aFeatureError = "Error : Resulting shape in not valid.";
344           setError(aFeatureError);
345           break;
346         }
347         aListOfShape.push_back(aTranslationAlgo->shape());
348         aListOfTranslationAlgo.push_back(aTranslationAlgo);
349         for (int i=1; i<nbAngular; i++) {
350           std::shared_ptr<GeomAlgoAPI_Rotation> aRotationnAlgo(
351             new GeomAlgoAPI_Rotation(aTranslationAlgo->shape(), anAxis, i*anAngle));
352           if (!aRotationnAlgo->check()) {
353             setError(aTranslationAlgo->getError());
354             break;
355           }
356           aRotationnAlgo->build();// Checking that the algorithm worked properly.
357           if (!aRotationnAlgo->isDone()) {
358             static const std::string aFeatureError = "Error : Multirotation algorithm failed.";
359             setError(aFeatureError);
360             break;
361           }
362           if (aRotationnAlgo->shape()->isNull()) {
363             static const std::string aShapeError = "Error : Resulting shape is null.";
364             setError(aShapeError);
365             break;
366           }
367           if (!aRotationnAlgo->isValid()) {
368             static const std::string aFeatureError = "Error : Resulting shape in not valid.";
369             setError(aFeatureError);
370             break;
371           }
372           aListOfShape.push_back(aRotationnAlgo->shape());
373           aListOfRotationAlgo.push_back(aRotationnAlgo);
374         }
375       }
376       std::shared_ptr<GeomAPI_Shape> aCompound =
377         GeomAlgoAPI_CompoundBuilder::compound(aListOfShape);
378       ResultBodyPtr aResultBody = document()->createBody(data(), aResultIndex);
379       aResultBody->storeModified(aBaseShape, aCompound);
380
381       loadNamingDS2(aListOfTranslationAlgo, aResultBody, aBaseShape);
382       loadNamingDS3(aListOfRotationAlgo, aResultBody, aBaseShape, nbRadial);
383       setResult(aResultBody, aResultIndex);
384       aResultIndex++;
385     }
386   }
387
388   // Remove the rest results if there were produced in the previous pass.
389   removeResults(aResultIndex);
390 }
391
392 //=================================================================================================
393 void FeaturesPlugin_MultiRotation::loadNamingDS2(
394     std::list<std::shared_ptr<GeomAlgoAPI_Translation> > theListOfTranslationAlgo,
395     std::shared_ptr<ModelAPI_ResultBody> theResultBody,
396     std::shared_ptr<GeomAPI_Shape> theBaseShape)
397 {
398   for (std::list<std::shared_ptr<GeomAlgoAPI_Translation> >::const_iterator anIt =
399     theListOfTranslationAlgo.begin(); anIt != theListOfTranslationAlgo.cend(); ++anIt) {
400     // naming of faces
401     theResultBody->loadModifiedShapes(*anIt, theBaseShape, GeomAPI_Shape::FACE, "Rotated_Face");
402
403     // naming of edges
404     theResultBody->loadModifiedShapes(*anIt, theBaseShape, GeomAPI_Shape::EDGE, "Rotated_Edge");
405
406     // naming of vertex
407     theResultBody->loadModifiedShapes(*anIt, theBaseShape, GeomAPI_Shape::VERTEX, "Rotated_Vertex");
408   }
409 }
410
411 //=================================================================================================
412 void FeaturesPlugin_MultiRotation::loadNamingDS3(
413     std::list<std::shared_ptr<GeomAlgoAPI_Rotation> > theListOfRotationAlgo,
414     std::shared_ptr<ModelAPI_ResultBody> theResultBody,
415     std::shared_ptr<GeomAPI_Shape> theBaseShape, int nb)
416 {
417   int anIndex = nb+1;
418   std::string aRotatedName;
419
420   for (std::list<std::shared_ptr<GeomAlgoAPI_Rotation> >::const_iterator anIt =
421     theListOfRotationAlgo.begin(); anIt != theListOfRotationAlgo.cend(); ++anIt) {
422
423     // naming of faces
424     int numFace = 1;
425     GeomAPI_ShapeExplorer anExp((*anIt)->shape(), GeomAPI_Shape::FACE);
426     for(; anExp.more(); anExp.next()) {
427        aRotatedName = "Rotated_Face_" + std::to_string((long long) anIndex);
428        aRotatedName = aRotatedName + "_" + std::to_string((long long) numFace);
429        theResultBody->generated(anExp.current(), aRotatedName);
430        ++numFace;
431     }
432     ++anIndex;
433   }
434 }
435 #endif