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