EulerCoordinateRotation.C
Go to the documentation of this file.
1/*---------------------------------------------------------------------------*\
2 ========= |
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4 \\ / O peration |
5 \\ / A nd | www.openfoam.com
6 \\/ M anipulation |
7-------------------------------------------------------------------------------
8 Copyright (C) 2011-2016 OpenFOAM Foundation
9 Copyright (C) 2017-2020 OpenCFD Ltd.
10-------------------------------------------------------------------------------
11License
12 This file is part of OpenFOAM.
13
14 OpenFOAM is free software: you can redistribute it and/or modify it
15 under the terms of the GNU General Public License as published by
16 the Free Software Foundation, either version 3 of the License, or
17 (at your option) any later version.
18
19 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26
27\*---------------------------------------------------------------------------*/
28
30#include "unitConversion.H"
32
33// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
34
35namespace Foam
36{
37namespace coordinateRotations
38{
39
41
42 // Standard short name
44 (
46 euler,
48 euler
49 );
50
51 // Long name - Compat 1806
53 (
55 euler,
57 euler,
58 EulerRotation,
59 1806
60 );
61
62} // End namespace coordinateRotations
63} // End namespace Foam
64
65
66// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
67
69(
70 const eulerOrder order,
71 const vector& angles,
72 bool degrees
73)
74{
75 scalar angle1(angles.x()); // Rotation #1
76 scalar angle2(angles.y()); // Rotation #2
77 scalar angle3(angles.z()); // Rotation #3
78
79 if (degrees)
80 {
81 angle1 *= degToRad();
82 angle2 *= degToRad();
83 angle3 *= degToRad();
84 }
85
86 const scalar c1(cos(angle1)); const scalar s1(sin(angle1));
87 const scalar c2(cos(angle2)); const scalar s2(sin(angle2));
88 const scalar c3(cos(angle3)); const scalar s3(sin(angle3));
89
90 // https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix
91
92 switch (order)
93 {
94 // Proper Euler angles
95
96 case eulerOrder::XZX: // X1-Z2-X3 rotation
97 {
98 return tensor
99 (
100 ( c2 ), ( -c3*s2 ), ( s2*s3 ),
101 ( c1*s2 ), ( c1*c2*c3 - s1*s3 ), ( -c3*s1 - c1*c2*s3 ),
102 ( s1*s2 ), ( c1*s3 + c2*c3*s1 ), ( c1*c3 - c2*s1*s3 )
103 );
104 break;
105 }
106
107 case eulerOrder::XYX: // X1-Y2-X3 rotation
108 {
109 return tensor
110 (
111 ( c2 ), ( s2*s3 ), ( c3*s2 ),
112 ( s1*s2 ), ( c1*c3 - c2*s1*s3 ), ( -c1*s3 - c2*c3*s1 ),
113 ( -c1*s2 ), ( c3*s1 + c1*c2*s3 ), ( c1*c2*c3 - s1*s3 )
114 );
115 break;
116 }
117
118 case eulerOrder::YXY: // Y1-X2-Y3 rotation
119 {
120 return tensor
121 (
122 ( c1*c3 - c2*s1*s3 ), ( s1*s2 ), ( c1*s3 + c2*c3*s1 ),
123 ( s2*s3 ), ( c2 ), ( -c3*s2 ),
124 ( -c3*s1 -c1*c2*s3 ), ( c1*s2 ), ( c1*c2*c3 - s1*s3 )
125 );
126 break;
127 }
128
129 case eulerOrder::YZY: // Y1-Z2-Y3 rotation
130 {
131 return tensor
132 (
133 ( c1*c2*c3 - s1*s3 ), ( -c1*s2 ), ( c3*s1 + c1*c2*s3 ),
134 ( c3*s2 ), ( c2 ), ( s2*s3 ),
135 (-c1*s3 - c2*c3*s1 ), ( s1*s2 ), ( c1*c3 - c2*s1*s3 )
136 );
137 break;
138 }
139
140 case eulerOrder::ZYZ: // Z1-Y2-Z3 rotation
141 {
142 return tensor
143 (
144 ( c1*c2*c3 - s1*s3 ), ( -c3*s1 - c1*c2*s3 ), ( c1*s2 ),
145 ( c1*s3 + c2*c3*s1 ), ( c1*c3 - c2*s1*s3 ), ( s1*s2 ),
146 ( -c3*s2 ), ( s2*s3 ), ( c2 )
147 );
148 break;
149 }
150
151 case eulerOrder::ZXZ: // Z1-X2-Z3 rotation
152 {
153 return tensor
154 (
155 ( c1*c3 - c2*s1*s3 ), ( -c1*s3 - c2*c3*s1 ), ( s1*s2 ),
156 ( c3*s1 + c1*c2*s3 ), ( c1*c2*c3 - s1*s3 ), ( -c1*s2 ),
157 ( s2*s3 ), ( c3*s2 ), ( c2 )
158 );
159 break;
160 }
161
162
163 // Tait-Bryan angles
164
165 case eulerOrder::XZY: // X1-Z2-Y3 rotation
166 {
167 return tensor
168 (
169 ( c2*c3 ), ( -s2 ), ( c2*s3 ),
170 ( s1*s3 + c1*c3*s2 ), ( c1*c2 ), ( c1*s2*s3 - c3*s1 ),
171 ( c3*s1*s2 - c1*s3 ), ( c2*s1 ), ( c1*c3 + s1*s2*s3 )
172 );
173 break;
174 }
175
176 case eulerOrder::XYZ: // X1-Y2-Z3 rotation
177 {
178 return tensor
179 (
180 ( c2*c3 ), ( -c2*s3 ), ( s2 ),
181 ( c1*s3 + c3*s1*s2 ), ( c1*c3 - s1*s2*s3 ), ( -c2*s1 ),
182 ( s1*s3 - c1*c3*s2 ), ( c3*s1 + c1*s2*s3 ), ( c1*c2 )
183 );
184 break;
185 }
186
187 case eulerOrder::YXZ: // Y1-X2-Z3 rotation
188 {
189 return tensor
190 (
191 ( c1*c3 + s1*s2*s3 ), ( c3*s1*s2 - c1*s3 ), ( c2*s1 ),
192 ( c2*s3 ), ( c2*c3 ), ( -s2 ),
193 ( c1*s2*s3 - c3*s1 ), ( c1*c3*s2 + s1*s3 ), ( c1*c2 )
194 );
195 break;
196 }
197
198 case eulerOrder::YZX: // Y1-Z2-X3 rotation
199 {
200 return tensor
201 (
202 ( c1*c2 ), ( s1*s3 - c1*c3*s2 ), ( c3*s1 + c1*s2*s3 ),
203 ( s2 ), ( c2*c3 ), ( -c2*s3 ),
204 ( -c2*s1 ), ( c1*s3 + c3*s1*s2 ), ( c1*c3 - s1*s2*s3 )
205 );
206 break;
207 }
208
209 case eulerOrder::ZYX: // Z1-Y2-X3 rotation
210 {
211 return tensor
212 (
213 ( c1*c2 ), ( c1*s2*s3 - c3*s1 ), ( s1*s3 + c1*c3*s2 ),
214 ( c2*s1 ), ( c1*c3 + s1*s2*s3 ), ( c3*s1*s2 - c1*s3 ),
215 ( -s2 ), ( c2*s3 ), ( c2*c3 )
216 );
217 break;
218 }
219
220 case eulerOrder::ZXY: // Z1-X2-Y3 rotation
221 {
222 return tensor
223 (
224 ( c1*c3 - s1*s2*s3 ), ( -c2*s1 ), ( c1*s3 + c3*s1*s2 ),
225 ( c3*s1 + c1*s2*s3 ), ( c1*c2 ), ( s1*s3 - c1*c3*s2 ),
226 ( -c2*s3 ), ( s2 ), ( c2*c3 )
227 );
228 break;
229 }
230
231 default:
233 << "Unknown euler rotation order "
234 << int(order) << abort(FatalError);
235 }
236
237 return sphericalTensor::I; // identity rotation
238}
239
240
242(
243 const vector& angles,
244 bool degrees
245)
246{
247 return rotation(eulerOrder::ZXZ, angles, degrees);
248}
249
250
251// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
252
254:
256 angles_(Zero),
257 degrees_(true),
258 order_(eulerOrder::ZXZ)
259{}
260
261
263:
265 angles_(crot.angles_),
266 degrees_(crot.degrees_),
267 order_(crot.order_)
268{}
269
270
272(
273 const vector& angles,
274 bool degrees
275)
276:
278 angles_(angles),
279 degrees_(degrees),
280 order_(eulerOrder::ZXZ)
281{}
282
283
285(
286 scalar angle1,
287 scalar angle2,
288 scalar angle3,
289 bool degrees
290)
291:
293 angles_(angle1, angle2, angle3),
294 degrees_(degrees),
295 order_(eulerOrder::ZXZ)
296{}
297
298
300:
302 angles_(dict.get<vector>("angles")),
303 degrees_(dict.getOrDefault("degrees", true)),
304 order_
305 (
306 quaternion::eulerOrderNames.getOrDefault
307 (
308 "order",
309 dict,
311 )
312 )
313{}
314
315
316// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
317
319{
320 angles_ = Zero;
321 degrees_ = true;
322}
323
324
326{
327 return euler::rotation(order_, angles_, degrees_);
328}
329
330
332{
333 os << "euler-angles(" << (degrees_ ? "deg" : "rad") << "): " << angles_;
334}
335
336
338(
339 const word& keyword,
340 Ostream& os
341) const
342{
343 os.beginBlock(keyword);
344
345 os.writeEntry("type", type());
346 os.writeEntry("angles", angles_);
347 if (!degrees_)
348 {
349 os.writeEntry("degrees", "false");
350 }
351
352 // writeEntryIfDifferent, but with enumerated name
353 if (order_ != eulerOrder::ZXZ)
354 {
355 os.writeEntry("order", quaternion::eulerOrderNames[order_]);
356 }
357
358 os.endBlock();
359}
360
361
362// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
Macros for easy insertion into run-time selection tables.
#define addAliasToRunTimeSelectionTable(baseType, thisType, argNames, lookup, other, ver)
Add lookup alias for runTime selection.
#define addNamedToRunTimeSelectionTable(baseType, thisType, argNames, lookupName)
Add to construction table with 'lookupName' as the key.
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:62
static const SphericalTensor I
const Cmpt & z() const
Access to the vector z component.
Definition: VectorI.H:85
const Cmpt & y() const
Access to the vector y component.
Definition: VectorI.H:79
const Cmpt & x() const
Access to the vector x component.
Definition: VectorI.H:73
User specification of a coordinate rotation.
A coordinateRotation defined in the z-x-z (intrinsic) Euler convention.
virtual tensor R() const
The rotation tensor calculated for the specified Euler angles.
euler()
Default construct - an identity transform.
virtual void writeEntry(const word &keyword, Ostream &os) const
Write dictionary entry.
virtual void clear()
Reset specification.
virtual const coordinateRotation & rotation() const
The rotation specification.
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:126
virtual bool write()
Write the output fields.
Quaternion class used to perform rotations in 3D space.
Definition: quaternion.H:58
static const Enum< eulerOrder > eulerOrderNames
Definition: quaternion.H:118
eulerOrder
Euler-angle rotation order.
Definition: quaternion.H:104
A class for handling words, derived from Foam::string.
Definition: word.H:68
#define defineTypeName(Type)
Define the typeName.
Definition: className.H:96
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
OBJstream os(runTime.globalPath()/outputName)
Namespace for OpenFOAM.
dimensionedScalar sin(const dimensionedScalar &ds)
Tensor< scalar > tensor
Definition: symmTensor.H:61
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Definition: MSwindows.C:598
constexpr scalar degToRad() noexcept
Multiplication factor for degrees to radians conversion.
errorManip< error > abort(error &err)
Definition: errorManip.H:144
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
error FatalError
dimensionedScalar cos(const dimensionedScalar &ds)
dictionary dict
Unit conversion functions.