1 #![allow(clippy::excessive_precision)]
2 
3 #[macro_use]
4 mod support;
5 
6 macro_rules! impl_quat_tests {
7     ($t:ident, $new:ident, $mat3:ident, $mat4:ident, $quat:ident, $vec2:ident, $vec3:ident, $vec4:ident) => {
8         use core::$t::INFINITY;
9         use core::$t::NAN;
10         use core::$t::NEG_INFINITY;
11 
12         glam_test!(test_const, {
13             const Q0: $quat = $quat::from_xyzw(1.0, 2.0, 3.0, 4.0);
14             const Q1: $quat = $quat::from_array([1.0, 2.0, 3.0, 4.0]);
15             assert_eq!([1.0, 2.0, 3.0, 4.0], *Q0.as_ref());
16             assert_eq!([1.0, 2.0, 3.0, 4.0], *Q1.as_ref());
17         });
18 
19         glam_test!(test_nan, {
20             assert!($quat::NAN.is_nan());
21             assert!(!$quat::NAN.is_finite());
22         });
23 
24         glam_test!(test_new, {
25             let ytheta = deg(45.0);
26             let q0 = $quat::from_rotation_y(ytheta);
27 
28             let v1 = $vec4::new(0.0, (ytheta * 0.5).sin(), 0.0, (ytheta * 0.5).cos());
29             assert_eq!(q0, $quat::from_vec4(v1));
30             let q1 = $quat::from_vec4(v1);
31             assert_eq!(v1, q1.into());
32 
33             assert_eq!(q0, $new(v1.x, v1.y, v1.z, v1.w));
34 
35             let a1: [$t; 4] = q1.into();
36             assert_eq!([v1.x, v1.y, v1.z, v1.w], a1);
37 
38             assert_eq!(q1, $quat::from_array(a1));
39 
40             assert_eq!(a1, *q0.as_ref());
41         });
42 
43         glam_test!(test_funcs, {
44             let q0 = $quat::from_euler(EulerRot::YXZ, deg(45.0), deg(180.0), deg(90.0));
45             assert!(q0.is_normalized());
46             assert_approx_eq!(q0.length_squared(), 1.0);
47             assert_approx_eq!(q0.length(), 1.0);
48             assert_approx_eq!(q0.length_recip(), 1.0);
49             assert_approx_eq!(q0, q0.normalize());
50 
51             assert_approx_eq!(q0.dot(q0), 1.0);
52             assert_approx_eq!(q0.dot(q0), 1.0);
53 
54             let q1 = $quat::from_vec4($vec4::from(q0) * 2.0);
55             assert!(!q1.is_normalized());
56             assert_approx_eq!(q1.length_squared(), 4.0, 1.0e-6);
57             assert_approx_eq!(q1.length(), 2.0);
58             assert_approx_eq!(q1.length_recip(), 0.5);
59             assert_approx_eq!(q0, q1.normalize());
60             assert_approx_eq!(q0.dot(q1), 2.0, 1.0e-6);
61 
62             should_glam_assert!({ ($quat::IDENTITY * 0.0).normalize() });
63         });
64 
65         glam_test!(test_rotation, {
66             let zero = deg(0.0);
67             let yaw = deg(30.0);
68             let pitch = deg(60.0);
69             let roll = deg(90.0);
70             let y0 = $quat::from_rotation_y(yaw);
71             assert!(y0.is_normalized());
72             let (axis, angle) = y0.to_axis_angle();
73             assert_approx_eq!(axis, $vec3::Y, 1.0e-6);
74             assert_approx_eq!(angle, yaw);
75             let y1 = $quat::from_euler(EulerRot::YXZ, yaw, zero, zero);
76             assert_approx_eq!(y0, y1);
77             let y2 = $quat::from_axis_angle($vec3::Y, yaw);
78             assert_approx_eq!(y0, y2);
79             let y3 = $quat::from_mat3(&$mat3::from_rotation_y(yaw));
80             assert_approx_eq!(y0, y3);
81             let y4 = $quat::from_mat3(&$mat3::from_quat(y0));
82             assert_approx_eq!(y0, y4);
83 
84             let x0 = $quat::from_rotation_x(pitch);
85             assert!(x0.is_normalized());
86             let (axis, angle) = x0.to_axis_angle();
87             assert_approx_eq!(axis, $vec3::X);
88             assert_approx_eq!(angle, pitch, 1e-6);
89             let x1 = $quat::from_euler(EulerRot::YXZ, zero, pitch, zero);
90             assert_approx_eq!(x0, x1);
91             let x2 = $quat::from_axis_angle($vec3::X, pitch);
92             assert_approx_eq!(x0, x2);
93             let x3 = $quat::from_mat4(&$mat4::from_rotation_x(deg(180.0)));
94             assert!(x3.is_normalized());
95             assert_approx_eq!($quat::from_rotation_x(deg(180.0)), x3);
96 
97             let z0 = $quat::from_rotation_z(roll);
98             assert!(z0.is_normalized());
99             let (axis, angle) = z0.to_axis_angle();
100             assert_approx_eq!(axis, $vec3::Z);
101             assert_approx_eq!(angle, roll);
102             let z1 = $quat::from_euler(EulerRot::YXZ, zero, zero, roll);
103             assert_approx_eq!(z0, z1);
104             let z2 = $quat::from_axis_angle($vec3::Z, roll);
105             assert_approx_eq!(z0, z2);
106             let z3 = $quat::from_mat4(&$mat4::from_rotation_z(roll));
107             assert_approx_eq!(z0, z3);
108 
109             let yx0 = y0 * x0;
110             assert!(yx0.is_normalized());
111             let yx1 = $quat::from_euler(EulerRot::YXZ, yaw, pitch, zero);
112             assert_approx_eq!(yx0, yx1);
113 
114             let yxz0 = y0 * x0 * z0;
115             assert!(yxz0.is_normalized());
116             let yxz1 = $quat::from_euler(EulerRot::YXZ, yaw, pitch, roll);
117             assert_approx_eq!(yxz0, yxz1);
118 
119             // use the conjugate of z0 to remove the rotation from yxz0
120             let yx2 = yxz0 * z0.conjugate();
121             assert_approx_eq!(yx0, yx2);
122             assert!((yxz0 * yxz0.conjugate()).is_near_identity());
123 
124             // test inverse does the same
125             let yx2 = yxz0 * z0.inverse();
126             assert_approx_eq!(yx0, yx2);
127             assert!((yxz0 * yxz0.inverse()).is_near_identity());
128 
129             let yxz2 = $quat::from_mat4(&$mat4::from_quat(yxz0));
130             assert_approx_eq!(yxz0, yxz2);
131 
132             // if near identity, just returns x axis and 0 rotation
133             let (axis, angle) = $quat::IDENTITY.to_axis_angle();
134             assert_eq!(axis, $vec3::X);
135             assert_eq!(angle, rad(0.0));
136 
137             let mut x0 = $quat::from_rotation_x(pitch);
138             x0 *= x0;
139             assert_approx_eq!(x0, $quat::from_rotation_x(pitch * 2.0));
140 
141             should_glam_assert!({ ($quat::IDENTITY * 2.0).inverse() });
142             should_glam_assert!({ $quat::from_axis_angle($vec3::ZERO, 0.0) });
143         });
144 
145         glam_test!(test_from_scaled_axis, {
146             assert_eq!($quat::from_scaled_axis($vec3::ZERO), $quat::IDENTITY);
147             assert_eq!(
148                 $quat::from_scaled_axis($vec3::Y * 1e-10),
149                 $quat::from_axis_angle($vec3::Y, 1e-10)
150             );
151             assert_eq!(
152                 $quat::from_scaled_axis($vec3::X * 1.0),
153                 $quat::from_axis_angle($vec3::X, 1.0)
154             );
155             assert_eq!(
156                 $quat::from_scaled_axis($vec3::Z * 2.0),
157                 $quat::from_axis_angle($vec3::Z, 2.0)
158             );
159 
160             assert_eq!(
161                 $quat::from_scaled_axis($vec3::ZERO).to_scaled_axis(),
162                 $vec3::ZERO
163             );
164             for &v in &vec3_float_test_vectors!($vec3) {
165                 if v.length() < core::$t::consts::PI {
166                     assert!(($quat::from_scaled_axis(v).to_scaled_axis() - v).length() < 1e-6,);
167                 }
168             }
169         });
170 
171         glam_test!(test_mul_vec3, {
172             let qrz = $quat::from_rotation_z(deg(90.0));
173             assert_approx_eq!($vec3::Y, qrz * $vec3::X);
174             assert_approx_eq!($vec3::Y, qrz.mul_vec3($vec3::X));
175             assert_approx_eq!($vec3::Y, -qrz * $vec3::X);
176             assert_approx_eq!($vec3::Y, qrz.neg().mul_vec3($vec3::X));
177             assert_approx_eq!(-$vec3::X, qrz * $vec3::Y);
178             assert_approx_eq!(-$vec3::X, qrz.mul_vec3($vec3::Y));
179             assert_approx_eq!(-$vec3::X, -qrz * $vec3::Y);
180             assert_approx_eq!(-$vec3::X, qrz.neg().mul_vec3($vec3::Y));
181 
182             // check vec3 * mat3 is the same
183             let mrz = $mat3::from_quat(qrz);
184             assert_approx_eq!($vec3::Y, mrz * $vec3::X);
185             assert_approx_eq!($vec3::Y, mrz.mul_vec3($vec3::X));
186             // assert_approx_eq!($vec3::Y, -mrz * $vec3::X);
187             assert_approx_eq!(-$vec3::X, mrz * $vec3::Y);
188             assert_approx_eq!(-$vec3::X, mrz.mul_vec3($vec3::Y));
189 
190             let qrx = $quat::from_rotation_x(deg(90.0));
191             assert_approx_eq!($vec3::X, qrx * $vec3::X);
192             assert_approx_eq!($vec3::X, qrx.mul_vec3($vec3::X));
193             assert_approx_eq!($vec3::X, -qrx * $vec3::X);
194             assert_approx_eq!($vec3::X, qrx.neg().mul_vec3($vec3::X));
195             assert_approx_eq!($vec3::Z, qrx * $vec3::Y);
196             assert_approx_eq!($vec3::Z, qrx.mul_vec3($vec3::Y));
197             assert_approx_eq!($vec3::Z, -qrx * $vec3::Y);
198             assert_approx_eq!($vec3::Z, qrx.neg().mul_vec3($vec3::Y));
199 
200             // check vec3 * mat3 is the same
201             let mrx = $mat3::from_quat(qrx);
202             assert_approx_eq!($vec3::X, mrx * $vec3::X);
203             assert_approx_eq!($vec3::X, mrx.mul_vec3($vec3::X));
204             assert_approx_eq!($vec3::Z, mrx * $vec3::Y);
205             assert_approx_eq!($vec3::Z, mrx.mul_vec3($vec3::Y));
206 
207             let qrxz = qrz * qrx;
208             assert_approx_eq!($vec3::Y, qrxz * $vec3::X);
209             assert_approx_eq!($vec3::Y, qrxz.mul_vec3($vec3::X));
210             assert_approx_eq!($vec3::Z, qrxz * $vec3::Y);
211             assert_approx_eq!($vec3::Z, qrxz.mul_vec3($vec3::Y));
212 
213             let mrxz = mrz * mrx;
214             assert_approx_eq!($vec3::Y, mrxz * $vec3::X);
215             assert_approx_eq!($vec3::Y, mrxz.mul_vec3($vec3::X));
216             assert_approx_eq!($vec3::Z, mrxz * $vec3::Y);
217             assert_approx_eq!($vec3::Z, mrxz.mul_vec3($vec3::Y));
218 
219             let qrzx = qrx * qrz;
220             assert_approx_eq!($vec3::Z, qrzx * $vec3::X);
221             assert_approx_eq!($vec3::Z, qrzx.mul_vec3($vec3::X));
222             assert_approx_eq!(-$vec3::X, qrzx * $vec3::Y);
223             assert_approx_eq!(-$vec3::X, qrzx.mul_vec3($vec3::Y));
224 
225             let mrzx = qrx * qrz;
226             assert_approx_eq!($vec3::Z, mrzx * $vec3::X);
227             assert_approx_eq!($vec3::Z, mrzx.mul_vec3($vec3::X));
228             assert_approx_eq!(-$vec3::X, mrzx * $vec3::Y);
229             assert_approx_eq!(-$vec3::X, mrzx.mul_vec3($vec3::Y));
230 
231             should_glam_assert!({ ($quat::IDENTITY * 0.5).mul_vec3($vec3::X) });
232             should_glam_assert!({ ($quat::IDENTITY * 0.5) * $vec3::X });
233             should_glam_assert!({ ($quat::IDENTITY * 0.5).mul_quat($quat::IDENTITY) });
234             should_glam_assert!({ ($quat::IDENTITY * 0.5) * $quat::IDENTITY });
235         });
236 
237         glam_test!(test_angle_between, {
238             const TAU: $t = 2.0 * core::$t::consts::PI;
239             let eps = 10.0 * core::$t::EPSILON as f32;
240             let q1 = $quat::from_euler(EulerRot::YXZ, 0.0, 0.0, 0.0);
241             let q2 = $quat::from_euler(EulerRot::YXZ, TAU * 0.25, 0.0, 0.0);
242             let q3 = $quat::from_euler(EulerRot::YXZ, TAU * 0.5, 0.0, 0.0);
243             let q4 = $quat::from_euler(EulerRot::YXZ, 0.0, 0.0, TAU * 0.25);
244             let q5 = $quat::from_axis_angle($vec3::new(1.0, 2.0, 3.0).normalize(), TAU * 0.3718);
245             let q6 = $quat::from_axis_angle($vec3::new(-1.0, 5.0, 3.0).normalize(), TAU * 0.94);
246             assert_approx_eq!(q1.angle_between(q2), TAU * 0.25, eps);
247             assert_approx_eq!(q1.angle_between(q3), TAU * 0.5, eps);
248             assert_approx_eq!(q3.angle_between(q3), 0.0, eps);
249             assert_approx_eq!(q3.angle_between(-q3), 0.0, eps);
250             assert_approx_eq!((q4 * q2 * q2).angle_between(q4 * q2), TAU * 0.25, eps);
251             assert_approx_eq!(q1.angle_between(q5), TAU * 0.3718, eps);
252             assert_approx_eq!(
253                 (q5 * q2 * q1).angle_between(q5 * q2 * q5),
254                 TAU * 0.3718,
255                 eps
256             );
257             assert_approx_eq!((q3 * q3).angle_between(q1), 0.0, eps);
258             assert_approx_eq!((q3 * q3 * q3).angle_between(q3), 0.0, eps);
259             assert_approx_eq!((q3 * q3 * q3 * q3).angle_between(q1), 0.0, eps);
260             assert_approx_eq!(q1.angle_between(q6), TAU - TAU * 0.94, eps);
261             assert_approx_eq!((q5 * q1).angle_between(q5 * q6), TAU - TAU * 0.94, eps);
262             assert_approx_eq!((q1 * q5).angle_between(q6 * q5), TAU - TAU * 0.94, eps);
263         });
264 
265         glam_test!(test_lerp, {
266             let q0 = $quat::from_rotation_y(deg(0.0));
267             let q1 = $quat::from_rotation_y(deg(90.0));
268             assert_approx_eq!(q0, q0.lerp(q1, 0.0));
269             assert_approx_eq!(q1, q0.lerp(q1, 1.0));
270             assert_approx_eq!($quat::from_rotation_y(deg(45.0)), q0.lerp(q1, 0.5));
271 
272             should_glam_assert!({ $quat::lerp($quat::IDENTITY * 2.0, $quat::IDENTITY, 1.0) });
273             should_glam_assert!({ $quat::lerp($quat::IDENTITY, $quat::IDENTITY * 0.5, 1.0) });
274         });
275 
276         glam_test!(test_slerp, {
277             let q0 = $quat::from_rotation_y(deg(0.0));
278             let q1 = $quat::from_rotation_y(deg(90.0));
279             assert_approx_eq!(q0, q0.slerp(q1, 0.0), 1.0e-3);
280             assert_approx_eq!(q1, q0.slerp(q1, 1.0), 1.0e-3);
281             assert_approx_eq!($quat::from_rotation_y(deg(45.0)), q0.slerp(q1, 0.5), 1.0e-3);
282 
283             should_glam_assert!({ $quat::lerp($quat::IDENTITY * 2.0, $quat::IDENTITY, 1.0) });
284             should_glam_assert!({ $quat::lerp($quat::IDENTITY, $quat::IDENTITY * 0.5, 1.0) });
285         });
286 
287         glam_test!(test_slerp_constant_speed, {
288             let step = 0.01;
289             let mut s = 0.0;
290             while s <= 1.0 {
291                 let q0 = $quat::from_rotation_y(deg(0.0));
292                 let q1 = $quat::from_rotation_y(deg(90.0));
293                 let result = q0.slerp(q1, s);
294                 assert_approx_eq!($quat::from_rotation_y(deg(s * 90.0)), result, 1.0e-3);
295                 assert!(result.is_normalized());
296                 s += step;
297             }
298         });
299 
300         glam_test!(test_slerp_tau, {
301             let q1 = $quat::IDENTITY;
302             let q2 = $quat::from_rotation_x(core::$t::consts::TAU);
303             let s = q1.slerp(q2, 1.);
304             assert!(s.is_finite());
305             assert!(s.is_normalized());
306         });
307 
308         glam_test!(test_slerp_negative_tau, {
309             let q1 = $quat::IDENTITY;
310             let q2 = $quat::from_rotation_x(-core::$t::consts::TAU);
311             let s = q1.slerp(q2, 1.);
312             assert!(s.is_finite());
313             assert!(s.is_normalized());
314         });
315 
316         glam_test!(test_slerp_pi, {
317             let q1 = $quat::IDENTITY;
318             let q2 = $quat::from_rotation_x(core::$t::consts::PI);
319             let s = q1.slerp(q2, 1.);
320             assert!(s.is_finite());
321             assert!(s.is_normalized());
322         });
323 
324         glam_test!(test_slerp_negative_pi, {
325             let q1 = $quat::IDENTITY;
326             let q2 = $quat::from_rotation_x(-core::$t::consts::PI);
327             let s = q1.slerp(q2, 1.);
328             assert!(s.is_finite());
329             assert!(s.is_normalized());
330         });
331 
332         glam_test!(test_fmt, {
333             let a = $quat::IDENTITY;
334             assert_eq!(
335                 format!("{:?}", a),
336                 format!("{}(0.0, 0.0, 0.0, 1.0)", stringify!($quat))
337             );
338             // assert_eq!(
339             //     format!("{:#?}", a),
340             //     "$quat(\n    1.0,\n    2.0,\n    3.0,\n    4.0\n)"
341             // );
342             assert_eq!(format!("{}", a), "[0, 0, 0, 1]");
343         });
344 
345         glam_test!(test_identity, {
346             let identity = $quat::IDENTITY;
347             assert!(identity.is_near_identity());
348             assert!(identity.is_normalized());
349             assert_eq!(identity, $quat::from_xyzw(0.0, 0.0, 0.0, 1.0));
350             assert_eq!(identity, identity * identity);
351             let q = $quat::from_euler(EulerRot::YXZ, deg(10.0), deg(-10.0), deg(45.0));
352             assert_eq!(q, q * identity);
353             assert_eq!(q, identity * q);
354             assert_eq!(identity, $quat::default());
355         });
356 
357         glam_test!(test_slice, {
358             let a: [$t; 4] =
359                 $quat::from_euler(EulerRot::YXZ, deg(30.0), deg(60.0), deg(90.0)).into();
360             let b = $quat::from_slice(&a);
361             let c: [$t; 4] = b.into();
362             assert_eq!(a, c);
363             let mut d = [0.0, 0.0, 0.0, 0.0];
364             b.write_to_slice(&mut d[..]);
365             assert_eq!(a, d);
366 
367             should_panic!({ $quat::IDENTITY.write_to_slice(&mut [0 as $t; 3]) });
368             should_panic!({ $quat::from_slice(&[0 as $t; 3]) });
369         });
370 
371         glam_test!(test_elements, {
372             let x = 1.0;
373             let y = 2.0;
374             let z = 3.0;
375             let w = 4.0;
376 
377             let a = $quat::from_xyzw(x, y, z, w);
378             assert!(a.x == x);
379             assert!(a.y == y);
380             assert!(a.z == z);
381             assert!(a.w == w);
382 
383             assert_eq!($vec3::new(1.0, 2.0, 3.0), a.xyz());
384         });
385 
386         glam_test!(test_addition, {
387             let a = $quat::from_xyzw(1.0, 2.0, 3.0, 4.0);
388             let b = $quat::from_xyzw(5.0, 6.0, 7.0, -9.0);
389             assert_eq!(a + b, $quat::from_xyzw(6.0, 8.0, 10.0, -5.0));
390         });
391 
392         glam_test!(test_subtraction, {
393             let a = $quat::from_xyzw(6.0, 8.0, 10.0, -5.0);
394             let b = $quat::from_xyzw(5.0, 6.0, 7.0, -9.0);
395             assert_eq!(a - b, $quat::from_xyzw(1.0, 2.0, 3.0, 4.0));
396         });
397 
398         glam_test!(test_scalar_multiplication, {
399             let a = $quat::from_xyzw(1.0, 2.0, 3.0, 4.0);
400             assert_eq!(a * 2.0, $quat::from_xyzw(2.0, 4.0, 6.0, 8.0));
401         });
402 
403         glam_test!(test_scalar_division, {
404             let a = $quat::from_xyzw(2.0, 4.0, 6.0, 8.0);
405             assert_eq!(a / 2.0, $quat::from_xyzw(1.0, 2.0, 3.0, 4.0));
406         });
407 
408         glam_test!(test_sum, {
409             let two = $new(2.0, 2.0, 2.0, 2.0);
410             assert_eq!([two, two].iter().sum::<$quat>(), two + two);
411             assert_eq!([two, two].into_iter().sum::<$quat>(), two + two);
412         });
413 
414         glam_test!(test_product, {
415             let two = $new(2.0, 2.0, 2.0, 2.0).normalize();
416             assert_eq!([two, two].iter().product::<$quat>(), two * two);
417             assert_eq!([two, two].into_iter().product::<$quat>(), two * two);
418         });
419 
420         glam_test!(test_is_finite, {
421             assert!($quat::from_xyzw(0.0, 0.0, 0.0, 0.0).is_finite());
422             assert!($quat::from_xyzw(-1e-10, 1.0, 1e10, 42.0).is_finite());
423             assert!(!$quat::from_xyzw(INFINITY, 0.0, 0.0, 0.0).is_finite());
424             assert!(!$quat::from_xyzw(0.0, NAN, 0.0, 0.0).is_finite());
425             assert!(!$quat::from_xyzw(0.0, 0.0, NEG_INFINITY, 0.0).is_finite());
426             assert!(!$quat::from_xyzw(0.0, 0.0, 0.0, NAN).is_finite());
427         });
428 
429         glam_test!(test_rotation_arc, {
430             let eps = 2.0 * core::$t::EPSILON.sqrt();
431 
432             for &from in &vec3_float_test_vectors!($vec3) {
433                 let from = from.normalize();
434 
435                 {
436                     let q = $quat::from_rotation_arc(from, from);
437                     assert!(q.is_near_identity(), "from: {}, q: {}", from, q);
438                 }
439 
440                 {
441                     let q = $quat::from_rotation_arc_colinear(from, from);
442                     assert!(q.is_near_identity(), "from: {}, q: {}", from, q);
443                 }
444 
445                 {
446                     let to = -from;
447                     let q = $quat::from_rotation_arc(from, to);
448                     assert!(q.is_normalized());
449                     assert!((q * from - to).length() < eps);
450                 }
451 
452                 {
453                     let to = -from;
454                     let q = $quat::from_rotation_arc_colinear(from, to);
455                     assert!(q.is_near_identity(), "from: {}, q: {}", from, q);
456                 }
457 
458                 for &to in &vec3_float_test_vectors!($vec3) {
459                     let to = to.normalize();
460 
461                     let q = $quat::from_rotation_arc(from, to);
462                     assert!(q.is_normalized());
463                     assert!((q * from - to).length() < eps);
464 
465                     let q = $quat::from_rotation_arc_colinear(from, to);
466                     assert!(q.is_normalized());
467                     let transformed = q * from;
468                     assert!(
469                         (transformed - to).length() < eps || (-transformed - to).length() < eps
470                     );
471                 }
472             }
473 
474             for &from in &vec2_float_test_vectors!($vec2) {
475                 let from = from.normalize();
476 
477                 {
478                     let q = $quat::from_rotation_arc_2d(from, from);
479                     assert!(q.is_near_identity(), "from: {}, q: {}", from, q);
480                 }
481 
482                 {
483                     let to = -from;
484                     let q = $quat::from_rotation_arc_2d(from, to);
485                     assert!(q.is_normalized());
486                     assert!((q * from.extend(0.0) - to.extend(0.0)).length() < eps);
487                 }
488 
489                 for &to in &vec2_float_test_vectors!($vec2) {
490                     let to = to.normalize();
491 
492                     let q = $quat::from_rotation_arc_2d(from, to);
493                     assert!(q.is_normalized());
494                     assert!((q * from.extend(0.0) - to.extend(0.0)).length() < eps);
495                 }
496             }
497 
498             should_glam_assert!({ $quat::from_rotation_arc($vec3::ZERO, $vec3::X) });
499             should_glam_assert!({ $quat::from_rotation_arc($vec3::X, $vec3::ZERO) });
500             should_glam_assert!({ $quat::from_rotation_arc_colinear($vec3::ZERO, $vec3::X) });
501             should_glam_assert!({ $quat::from_rotation_arc_colinear($vec3::X, $vec3::ZERO) });
502 
503             should_glam_assert!({ $quat::from_rotation_arc_2d($vec2::ZERO, $vec2::X) });
504             should_glam_assert!({ $quat::from_rotation_arc_2d($vec2::X, $vec2::ZERO) });
505         });
506 
507         glam_test!(test_to_array, {
508             assert!($new(1.0, 2.0, 3.0, 4.0).to_array() == [1.0, 2.0, 3.0, 4.0]);
509         });
510 
511         glam_test!(test_to_axis_angle, {
512             {
513                 let q = $quat::from_xyzw(
514                     5.28124762e-08,
515                     -5.12559303e-03,
516                     8.29266140e-08,
517                     9.99986828e-01,
518                 );
519                 assert!(q.is_normalized());
520                 let (axis, angle) = q.to_axis_angle();
521                 assert!(axis.is_normalized());
522                 let q2 = $quat::from_axis_angle(axis, angle);
523                 assert!((q.dot(q2) - 1.0).abs() < 1e-6);
524             }
525             {
526                 let q = $quat::IDENTITY;
527                 let (axis, angle) = q.to_axis_angle();
528                 assert!(axis.is_normalized());
529                 let q2 = $quat::from_axis_angle(axis, angle);
530                 assert!((q.dot(q2) - 1.0).abs() < 1e-6);
531             }
532             {
533                 let q = $quat::from_xyzw(0.0, 1.0, 0.0, 0.0);
534                 assert!(q.is_normalized());
535                 let (axis, angle) = q.to_axis_angle();
536                 assert!(axis.is_normalized());
537                 let q2 = $quat::from_axis_angle(axis, angle);
538                 assert!((q.dot(q2) - 1.0).abs() < 1e-6);
539             }
540             {
541                 let axis = $vec3::Z;
542                 let angle = core::$t::consts::PI * 0.25;
543                 let q = $quat::from_axis_angle(axis, angle);
544                 assert!(q.is_normalized());
545                 let (axis2, angle2) = q.to_axis_angle();
546                 assert!(axis.is_normalized());
547                 assert_approx_eq!(axis, axis2);
548                 assert_approx_eq!(angle, angle2);
549             }
550         });
551     };
552 }
553 
554 mod quat {
555     use crate::support::{deg, rad};
556     use core::ops::Neg;
557     use glam::{quat, EulerRot, Mat3, Mat4, Quat, Vec2, Vec3, Vec3A, Vec4};
558 
559     glam_test!(test_align, {
560         use std::mem;
561         assert_eq!(16, mem::size_of::<Quat>());
562         if cfg!(feature = "scalar-math") {
563             assert_eq!(4, mem::align_of::<Quat>());
564         } else {
565             assert_eq!(16, mem::align_of::<Quat>());
566         }
567     });
568 
569     glam_test!(test_mul_vec3a, {
570         let qrz = Quat::from_rotation_z(deg(90.0));
571         assert_approx_eq!(Vec3A::Y, qrz * Vec3A::X);
572         assert_approx_eq!(Vec3A::Y, qrz.mul_vec3a(Vec3A::X));
573         assert_approx_eq!(Vec3A::Y, -qrz * Vec3A::X);
574         assert_approx_eq!(Vec3A::Y, qrz.neg().mul_vec3a(Vec3A::X));
575         assert_approx_eq!(-Vec3A::X, qrz * Vec3A::Y);
576         assert_approx_eq!(-Vec3A::X, qrz.mul_vec3a(Vec3A::Y));
577         assert_approx_eq!(-Vec3A::X, -qrz * Vec3A::Y);
578         assert_approx_eq!(-Vec3A::X, qrz.neg().mul_vec3a(Vec3A::Y));
579 
580         // check vec3 * mat3 is the same
581         let mrz = Mat3::from_quat(qrz);
582         assert_approx_eq!(Vec3A::Y, mrz * Vec3A::X);
583         assert_approx_eq!(Vec3A::Y, mrz.mul_vec3a(Vec3A::X));
584         // assert_approx_eq!(Vec3A::Y, -mrz * Vec3A::X);
585         assert_approx_eq!(-Vec3A::X, mrz * Vec3A::Y);
586         assert_approx_eq!(-Vec3A::X, mrz.mul_vec3a(Vec3A::Y));
587 
588         let qrx = Quat::from_rotation_x(deg(90.0));
589         assert_approx_eq!(Vec3A::X, qrx * Vec3A::X);
590         assert_approx_eq!(Vec3A::X, qrx.mul_vec3a(Vec3A::X));
591         assert_approx_eq!(Vec3A::X, -qrx * Vec3A::X);
592         assert_approx_eq!(Vec3A::X, qrx.neg().mul_vec3a(Vec3A::X));
593         assert_approx_eq!(Vec3A::Z, qrx * Vec3A::Y);
594         assert_approx_eq!(Vec3A::Z, qrx.mul_vec3a(Vec3A::Y));
595         assert_approx_eq!(Vec3A::Z, -qrx * Vec3A::Y);
596         assert_approx_eq!(Vec3A::Z, qrx.neg().mul_vec3a(Vec3A::Y));
597 
598         // check vec3 * mat3 is the same
599         let mrx = Mat3::from_quat(qrx);
600         assert_approx_eq!(Vec3A::X, mrx * Vec3A::X);
601         assert_approx_eq!(Vec3A::X, mrx.mul_vec3a(Vec3A::X));
602         assert_approx_eq!(Vec3A::Z, mrx * Vec3A::Y);
603         assert_approx_eq!(Vec3A::Z, mrx.mul_vec3a(Vec3A::Y));
604 
605         let qrxz = qrz * qrx;
606         assert_approx_eq!(Vec3A::Y, qrxz * Vec3A::X);
607         assert_approx_eq!(Vec3A::Y, qrxz.mul_vec3a(Vec3A::X));
608         assert_approx_eq!(Vec3A::Z, qrxz * Vec3A::Y);
609         assert_approx_eq!(Vec3A::Z, qrxz.mul_vec3a(Vec3A::Y));
610 
611         let mrxz = mrz * mrx;
612         assert_approx_eq!(Vec3A::Y, mrxz * Vec3A::X);
613         assert_approx_eq!(Vec3A::Y, mrxz.mul_vec3a(Vec3A::X));
614         assert_approx_eq!(Vec3A::Z, mrxz * Vec3A::Y);
615         assert_approx_eq!(Vec3A::Z, mrxz.mul_vec3a(Vec3A::Y));
616 
617         let qrzx = qrx * qrz;
618         assert_approx_eq!(Vec3A::Z, qrzx * Vec3A::X);
619         assert_approx_eq!(Vec3A::Z, qrzx.mul_vec3a(Vec3A::X));
620         assert_approx_eq!(-Vec3A::X, qrzx * Vec3A::Y);
621         assert_approx_eq!(-Vec3A::X, qrzx.mul_vec3a(Vec3A::Y));
622 
623         let mrzx = qrx * qrz;
624         assert_approx_eq!(Vec3A::Z, mrzx * Vec3A::X);
625         assert_approx_eq!(Vec3A::Z, mrzx.mul_vec3a(Vec3A::X));
626         assert_approx_eq!(-Vec3A::X, mrzx * Vec3A::Y);
627         assert_approx_eq!(-Vec3A::X, mrzx.mul_vec3a(Vec3A::Y));
628     });
629 
630     glam_test!(test_from_mat3a, {
631         use glam::Mat3A;
632         let yaw = deg(30.0);
633         let y0 = Quat::from_rotation_y(yaw);
634         let y1 = Quat::from_mat3a(&Mat3A::from_rotation_y(yaw));
635         assert_approx_eq!(y0, y1);
636         let y2 = Quat::from_mat3a(&Mat3A::from_quat(y0));
637         assert_approx_eq!(y0, y2);
638     });
639 
640     glam_test!(test_as, {
641         use glam::DQuat;
642         assert_approx_eq!(
643             DQuat::from_euler(EulerRot::YXZ, 1.0, 2.0, 3.0),
644             Quat::from_euler(EulerRot::YXZ, 1.0, 2.0, 3.0).as_dquat()
645         );
646         assert_approx_eq!(
647             Quat::from_euler(EulerRot::YXZ, 1.0, 2.0, 3.0),
648             DQuat::from_euler(EulerRot::YXZ, 1.0, 2.0, 3.0).as_quat()
649         );
650     });
651 
652     impl_quat_tests!(f32, quat, Mat3, Mat4, Quat, Vec2, Vec3, Vec4);
653 }
654 
655 mod dquat {
656     use crate::support::{deg, rad};
657     use core::ops::Neg;
658     use glam::{dquat, DMat3, DMat4, DQuat, DVec2, DVec3, DVec4, EulerRot};
659 
660     glam_test!(test_align, {
661         use std::mem;
662         assert_eq!(32, mem::size_of::<DQuat>());
663         assert_eq!(mem::align_of::<f64>(), mem::align_of::<DQuat>());
664     });
665 
666     impl_quat_tests!(f64, dquat, DMat3, DMat4, DQuat, DVec2, DVec3, DVec4);
667 }
668