1use crate::{DMat3, DMat4, DQuat, DVec3, Mat3, Mat3A, Mat4, Quat, Vec3, Vec3A, Vec3Swizzles};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
27pub enum EulerRot {
28 ZYX,
30 ZXY,
32 YXZ,
34 YZX,
36 XYZ,
38 XZY,
40
41 ZYZ,
43 ZXZ,
45 YXY,
47 YZY,
49 XYX,
51 XZX,
53
54 ZYXEx,
56 ZXYEx,
58 YXZEx,
60 YZXEx,
62 XYZEx,
64 XZYEx,
66
67 ZYZEx,
69 ZXZEx,
71 YXYEx,
73 YZYEx,
75 XYXEx,
77 XZXEx,
79}
80
81impl Default for EulerRot {
82 fn default() -> Self {
84 Self::YXZ
85 }
86}
87
88pub(crate) trait ToEuler {
89 type Scalar;
90 fn to_euler_angles(self, order: EulerRot) -> (Self::Scalar, Self::Scalar, Self::Scalar);
91}
92
93pub(crate) trait FromEuler {
94 type Scalar;
95 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)]
104enum Axis {
105 X = 0,
106 Y = 1,
107 Z = 2,
108}
109
110#[derive(Copy, Clone, Debug, PartialEq, Eq)]
111enum Parity {
112 Odd = 0,
113 Even = 1,
114}
115
116#[derive(Copy, Clone, Debug, PartialEq, Eq)]
117enum Repeated {
118 No = 0,
119 Yes = 1,
120}
121
122#[derive(Copy, Clone, Debug, PartialEq, Eq)]
123enum Frame {
124 Relative = 0,
125 Static = 1,
126}
127
128#[derive(Copy, Clone, Debug, PartialEq, Eq)]
129struct Order {
130 initial_axis: Axis,
131 parity_even: bool,
132 initial_repeated: bool,
133 frame_static: bool,
134}
135
136impl Order {
137 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
151 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
180 const fn next_axis(i: usize) -> usize {
181 (i + 1) % 3
182 }
183
184 const fn prev_axis(i: usize) -> usize {
185 if i > 0 {
186 i - 1
187 } else {
188 2
189 }
190 }
191
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
208macro_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 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
273macro_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
289macro_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
347macro_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 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
402macro_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
416macro_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
430impl_mat3_to_euler!(f32, Mat3, Vec3);
431impl_mat3_from_euler!(f32, Mat3, Vec3);
432impl_mat3_to_euler!(f32, Mat3A, Vec3A);
433impl_mat3_from_euler!(f32, Mat3A, Vec3A);
434impl_mat4_from_euler!(f32, Mat4, Mat3);
435impl_mat4_to_euler!(f32, Mat4, Mat3);
436impl_quat_to_euler!(f32, Quat, Mat3);
437impl_quat_from_euler!(f32, Quat, Vec3);
438
439impl_mat3_to_euler!(f64, DMat3, DVec3);
440impl_mat3_from_euler!(f64, DMat3, DVec3);
441impl_mat4_to_euler!(f64, DMat4, DMat3);
442impl_mat4_from_euler!(f64, DMat4, DMat3);
443impl_quat_to_euler!(f64, DQuat, DMat3);
444impl_quat_from_euler!(f64, DQuat, DVec3);