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