• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Based on Ken Shoemake. 1994. Euler angle conversion. Graphics gems IV.  Academic Press
2 // Professional, Inc., USA, 222–229.
3 use crate::{DMat3, DMat4, DQuat, DVec3, Mat3, Mat3A, Mat4, Quat, Vec3, Vec3A, Vec3Swizzles};
4 
5 /// Euler rotation sequences.
6 ///
7 /// The three elemental rotations may be extrinsic (rotations about the axes xyz of the original
8 /// coordinate system, which is assumed to remain motionless), or intrinsic(rotations about the
9 /// axes of the rotating coordinate system XYZ, solidary with the moving body, which changes its
10 /// orientation after each elemental rotation).
11 ///
12 /// ```
13 /// # use glam::{EulerRot, Mat3};
14 /// # let i = core::f32::consts::FRAC_PI_2;
15 /// # let j = core::f32::consts::FRAC_PI_4;
16 /// # let k = core::f32::consts::FRAC_PI_8;
17 /// let m_intrinsic = Mat3::from_rotation_x(i) * Mat3::from_rotation_y(j) * Mat3::from_rotation_z(k);
18 /// let n_intrinsic = Mat3::from_euler(EulerRot::XYZ, i, j, k);
19 /// assert!(m_intrinsic.abs_diff_eq(n_intrinsic, 2e-6));
20 ///
21 /// let m_extrinsic = Mat3::from_rotation_z(k) * Mat3::from_rotation_y(j) * Mat3::from_rotation_x(i);
22 /// let n_extrinsic = Mat3::from_euler(EulerRot::XYZEx, i, j, k);
23 /// assert!(m_extrinsic.abs_diff_eq(n_extrinsic, 2e-6));
24 /// ```
25 ///
26 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
27 pub enum EulerRot {
28     /// Intrinsic three-axis rotation ZYX
29     ZYX,
30     /// Intrinsic three-axis rotation ZXY
31     ZXY,
32     /// Intrinsic three-axis rotation YXZ
33     YXZ,
34     /// Intrinsic three-axis rotation YZX
35     YZX,
36     /// Intrinsic three-axis rotation XYZ
37     XYZ,
38     /// Intrinsic three-axis rotation XZY
39     XZY,
40 
41     /// Intrinsic two-axis rotation ZYZ
42     ZYZ,
43     /// Intrinsic two-axis rotation ZXZ
44     ZXZ,
45     /// Intrinsic two-axis rotation YXY
46     YXY,
47     /// Intrinsic two-axis rotation YZY
48     YZY,
49     /// Intrinsic two-axis rotation XYX
50     XYX,
51     /// Intrinsic two-axis rotation XZX
52     XZX,
53 
54     /// Extrinsic three-axis rotation ZYX
55     ZYXEx,
56     /// Extrinsic three-axis rotation ZXY
57     ZXYEx,
58     /// Extrinsic three-axis rotation YXZ
59     YXZEx,
60     /// Extrinsic three-axis rotation YZX
61     YZXEx,
62     /// Extrinsic three-axis rotation XYZ
63     XYZEx,
64     /// Extrinsic three-axis rotation XZY
65     XZYEx,
66 
67     /// Extrinsic two-axis rotation ZYZ
68     ZYZEx,
69     /// Extrinsic two-axis rotation ZXZ
70     ZXZEx,
71     /// Extrinsic two-axis rotation YXY
72     YXYEx,
73     /// Extrinsic two-axis rotation YZY
74     YZYEx,
75     /// Extrinsic two-axis rotation XYX
76     XYXEx,
77     /// Extrinsic two-axis rotation XZX
78     XZXEx,
79 }
80 
81 impl Default for EulerRot {
82     /// Default `YXZ` as yaw (y-axis), pitch (x-axis), roll (z-axis).
default() -> Self83     fn default() -> Self {
84         Self::YXZ
85     }
86 }
87 
88 pub(crate) trait ToEuler {
89     type Scalar;
to_euler_angles(self, order: EulerRot) -> (Self::Scalar, Self::Scalar, Self::Scalar)90     fn to_euler_angles(self, order: EulerRot) -> (Self::Scalar, Self::Scalar, Self::Scalar);
91 }
92 
93 pub(crate) trait FromEuler {
94     type Scalar;
from_euler_angles( order: EulerRot, i: Self::Scalar, j: Self::Scalar, k: Self::Scalar, ) -> Self95     fn from_euler_angles(
96         order: EulerRot,
97         i: Self::Scalar,
98         j: Self::Scalar,
99         k: Self::Scalar,
100     ) -> Self;
101 }
102 
103 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
104 enum Axis {
105     X = 0,
106     Y = 1,
107     Z = 2,
108 }
109 
110 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
111 enum Parity {
112     Odd = 0,
113     Even = 1,
114 }
115 
116 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
117 enum Repeated {
118     No = 0,
119     Yes = 1,
120 }
121 
122 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
123 enum Frame {
124     Relative = 0,
125     Static = 1,
126 }
127 
128 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
129 struct Order {
130     initial_axis: Axis,
131     parity_even: bool,
132     initial_repeated: bool,
133     frame_static: bool,
134 }
135 
136 impl Order {
new( initial_axis: Axis, parity: Parity, initial_repeated: Repeated, frame: Frame, ) -> Self137     const fn new(
138         initial_axis: Axis,
139         parity: Parity,
140         initial_repeated: Repeated,
141         frame: Frame,
142     ) -> Self {
143         Self {
144             initial_axis,
145             parity_even: parity as u32 == Parity::Even as u32,
146             initial_repeated: initial_repeated as u32 == Repeated::Yes as u32,
147             frame_static: frame as u32 == Frame::Static as u32,
148         }
149     }
150 
from_euler(euler: EulerRot) -> Self151     const fn from_euler(euler: EulerRot) -> Self {
152         match euler {
153             EulerRot::XYZ => Self::new(Axis::X, Parity::Even, Repeated::No, Frame::Static),
154             EulerRot::XYX => Self::new(Axis::X, Parity::Even, Repeated::Yes, Frame::Static),
155             EulerRot::XZY => Self::new(Axis::X, Parity::Odd, Repeated::No, Frame::Static),
156             EulerRot::XZX => Self::new(Axis::X, Parity::Odd, Repeated::Yes, Frame::Static),
157             EulerRot::YZX => Self::new(Axis::Y, Parity::Even, Repeated::No, Frame::Static),
158             EulerRot::YZY => Self::new(Axis::Y, Parity::Even, Repeated::Yes, Frame::Static),
159             EulerRot::YXZ => Self::new(Axis::Y, Parity::Odd, Repeated::No, Frame::Static),
160             EulerRot::YXY => Self::new(Axis::Y, Parity::Odd, Repeated::Yes, Frame::Static),
161             EulerRot::ZXY => Self::new(Axis::Z, Parity::Even, Repeated::No, Frame::Static),
162             EulerRot::ZXZ => Self::new(Axis::Z, Parity::Even, Repeated::Yes, Frame::Static),
163             EulerRot::ZYX => Self::new(Axis::Z, Parity::Odd, Repeated::No, Frame::Static),
164             EulerRot::ZYZ => Self::new(Axis::Z, Parity::Odd, Repeated::Yes, Frame::Static),
165             EulerRot::ZYXEx => Self::new(Axis::X, Parity::Even, Repeated::No, Frame::Relative),
166             EulerRot::XYXEx => Self::new(Axis::X, Parity::Even, Repeated::Yes, Frame::Relative),
167             EulerRot::YZXEx => Self::new(Axis::X, Parity::Odd, Repeated::No, Frame::Relative),
168             EulerRot::XZXEx => Self::new(Axis::X, Parity::Odd, Repeated::Yes, Frame::Relative),
169             EulerRot::XZYEx => Self::new(Axis::Y, Parity::Even, Repeated::No, Frame::Relative),
170             EulerRot::YZYEx => Self::new(Axis::Y, Parity::Even, Repeated::Yes, Frame::Relative),
171             EulerRot::ZXYEx => Self::new(Axis::Y, Parity::Odd, Repeated::No, Frame::Relative),
172             EulerRot::YXYEx => Self::new(Axis::Y, Parity::Odd, Repeated::Yes, Frame::Relative),
173             EulerRot::YXZEx => Self::new(Axis::Z, Parity::Even, Repeated::No, Frame::Relative),
174             EulerRot::ZXZEx => Self::new(Axis::Z, Parity::Even, Repeated::Yes, Frame::Relative),
175             EulerRot::XYZEx => Self::new(Axis::Z, Parity::Odd, Repeated::No, Frame::Relative),
176             EulerRot::ZYZEx => Self::new(Axis::Z, Parity::Odd, Repeated::Yes, Frame::Relative),
177         }
178     }
179 
next_axis(i: usize) -> usize180     const fn next_axis(i: usize) -> usize {
181         (i + 1) % 3
182     }
183 
prev_axis(i: usize) -> usize184     const fn prev_axis(i: usize) -> usize {
185         if i > 0 {
186             i - 1
187         } else {
188             2
189         }
190     }
191 
angle_order(self) -> (usize, usize, usize)192     const fn angle_order(self) -> (usize, usize, usize) {
193         let i = self.initial_axis as usize;
194         let j = if self.parity_even {
195             Order::next_axis(i)
196         } else {
197             Order::prev_axis(i)
198         };
199         let k = if self.parity_even {
200             Order::prev_axis(i)
201         } else {
202             Order::next_axis(i)
203         };
204         (i, j, k)
205     }
206 }
207 
208 macro_rules! impl_mat3_from_euler {
209     ($scalar:ident, $mat3:ident, $vec3:ident) => {
210         impl FromEuler for $mat3 {
211             type Scalar = $scalar;
212             fn from_euler_angles(
213                 euler: EulerRot,
214                 x: Self::Scalar,
215                 y: Self::Scalar,
216                 z: Self::Scalar,
217             ) -> Self {
218                 use crate::$scalar::math;
219 
220                 let order = Order::from_euler(euler);
221                 let (i, j, k) = order.angle_order();
222 
223                 let mut angles = if order.frame_static {
224                     $vec3::new(x, y, z)
225                 } else {
226                     $vec3::new(z, y, x)
227                 };
228 
229                 // rotation direction is reverse from original paper
230                 if order.parity_even {
231                     angles = -angles;
232                 }
233 
234                 let (si, ci) = math::sin_cos(angles.x);
235                 let (sj, cj) = math::sin_cos(angles.y);
236                 let (sh, ch) = math::sin_cos(angles.z);
237 
238                 let cc = ci * ch;
239                 let cs = ci * sh;
240                 let sc = si * ch;
241                 let ss = si * sh;
242 
243                 let mut m = [[0.0; 3]; 3];
244 
245                 if order.initial_repeated {
246                     m[i][i] = cj;
247                     m[i][j] = sj * si;
248                     m[i][k] = sj * ci;
249                     m[j][i] = sj * sh;
250                     m[j][j] = -cj * ss + cc;
251                     m[j][k] = -cj * cs - sc;
252                     m[k][i] = -sj * ch;
253                     m[k][j] = cj * sc + cs;
254                     m[k][k] = cj * cc - ss;
255                 } else {
256                     m[i][i] = cj * ch;
257                     m[i][j] = sj * sc - cs;
258                     m[i][k] = sj * cc + ss;
259                     m[j][i] = cj * sh;
260                     m[j][j] = sj * ss + cc;
261                     m[j][k] = sj * cs - sc;
262                     m[k][i] = -sj;
263                     m[k][j] = cj * si;
264                     m[k][k] = cj * ci;
265                 }
266 
267                 $mat3::from_cols_array_2d(&m)
268             }
269         }
270     };
271 }
272 
273 macro_rules! impl_mat4_from_euler {
274     ($scalar:ident, $mat4:ident, $mat3:ident) => {
275         impl FromEuler for $mat4 {
276             type Scalar = $scalar;
277             fn from_euler_angles(
278                 euler: EulerRot,
279                 x: Self::Scalar,
280                 y: Self::Scalar,
281                 z: Self::Scalar,
282             ) -> Self {
283                 $mat4::from_mat3($mat3::from_euler_angles(euler, x, y, z))
284             }
285         }
286     };
287 }
288 
289 macro_rules! impl_quat_from_euler {
290     ($scalar:ident, $quat:ident, $vec3:ident) => {
291         impl FromEuler for $quat {
292             type Scalar = $scalar;
293             fn from_euler_angles(
294                 euler: EulerRot,
295                 x: Self::Scalar,
296                 y: Self::Scalar,
297                 z: Self::Scalar,
298             ) -> Self {
299                 use crate::$scalar::math;
300 
301                 let order = Order::from_euler(euler);
302                 let (i, j, k) = order.angle_order();
303 
304                 let mut angles = if order.frame_static {
305                     $vec3::new(x, y, z)
306                 } else {
307                     $vec3::new(z, y, x)
308                 };
309 
310                 if order.parity_even {
311                     angles.y = -angles.y;
312                 }
313 
314                 let ti = angles.x * 0.5;
315                 let tj = angles.y * 0.5;
316                 let th = angles.z * 0.5;
317                 let (si, ci) = math::sin_cos(ti);
318                 let (sj, cj) = math::sin_cos(tj);
319                 let (sh, ch) = math::sin_cos(th);
320                 let cc = ci * ch;
321                 let cs = ci * sh;
322                 let sc = si * ch;
323                 let ss = si * sh;
324 
325                 let parity = if !order.parity_even { 1.0 } else { -1.0 };
326 
327                 let mut a = [0.0; 4];
328 
329                 if order.initial_repeated {
330                     a[i] = cj * (cs + sc);
331                     a[j] = sj * (cc + ss) * parity;
332                     a[k] = sj * (cs - sc);
333                     a[3] = cj * (cc - ss);
334                 } else {
335                     a[i] = cj * sc - sj * cs;
336                     a[j] = (cj * ss + sj * cc) * parity;
337                     a[k] = cj * cs - sj * sc;
338                     a[3] = cj * cc + sj * ss;
339                 }
340 
341                 $quat::from_array(a)
342             }
343         }
344     };
345 }
346 
347 macro_rules! impl_mat3_to_euler {
348     ($scalar:ident, $mat3:ident, $vec3:ident) => {
349         impl ToEuler for $mat3 {
350             type Scalar = $scalar;
351             fn to_euler_angles(
352                 self,
353                 euler: EulerRot,
354             ) -> (Self::Scalar, Self::Scalar, Self::Scalar) {
355                 use crate::$scalar::math;
356 
357                 let order = Order::from_euler(euler);
358                 let (i, j, k) = order.angle_order();
359 
360                 let mut ea = $vec3::ZERO;
361                 if order.initial_repeated {
362                     let sy = math::sqrt(
363                         self.col(i)[j] * self.col(i)[j] + self.col(i)[k] * self.col(i)[k],
364                     );
365                     if (sy > 16.0 * $scalar::EPSILON) {
366                         ea.x = math::atan2(self.col(i)[j], self.col(i)[k]);
367                         ea.y = math::atan2(sy, self.col(i)[i]);
368                         ea.z = math::atan2(self.col(j)[i], -self.col(k)[i]);
369                     } else {
370                         ea.x = math::atan2(-self.col(j)[k], self.col(j)[j]);
371                         ea.y = math::atan2(sy, self.col(i)[i]);
372                     }
373                 } else {
374                     let cy = math::sqrt(
375                         self.col(i)[i] * self.col(i)[i] + self.col(j)[i] * self.col(j)[i],
376                     );
377                     if (cy > 16.0 * $scalar::EPSILON) {
378                         ea.x = math::atan2(self.col(k)[j], self.col(k)[k]);
379                         ea.y = math::atan2(-self.col(k)[i], cy);
380                         ea.z = math::atan2(self.col(j)[i], self.col(i)[i]);
381                     } else {
382                         ea.x = math::atan2(-self.col(j)[k], self.col(j)[j]);
383                         ea.y = math::atan2(-self.col(k)[i], cy);
384                     }
385                 }
386 
387                 // reverse rotation angle of original code
388                 if order.parity_even {
389                     ea = -ea;
390                 }
391 
392                 if !order.frame_static {
393                     ea = ea.zyx();
394                 }
395 
396                 (ea.x, ea.y, ea.z)
397             }
398         }
399     };
400 }
401 
402 macro_rules! impl_mat4_to_euler {
403     ($scalar:ident, $mat4:ident, $mat3:ident) => {
404         impl ToEuler for $mat4 {
405             type Scalar = $scalar;
406             fn to_euler_angles(
407                 self,
408                 order: EulerRot,
409             ) -> (Self::Scalar, Self::Scalar, Self::Scalar) {
410                 $mat3::from_mat4(self).to_euler_angles(order)
411             }
412         }
413     };
414 }
415 
416 macro_rules! impl_quat_to_euler {
417     ($scalar:ident, $quat:ident, $mat3:ident) => {
418         impl ToEuler for $quat {
419             type Scalar = $scalar;
420             fn to_euler_angles(
421                 self,
422                 order: EulerRot,
423             ) -> (Self::Scalar, Self::Scalar, Self::Scalar) {
424                 $mat3::from_quat(self).to_euler_angles(order)
425             }
426         }
427     };
428 }
429 
430 impl_mat3_to_euler!(f32, Mat3, Vec3);
431 impl_mat3_from_euler!(f32, Mat3, Vec3);
432 impl_mat3_to_euler!(f32, Mat3A, Vec3A);
433 impl_mat3_from_euler!(f32, Mat3A, Vec3A);
434 impl_mat4_from_euler!(f32, Mat4, Mat3);
435 impl_mat4_to_euler!(f32, Mat4, Mat3);
436 impl_quat_to_euler!(f32, Quat, Mat3);
437 impl_quat_from_euler!(f32, Quat, Vec3);
438 
439 impl_mat3_to_euler!(f64, DMat3, DVec3);
440 impl_mat3_from_euler!(f64, DMat3, DVec3);
441 impl_mat4_to_euler!(f64, DMat4, DMat3);
442 impl_mat4_from_euler!(f64, DMat4, DMat3);
443 impl_quat_to_euler!(f64, DQuat, DMat3);
444 impl_quat_from_euler!(f64, DQuat, DVec3);
445