Ocean
Euler.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) Meta Platforms, Inc. and affiliates.
3  *
4  * This source code is licensed under the MIT license found in the
5  * LICENSE file in the root directory of this source tree.
6  */
7 
8 #ifndef META_OCEAN_MATH_EULER_H
9 #define META_OCEAN_MATH_EULER_H
10 
11 #include "ocean/math/Math.h"
12 #include "ocean/math/Numeric.h"
13 #include "ocean/math/Rotation.h"
15 
16 namespace Ocean
17 {
18 
19 // Forward declaration
20 template <typename T> class HomogenousMatrixT4;
21 // Forward declaration
22 template <typename T> class RotationT;
23 // Forward declaration
24 template <typename T> class QuaternionT;
25 // Forward declaration
26 template <typename T> class SquareMatrixT3;
27 
28 // Forward declaration.
29 template <typename T> class EulerT;
30 
31 /**
32  * Definition of the Euler object, depending on the OCEAN_MATH_USE_SINGLE_PRECISION either with single or double precision float data type.
33  * @see EulerT
34  * @ingroup math
35  */
37 
38 /**
39  * Instantiation of the EulerT template class using a double precision float data type.
40  * @see EulerT
41  * @ingroup math
42  */
44 
45 /**
46  * Instantiation of the EulerT template class using a single precision float data type.
47  * @see EulerT
48  * @ingroup math
49  */
51 
52 /**
53  * Definition of a typename alias for vectors with EulerT objects.
54  * @see EulerT
55  * @ingroup math
56  */
57 template <typename T>
58 using EulersT = std::vector<EulerT<T>>;
59 
60 /**
61  * Definition of a vector holding euler objects.
62  * @see Euler
63  * @ingroup math
64  */
65 typedef std::vector<Euler> Eulers;
66 
67 /**
68  * This class implements an euler rotation with angles: yaw, pitch and roll.
69  * The yaw angle is defined about the positive y-axis with range [-Pi, Pi].<br>
70  * The pitch angle is defined about the positive x-axis with range [-Pi/2, Pi/2].<br>
71  * The roll angle is defined about the positive z-axis with range [-Pi, Pi].<br>
72  * The entire rotation can be written as matrix product: Ry(yaw) * Rx(pitch) * Rz(roll).<br>
73  * All angles are defined in radian.
74  * @tparam T Data type of angle values_
75  * @see Euler, EulerF, EulerD, Rotation, Quaternion, SquareMatrix3, ExponentialMap.
76  * @ingroup math
77  */
78 template <typename T>
79 class EulerT
80 {
81  public:
82 
83  /**
84  * Definition of the used data type.
85  */
86  typedef T Type;
87 
88  public:
89 
90  /**
91  * Creates a new Euler rotation with all angles zero.
92  */
93  EulerT();
94 
95  /**
96  * Creates a new euler rotation by given angles.
97  * @param yaw The yaw angle with range [-Pi, Pi]
98  * @param pitch The pitch angle with range [-Pi/2, Pi/2]
99  * @param roll The roll angle with range [-Pi, Pi]
100  */
101  EulerT(const T yaw, const T pitch, const T roll);
102 
103  /**
104  * Creates a new euler rotation by an array of angles.
105  * @param arrayValue Array with three angles, with order yaw, pitch, roll, must be valid
106  */
107  explicit EulerT(const T* arrayValue);
108 
109  /**
110  * Creates a new euler rotation by a given homogeneous transformation.
111  * @param transformation The homogeneous transformation to create a euler rotation from
112  */
113  explicit EulerT(const HomogenousMatrixT4<T>& transformation);
114 
115  /**
116  * Creates a new euler rotation by a given angle-axis rotation.
117  * @param rotation Angle-axis rotation to create a euler rotation from
118  */
119  explicit EulerT(const RotationT<T>& rotation);
120 
121  /**
122  * Creates a new euler rotation by a given quaternion rotation.
123  * @param quaternion The quaternion rotation to create a euler rotation from
124  */
125  explicit EulerT(const QuaternionT<T>& quaternion);
126 
127  /**
128  * Creates a new euler rotation by a given 3x3 matrix rotation.
129  * @param matrix The rotation matrix to create a euler rotation from
130  */
131  explicit EulerT(const SquareMatrixT3<T>& matrix);
132 
133  /**
134  * Returns the yaw angle.
135  * @return Yaw angle in radian
136  */
137  inline const T& yaw() const;
138 
139  /**
140  * Returns the yaw angle.
141  * @return Yaw angle in radian
142  */
143  inline T& yaw();
144 
145  /**
146  * Returns the pitch angle.
147  * @return Pitch angle in radian
148  */
149  inline const T& pitch() const;
150 
151  /**
152  * Returns the pitch angle.
153  * @return Pitch angle in radian
154  */
155  inline T& pitch();
156 
157  /**
158  * Returns the roll angle.
159  * @return Roll angle in radian
160  */
161  inline const T& roll() const;
162 
163  /**
164  * Returns the roll angle.
165  * @return Roll angle in radian
166  */
167  inline T& roll();
168 
169  /**
170  * Returns whether the euler rotation holds valid parameters.
171  * @return True, if so
172  */
173  bool isValid() const;
174 
175  /**
176  * Returns whether two euler rotations are identical up to a small epsilon.
177  * @param euler Right euler rotation
178  * @return True, if so
179  */
180  bool operator==(const EulerT<T>& euler) const;
181 
182  /**
183  * Returns whether two euler rotations are not identical up to a small epsilon.
184  * @param euler Right euler rotation
185  * @return True, if so
186  */
187  inline bool operator!=(const EulerT<T>& euler) const;
188 
189  /**
190  * Element access operator.
191  * @param index The index of the element to access, with range [0, 2]
192  * @return Element of the euler rotation
193  */
194  inline const T& operator[](const unsigned int index) const;
195 
196  /**
197  * Element access operator.
198  * @param index The index of the element to access, with range [0, 2]
199  * @return Element of the euler rotation
200  */
201  inline T& operator[](const unsigned int index);
202 
203  /**
204  * Element access operator.
205  * @param index The index of the element to access, with range [0, 2]
206  * @return Element of the euler rotation
207  */
208  inline const T& operator()(const unsigned int index) const;
209 
210  /**
211  * Element access operator.
212  * @param index The index of the element to access, with range [0, 2]
213  * @return Element of the euler rotation
214  */
215  inline T& operator()(const unsigned int index);
216 
217  /**
218  * Access operator.
219  * @return Pointer to the elements
220  */
221  inline const T* operator()() const;
222 
223  /**
224  * Access operator.
225  * @return Pointer to the elements
226  */
227  inline T* operator()();
228 
229  /**
230  * Decomposes a 3x3 rotation matrix to the corresponding yaw, pitch and roll angles as defined by the euler class.
231  * The provided rotation matrix can be recreated by the matrix product: Ry(yAngle) * Rx(xAngle) * Rz(zAngle).
232  * @param matrix The 3x3 square matrix to decompose, must be an orthonormal rotation matrix
233  * @param yAngle The resulting (yaw) angle (rotation around the y-axis), with range [-PI, PI]
234  * @param xAngle The resulting (pitch) angle (rotation around the x-axis), with range [-PI/2, PI/2]
235  * @param zAngle The resulting (roll) angle (rotation around the z-axis), with range [-PI, PI]
236  */
237  static void decomposeRotationMatrixToYXZ(const SquareMatrixT3<T>& matrix, T& yAngle, T& xAngle, T& zAngle);
238 
239  /**
240  * Decomposes a 3x3 rotation matrix to the corresponding x, y and z angles.
241  * The provided rotation matrix can be recreated by the matrix product: Rx(xAngle) * Ry(yAngle) * Rz(zAngle).
242  * @param matrix The 3x3 square matrix to decompose, must be an orthonormal rotation matrix
243  * @param xAngle The resulting x angle (rotation around the x-axis), with range [-PI, PI]
244  * @param yAngle The resulting y angle (rotation around the y-axis), with range [-PI/2, PI/2]
245  * @param zAngle The resulting z angle (rotation around the z-axis), with range [-PI, PI]
246  */
247  static void decomposeRotationMatrixToXYZ(const SquareMatrixT3<T>& matrix, T& xAngle, T& yAngle, T& zAngle);
248 
249  /**
250  * Adjusts euler angles with arbitrary value (e.g., outside the valid value range) to euler angles within the value range of a valid Euler object.
251  * @param yaw The yaw angle to be adjusted, in radian, afterwards will be in the value range of [-PI, PI], with range (-infinity, infinity)
252  * @param pitch The pitch angle to be adjusted, in radian, afterwards will be in the value range of [-PI/2, PI/2], with range (-infinity, infinity)
253  * @param roll The roll angle to be adjusted, in radian, afterwards will be in the value range of [-PI, PI], with range (-infinity, infinity)
254  */
255  static void adjustAngles(T& yaw, T& pitch, T& roll);
256 
257  protected:
258 
259  /// The three angles of the euler rotation.
260  T values_[3];
261 };
262 
263 template <typename T>
265 {
266  values_[0] = T(0);
267  values_[1] = T(0);
268  values_[2] = T(0);
269 }
270 
271 template <typename T>
272 EulerT<T>::EulerT(const T yaw, const T pitch, const T roll)
273 {
274  values_[0] = yaw;
275  values_[1] = pitch;
276  values_[2] = roll;
277 }
278 
279 template <typename T>
280 EulerT<T>::EulerT(const T* arrayValue)
281 {
282  ocean_assert(arrayValue);
283  memcpy(values_, arrayValue, sizeof(T) * 3);
284 }
285 
286 template <typename T>
288 {
289  decomposeRotationMatrixToYXZ(transformation.orthonormalRotationMatrix(), values_[0], values_[1], values_[2]);
290  ocean_assert(isValid());
291 }
292 
293 template <typename T>
295 {
296  decomposeRotationMatrixToYXZ(SquareMatrixT3<T>(rotation), values_[0], values_[1], values_[2]);
297  ocean_assert(isValid());
298 }
299 
300 template <typename T>
302 {
303  decomposeRotationMatrixToYXZ(SquareMatrixT3<T>(quaternion), values_[0], values_[1], values_[2]);
304  ocean_assert(isValid());
305 }
306 
307 template <typename T>
309 {
310  decomposeRotationMatrixToYXZ(matrix, values_[0], values_[1], values_[2]);
311  ocean_assert(isValid());
312 }
313 
314 template <typename T>
315 inline const T& EulerT<T>::yaw() const
316 {
317  return values_[0];
318 }
319 
320 template <typename T>
321 inline T& EulerT<T>::yaw()
322 {
323  return values_[0];
324 }
325 
326 template <typename T>
327 inline const T& EulerT<T>::pitch() const
328 {
329  return values_[1];
330 }
331 
332 template <typename T>
333 inline T& EulerT<T>::pitch()
334 {
335  return values_[1];
336 }
337 
338 template <typename T>
339 inline const T& EulerT<T>::roll() const
340 {
341  return values_[2];
342 }
343 
344 template <typename T>
345 inline T& EulerT<T>::roll()
346 {
347  return values_[2];
348 }
349 
350 template <typename T>
351 bool EulerT<T>::isValid() const
352 {
356 }
357 
358 template <typename T>
359 bool EulerT<T>::operator==(const EulerT<T>& euler) const
360 {
361  return NumericT<T>::isEqual(values_[0], euler.values_[0]) && NumericT<T>::isEqual(values_[1], euler.values_[1]) && NumericT<T>::isEqual(values_[2], euler.values_[2]);
362 }
363 
364 template <typename T>
365 inline bool EulerT<T>::operator!=(const EulerT<T>& euler) const
366 {
367  return !(*this == euler);
368 }
369 
370 template <typename T>
371 inline const T& EulerT<T>::operator[](const unsigned int index) const
372 {
373  ocean_assert(index < 3u);
374  return values_[index];
375 }
376 
377 template <typename T>
378 inline T& EulerT<T>::operator[](const unsigned int index)
379 {
380  ocean_assert(index < 3u);
381  return values_[index];
382 }
383 
384 template <typename T>
385 inline const T& EulerT<T>::operator()(const unsigned int index) const
386 {
387  ocean_assert(index < 3u);
388  return values_[index];
389 }
390 
391 template <typename T>
392 inline T& EulerT<T>::operator()(const unsigned int index)
393 {
394  ocean_assert(index < 3u);
395  return values_[index];
396 }
397 
398 template <typename T>
399 inline const T* EulerT<T>::operator()() const
400 {
401  return values_;
402 }
403 
404 template <typename T>
406 {
407  return values_;
408 }
409 
410 template <typename T>
411 void EulerT<T>::decomposeRotationMatrixToYXZ(const SquareMatrixT3<T>& matrix, T& yAngle, T& xAngle, T& zAngle)
412 {
413  ocean_assert(matrix.isOrthonormal());
414 
415  /**
416  * Combined rotation matrix for R(y)R(x)R(z)
417  * [ cy cz + sx sy sz cz sx sy - cy sz cx sy ]
418  * [ cx sz cx cz -sx ]
419  * [ -cz sy + cy sx sz cy cz sx + sy sz cx cy ]
420  */
421 
422  if (matrix(1, 2) > T(-1) + NumericT<T>::eps())
423  {
424  if (matrix(1, 2) < T(1) - NumericT<T>::eps())
425  {
426  // we have the normal case without any extreme angles
427 
428  xAngle = NumericT<T>::asin(-matrix(1, 2));
429 
430  ocean_assert(NumericT<T>::isNotEqualEps(matrix(0, 2)) || NumericT<T>::isNotEqualEps(matrix(2, 2)));
431  yAngle = NumericT<T>::atan2(matrix(0, 2), matrix(2, 2));
432 
433  ocean_assert(NumericT<T>::isNotEqualEps(matrix(1, 0)) || NumericT<T>::isNotEqualEps(matrix(1, 1)));
434  zAngle = NumericT<T>::atan2(matrix(1, 0), matrix(1, 1));
435  }
436  else
437  {
438  // we have a special case where sx == -1
439  ocean_assert((std::is_same<float, T>::value) ? NumericT<T>::isWeakEqual(matrix(1, 2), 1) : NumericT<T>::isEqual(matrix(1, 2), 1));
440 
441  /**
442  * Combined rotation matrix for R(y)R(x)R(z), with sx == -1 and cx == 0
443  * [ cy cz - sy sz - cz sy - cy sz 0 ] [ cos(y + z) -sin(y + z) 0 ]
444  * [ 0 0 -1 ] = [ 0 0 -1 ]
445  * [ -cz sy - cy sz - cy cz + sy sz 0 ] [ -sin(y + z) -cos(y + z) 0 ]
446  */
447 
448  // tan(y + z) = sin(y + z) / cos(y + z), z == 0
449 
450  yAngle = NumericT<T>::atan2(-matrix(0, 1), -matrix(2, 1));
451  xAngle = -NumericT<T>::pi_2();
452  zAngle = T(0.0);
453  }
454  }
455  else
456  {
457  // we have a special case where sx == 1
458  ocean_assert((std::is_same<float, T>::value) ? NumericT<T>::isWeakEqual(matrix(1, 2), -1) : NumericT<T>::isEqual(matrix(1, 2), -1));
459 
460  /**
461  * Combined rotation matrix for R(y)R(x)R(z), with sx == 1 and cx == 0
462  * [ cy cz + sy sz cz sy - cy sz 0 ] [ cos(y - z) sin(y - z) 0 ]
463  * [ 0 0 -1 ] = [ 0 0 -1 ]
464  * [ -cz sy + cy sz cy cz + sy sz 0 ] [ sin(z - y) cos(y - z) 0 ]
465  */
466 
467  // tan(y - z) = sin(y - z) / cos(y - z), z == 0
468 
469  yAngle = NumericT<T>::atan2(matrix(0, 1), matrix(2, 1));
470  xAngle = NumericT<T>::pi_2();
471  zAngle = T(0.0);
472  }
473 
474  ocean_assert(NumericT<T>::isInsideRange(-NumericT<T>::pi(), yAngle, NumericT<T>::pi()));
476  ocean_assert(NumericT<T>::isInsideRange(-NumericT<T>::pi(), zAngle, NumericT<T>::pi()));
477 }
478 
479 template <typename T>
480 void EulerT<T>::decomposeRotationMatrixToXYZ(const SquareMatrixT3<T>& matrix, T& xAngle, T& yAngle, T& zAngle)
481 {
482  ocean_assert(matrix.isOrthonormal());
483 
484  /**
485  * Combined rotation matrix for R(x)R(y)R(z)
486  * [ cy cz -cy sz sy ]
487  * [ cx sz + sx sy cz cx cz - sx sy sz -sx cy ]
488  * [ sx sz - cx sy cz sx cz + cx sy sz cx cy ]
489  */
490 
491  if (matrix(0, 2) < T(1) - NumericT<T>::eps())
492  {
493  if (matrix(0, 2) > T(-1) + NumericT<T>::eps())
494  {
495  // we have the normal case without any extreme angles
496 
497  ocean_assert(NumericT<T>::isNotEqualEps(matrix(1, 2)) || NumericT<T>::isNotEqualEps(matrix(2, 2)));
498  xAngle = NumericT<T>::atan2(-matrix(1, 2), matrix(2, 2));
499 
500  yAngle = NumericT<T>::asin(matrix(0, 2));
501 
502  ocean_assert(NumericT<T>::isNotEqualEps(matrix(0, 1)) || NumericT<T>::isNotEqualEps(matrix(0, 0)));
503  zAngle = NumericT<T>::atan2(-matrix(0, 1), matrix(0, 0));
504  }
505  else
506  {
507  // we have a special case where sx == -1
508  ocean_assert((std::is_same<float, T>::value) ? NumericT<T>::isWeakEqual(matrix(0, 2), -1) : NumericT<T>::isEqual(matrix(0, 2), -1));
509 
510  /**
511  * Combined rotation matrix for R(x)R(y)R(z), with sy == -1 and cy == 0
512  * [ 0 0 1 ] [ 0 0 1 ]
513  * [ cx sz - sx cz cx cz + sx sz 0 ] = [ -sin(x - z) cos(x - z) 0 ]
514  * [ sx sz + cx cz sx cz - cx sz 0 ] [ cos(x - z) sin(x - z) 0 ]
515  */
516 
517  // tan(x - z) = sin(x - z) / cos(x - z), z == 0
518 
519  xAngle = NumericT<T>::atan2(matrix(2, 1), matrix(1, 1));
520  yAngle = -NumericT<T>::pi_2();
521  zAngle = T(0.0);
522  }
523  }
524  else
525  {
526  // we have a special case where sy == 1
527  ocean_assert((std::is_same<float, T>::value) ? NumericT<T>::isWeakEqual(matrix(0, 2), 1) : NumericT<T>::isEqual(matrix(0, 2), 1));
528 
529  /**
530  * Combined rotation matrix for R(x)R(y)R(z), with sy == 1 and cy == 0
531  * [ 0 0 1 ] [ 0 0 1 ]
532  * [ cx sz + sx cz cx cz - sx sz 0 ] = [ sin(x + z) cos(x + z) 0 ]
533  * [ sx sz - cx cz sx cz + cx sz 0 ] [ -cos(x + z) sin(x + z) 0 ]
534  */
535 
536  // tan(x + z) = sin(x + z) / cos(x + z), z == 0
537 
538  xAngle = NumericT<T>::atan2(matrix(1, 0), matrix(1, 1));
539  yAngle = NumericT<T>::pi_2();
540  zAngle = T(0.0);
541  }
542 
543  ocean_assert(NumericT<T>::isInsideRange(-NumericT<T>::pi(), xAngle, NumericT<T>::pi()));
545  ocean_assert(NumericT<T>::isInsideRange(-NumericT<T>::pi(), zAngle, NumericT<T>::pi()));
546 }
547 
548 template <typename T>
549 void EulerT<T>::adjustAngles(T& yaw, T& pitch, T& roll)
550 {
551  pitch = NumericT<T>::angleAdjustNull(pitch);
552 
553  if (NumericT<T>::abs(pitch) > NumericT<T>::pi_2())
554  {
555  pitch = NumericT<T>::copySign(NumericT<T>::pi(), pitch) - pitch;
556  yaw += NumericT<T>::pi();
557  roll += NumericT<T>::pi();
558  }
559 
560  yaw = NumericT<T>::angleAdjustNull(yaw);
561  roll = NumericT<T>::angleAdjustNull(roll);
562 
563  ocean_assert(Euler(yaw, pitch, roll).isValid());
564 }
565 
566 }
567 
568 #endif // META_OCEAN_MATH_EULER_H
This class implements an euler rotation with angles: yaw, pitch and roll.
Definition: Euler.h:80
EulerT()
Creates a new Euler rotation with all angles zero.
Definition: Euler.h:264
static void decomposeRotationMatrixToXYZ(const SquareMatrixT3< T > &matrix, T &xAngle, T &yAngle, T &zAngle)
Decomposes a 3x3 rotation matrix to the corresponding x, y and z angles.
Definition: Euler.h:480
const T & yaw() const
Returns the yaw angle.
Definition: Euler.h:315
const T * operator()() const
Access operator.
Definition: Euler.h:399
T values_[3]
The three angles of the euler rotation.
Definition: Euler.h:260
const T & operator[](const unsigned int index) const
Element access operator.
Definition: Euler.h:371
const T & roll() const
Returns the roll angle.
Definition: Euler.h:339
bool operator!=(const EulerT< T > &euler) const
Returns whether two euler rotations are not identical up to a small epsilon.
Definition: Euler.h:365
static void decomposeRotationMatrixToYXZ(const SquareMatrixT3< T > &matrix, T &yAngle, T &xAngle, T &zAngle)
Decomposes a 3x3 rotation matrix to the corresponding yaw, pitch and roll angles as defined by the eu...
Definition: Euler.h:411
bool isValid() const
Returns whether the euler rotation holds valid parameters.
Definition: Euler.h:351
T Type
Definition of the used data type.
Definition: Euler.h:86
const T & pitch() const
Returns the pitch angle.
Definition: Euler.h:327
static void adjustAngles(T &yaw, T &pitch, T &roll)
Adjusts euler angles with arbitrary value (e.g., outside the valid value range) to euler angles withi...
Definition: Euler.h:549
bool operator==(const EulerT< T > &euler) const
Returns whether two euler rotations are identical up to a small epsilon.
Definition: Euler.h:359
This class implements a 4x4 homogeneous transformation matrix using floating point values with the pr...
Definition: HomogenousMatrix4.h:110
SquareMatrixT3< T > orthonormalRotationMatrix() const
Returns the 3x3 orthonormal rotation matrix of the 4x4 transformation (by forcing a orthogonal and no...
Definition: HomogenousMatrix4.h:1538
This class provides basic numeric functionalities.
Definition: Numeric.h:57
static constexpr bool isInsideRange(const T lower, const T value, const T upper, const T epsilon=NumericT< T >::eps())
Returns whether a value lies between a given range up to a provided epsilon border.
Definition: Numeric.h:2872
static constexpr T pi_2()
Returns PI/2 which is equivalent to 90 degree.
Definition: Numeric.h:938
static T atan2(const T y, const T x)
Returns the arctangent of a given value in radian.
Definition: Numeric.h:1632
static constexpr T pi()
Returns PI which is equivalent to 180 degree.
Definition: Numeric.h:926
static T angleAdjustNull(const T angle)
Adjusts an arbitrary angle into the range of (-PI, PI].
Definition: Numeric.h:1794
static bool isEqual(const T first, const T second)
Returns whether two values are equal up to a small epsilon.
Definition: Numeric.h:2386
static constexpr T copySign(const T signReceiver, const T signProvider)
Copies the sign of a given value to another one.
Definition: Numeric.h:3264
static T asin(const T value)
Returns the arcsine of a given value.
Definition: Numeric.h:2887
This class implements a unit quaternion rotation.
Definition: Quaternion.h:100
This class implements a axis-angle rotation using floating point values.
Definition: Rotation.h:79
This class implements a 3x3 square matrix.
Definition: SquareMatrix3.h:88
bool isOrthonormal(const T epsilon=NumericT< T >::eps()) const
Returns whether this matrix is an orthonormal matrix.
Definition: SquareMatrix3.h:1365
EulerT< float > EulerF
Instantiation of the EulerT template class using a single precision float data type.
Definition: Euler.h:50
EulerT< Scalar > Euler
Definition of the Euler object, depending on the OCEAN_MATH_USE_SINGLE_PRECISION either with single o...
Definition: Euler.h:29
std::vector< Euler > Eulers
Definition of a vector holding euler objects.
Definition: Euler.h:65
EulerT< double > EulerD
Instantiation of the EulerT template class using a double precision float data type.
Definition: Euler.h:43
std::vector< EulerT< T > > EulersT
Definition of a typename alias for vectors with EulerT objects.
Definition: Euler.h:58
The namespace covering the entire Ocean framework.
Definition: Accessor.h:15