1#[cfg(feature = "f64")]
4use crate::{DMat3, DMat4, DQuat, DVec3};
5use crate::{Mat3, Mat3A, Mat4, Quat, Vec3, Vec3A, Vec3Swizzles};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
29pub enum EulerRot {
30 ZYX,
32 ZXY,
34 YXZ,
36 YZX,
38 XYZ,
40 XZY,
42
43 ZYZ,
45 ZXZ,
47 YXY,
49 YZY,
51 XYX,
53 XZX,
55
56 ZYXEx,
58 ZXYEx,
60 YXZEx,
62 YZXEx,
64 XYZEx,
66 XZYEx,
68
69 ZYZEx,
71 ZXZEx,
73 YXYEx,
75 YZYEx,
77 XYXEx,
79 XZXEx,
81}
82
83impl Default for EulerRot {
84 fn default() -> Self {
86 Self::YXZ
87 }
88}
89
90pub(crate) trait ToEuler {
91 type Scalar;
92 fn to_euler_angles(self, order: EulerRot) -> (Self::Scalar, Self::Scalar, Self::Scalar);
93}
94
95pub(crate) trait FromEuler {
96 type Scalar;
97 fn from_euler_angles(
98 order: EulerRot,
99 i: Self::Scalar,
100 j: Self::Scalar,
101 k: Self::Scalar,
102 ) -> Self;
103}
104
105#[derive(Copy, Clone, Debug, PartialEq, Eq)]
106enum Axis {
107 X = 0,
108 Y = 1,
109 Z = 2,
110}
111
112#[derive(Copy, Clone, Debug, PartialEq, Eq)]
113enum Parity {
114 Odd = 0,
115 Even = 1,
116}
117
118#[derive(Copy, Clone, Debug, PartialEq, Eq)]
119enum Repeated {
120 No = 0,
121 Yes = 1,
122}
123
124#[derive(Copy, Clone, Debug, PartialEq, Eq)]
125enum Frame {
126 Relative = 0,
127 Static = 1,
128}
129
130#[derive(Copy, Clone, Debug, PartialEq, Eq)]
131struct Order {
132 initial_axis: Axis,
133 parity_even: bool,
134 initial_repeated: bool,
135 frame_static: bool,
136}
137
138impl Order {
139 const fn new(
140 initial_axis: Axis,
141 parity: Parity,
142 initial_repeated: Repeated,
143 frame: Frame,
144 ) -> Self {
145 Self {
146 initial_axis,
147 parity_even: parity as u32 == Parity::Even as u32,
148 initial_repeated: initial_repeated as u32 == Repeated::Yes as u32,
149 frame_static: frame as u32 == Frame::Static as u32,
150 }
151 }
152
153 const fn from_euler(euler: EulerRot) -> Self {
154 match euler {
155 EulerRot::XYZ => Self::new(Axis::X, Parity::Even, Repeated::No, Frame::Static),
156 EulerRot::XYX => Self::new(Axis::X, Parity::Even, Repeated::Yes, Frame::Static),
157 EulerRot::XZY => Self::new(Axis::X, Parity::Odd, Repeated::No, Frame::Static),
158 EulerRot::XZX => Self::new(Axis::X, Parity::Odd, Repeated::Yes, Frame::Static),
159 EulerRot::YZX => Self::new(Axis::Y, Parity::Even, Repeated::No, Frame::Static),
160 EulerRot::YZY => Self::new(Axis::Y, Parity::Even, Repeated::Yes, Frame::Static),
161 EulerRot::YXZ => Self::new(Axis::Y, Parity::Odd, Repeated::No, Frame::Static),
162 EulerRot::YXY => Self::new(Axis::Y, Parity::Odd, Repeated::Yes, Frame::Static),
163 EulerRot::ZXY => Self::new(Axis::Z, Parity::Even, Repeated::No, Frame::Static),
164 EulerRot::ZXZ => Self::new(Axis::Z, Parity::Even, Repeated::Yes, Frame::Static),
165 EulerRot::ZYX => Self::new(Axis::Z, Parity::Odd, Repeated::No, Frame::Static),
166 EulerRot::ZYZ => Self::new(Axis::Z, Parity::Odd, Repeated::Yes, Frame::Static),
167 EulerRot::ZYXEx => Self::new(Axis::X, Parity::Even, Repeated::No, Frame::Relative),
168 EulerRot::XYXEx => Self::new(Axis::X, Parity::Even, Repeated::Yes, Frame::Relative),
169 EulerRot::YZXEx => Self::new(Axis::X, Parity::Odd, Repeated::No, Frame::Relative),
170 EulerRot::XZXEx => Self::new(Axis::X, Parity::Odd, Repeated::Yes, Frame::Relative),
171 EulerRot::XZYEx => Self::new(Axis::Y, Parity::Even, Repeated::No, Frame::Relative),
172 EulerRot::YZYEx => Self::new(Axis::Y, Parity::Even, Repeated::Yes, Frame::Relative),
173 EulerRot::ZXYEx => Self::new(Axis::Y, Parity::Odd, Repeated::No, Frame::Relative),
174 EulerRot::YXYEx => Self::new(Axis::Y, Parity::Odd, Repeated::Yes, Frame::Relative),
175 EulerRot::YXZEx => Self::new(Axis::Z, Parity::Even, Repeated::No, Frame::Relative),
176 EulerRot::ZXZEx => Self::new(Axis::Z, Parity::Even, Repeated::Yes, Frame::Relative),
177 EulerRot::XYZEx => Self::new(Axis::Z, Parity::Odd, Repeated::No, Frame::Relative),
178 EulerRot::ZYZEx => Self::new(Axis::Z, Parity::Odd, Repeated::Yes, Frame::Relative),
179 }
180 }
181
182 const fn next_axis(i: usize) -> usize {
183 (i + 1) % 3
184 }
185
186 const fn prev_axis(i: usize) -> usize {
187 if i > 0 { i - 1 } else { 2 }
188 }
189
190 const fn angle_order(self) -> (usize, usize, usize) {
191 let i = self.initial_axis as usize;
192 let j = if self.parity_even {
193 Self::next_axis(i)
194 } else {
195 Self::prev_axis(i)
196 };
197 let k = if self.parity_even {
198 Self::prev_axis(i)
199 } else {
200 Self::next_axis(i)
201 };
202 (i, j, k)
203 }
204}
205
206macro_rules! impl_mat3_from_euler {
207 ($scalar:ident, $mat3:ident, $vec3:ident) => {
208 impl FromEuler for $mat3 {
209 type Scalar = $scalar;
210 fn from_euler_angles(
211 euler: EulerRot,
212 x: Self::Scalar,
213 y: Self::Scalar,
214 z: Self::Scalar,
215 ) -> Self {
216 use crate::$scalar::math;
217
218 let order = Order::from_euler(euler);
219 let (i, j, k) = order.angle_order();
220
221 let mut angles = if order.frame_static {
222 $vec3::new(x, y, z)
223 } else {
224 $vec3::new(z, y, x)
225 };
226
227 if order.parity_even {
229 angles = -angles;
230 }
231
232 let (si, ci) = math::sin_cos(angles.x);
233 let (sj, cj) = math::sin_cos(angles.y);
234 let (sh, ch) = math::sin_cos(angles.z);
235
236 let cc = ci * ch;
237 let cs = ci * sh;
238 let sc = si * ch;
239 let ss = si * sh;
240
241 let mut m = [[0.0; 3]; 3];
242
243 if order.initial_repeated {
244 m[i][i] = cj;
245 m[i][j] = sj * si;
246 m[i][k] = sj * ci;
247 m[j][i] = sj * sh;
248 m[j][j] = -cj * ss + cc;
249 m[j][k] = -cj * cs - sc;
250 m[k][i] = -sj * ch;
251 m[k][j] = cj * sc + cs;
252 m[k][k] = cj * cc - ss;
253 } else {
254 m[i][i] = cj * ch;
255 m[i][j] = sj * sc - cs;
256 m[i][k] = sj * cc + ss;
257 m[j][i] = cj * sh;
258 m[j][j] = sj * ss + cc;
259 m[j][k] = sj * cs - sc;
260 m[k][i] = -sj;
261 m[k][j] = cj * si;
262 m[k][k] = cj * ci;
263 }
264
265 $mat3::from_cols_array_2d(&m)
266 }
267 }
268 };
269}
270
271macro_rules! impl_mat4_from_euler {
272 ($scalar:ident, $mat4:ident, $mat3:ident) => {
273 impl FromEuler for $mat4 {
274 type Scalar = $scalar;
275 fn from_euler_angles(
276 euler: EulerRot,
277 x: Self::Scalar,
278 y: Self::Scalar,
279 z: Self::Scalar,
280 ) -> Self {
281 $mat4::from_mat3($mat3::from_euler_angles(euler, x, y, z))
282 }
283 }
284 };
285}
286
287macro_rules! impl_quat_from_euler {
288 ($scalar:ident, $quat:ident, $vec3:ident) => {
289 impl FromEuler for $quat {
290 type Scalar = $scalar;
291 fn from_euler_angles(
292 euler: EulerRot,
293 x: Self::Scalar,
294 y: Self::Scalar,
295 z: Self::Scalar,
296 ) -> Self {
297 use crate::$scalar::math;
298
299 let order = Order::from_euler(euler);
300 let (i, j, k) = order.angle_order();
301
302 let mut angles = if order.frame_static {
303 $vec3::new(x, y, z)
304 } else {
305 $vec3::new(z, y, x)
306 };
307
308 if order.parity_even {
309 angles.y = -angles.y;
310 }
311
312 let ti = angles.x * 0.5;
313 let tj = angles.y * 0.5;
314 let th = angles.z * 0.5;
315 let (si, ci) = math::sin_cos(ti);
316 let (sj, cj) = math::sin_cos(tj);
317 let (sh, ch) = math::sin_cos(th);
318 let cc = ci * ch;
319 let cs = ci * sh;
320 let sc = si * ch;
321 let ss = si * sh;
322
323 let parity = if !order.parity_even { 1.0 } else { -1.0 };
324
325 let mut a = [0.0; 4];
326
327 if order.initial_repeated {
328 a[i] = cj * (cs + sc);
329 a[j] = sj * (cc + ss) * parity;
330 a[k] = sj * (cs - sc);
331 a[3] = cj * (cc - ss);
332 } else {
333 a[i] = cj * sc - sj * cs;
334 a[j] = (cj * ss + sj * cc) * parity;
335 a[k] = cj * cs - sj * sc;
336 a[3] = cj * cc + sj * ss;
337 }
338
339 $quat::from_array(a)
340 }
341 }
342 };
343}
344
345macro_rules! impl_mat3_to_euler {
346 ($scalar:ident, $mat3:ident, $vec3:ident) => {
347 impl ToEuler for $mat3 {
348 type Scalar = $scalar;
349 fn to_euler_angles(
350 self,
351 euler: EulerRot,
352 ) -> (Self::Scalar, Self::Scalar, Self::Scalar) {
353 use crate::$scalar::math;
354
355 let order = Order::from_euler(euler);
356 let (i, j, k) = order.angle_order();
357
358 let mut ea = $vec3::ZERO;
359 if order.initial_repeated {
360 let sy = math::sqrt(
361 self.col(i)[j] * self.col(i)[j] + self.col(i)[k] * self.col(i)[k],
362 );
363 if (sy > 16.0 * $scalar::EPSILON) {
364 ea.x = math::atan2(self.col(i)[j], self.col(i)[k]);
365 ea.y = math::atan2(sy, self.col(i)[i]);
366 ea.z = math::atan2(self.col(j)[i], -self.col(k)[i]);
367 } else {
368 ea.x = math::atan2(-self.col(j)[k], self.col(j)[j]);
369 ea.y = math::atan2(sy, self.col(i)[i]);
370 }
371 } else {
372 let cy = math::sqrt(
373 self.col(i)[i] * self.col(i)[i] + self.col(j)[i] * self.col(j)[i],
374 );
375 if (cy > 16.0 * $scalar::EPSILON) {
376 ea.x = math::atan2(self.col(k)[j], self.col(k)[k]);
377 ea.y = math::atan2(-self.col(k)[i], cy);
378 ea.z = math::atan2(self.col(j)[i], self.col(i)[i]);
379 } else {
380 ea.x = math::atan2(-self.col(j)[k], self.col(j)[j]);
381 ea.y = math::atan2(-self.col(k)[i], cy);
382 }
383 }
384
385 if order.parity_even {
387 ea = -ea;
388 }
389
390 if !order.frame_static {
391 ea = ea.zyx();
392 }
393
394 (ea.x, ea.y, ea.z)
395 }
396 }
397 };
398}
399
400impl_mat3_to_euler!(f32, Mat3, Vec3);
401impl_mat3_from_euler!(f32, Mat3, Vec3);
402impl_mat3_to_euler!(f32, Mat3A, Vec3A);
403impl_mat3_from_euler!(f32, Mat3A, Vec3A);
404impl_mat4_from_euler!(f32, Mat4, Mat3);
405impl_quat_from_euler!(f32, Quat, Vec3);
406
407#[cfg(feature = "f64")]
408impl_mat3_to_euler!(f64, DMat3, DVec3);
409#[cfg(feature = "f64")]
410impl_mat3_from_euler!(f64, DMat3, DVec3);
411#[cfg(feature = "f64")]
412impl_mat4_from_euler!(f64, DMat4, DMat3);
413#[cfg(feature = "f64")]
414impl_quat_from_euler!(f64, DQuat, DVec3);