1 #[macro_use] 2 mod support; 3 4 macro_rules! impl_affine3_tests { 5 ($t:ident, $affine3:ident, $quat:ident, $vec3:ident, $mat3:ident, $mat4:ident) => { 6 const MATRIX1D: [$t; 12] = [ 7 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 8 ]; 9 const MATRIX2D: [[$t; 3]; 4] = [ 10 [1.0, 2.0, 3.0], 11 [4.0, 5.0, 6.0], 12 [7.0, 8.0, 9.0], 13 [10.0, 11.0, 12.0], 14 ]; 15 16 use core::$t::NAN; 17 use core::$t::NEG_INFINITY; 18 19 glam_test!(test_affine3_identity, { 20 assert_eq!($affine3::IDENTITY, $affine3::IDENTITY * $affine3::IDENTITY); 21 assert_eq!($affine3::IDENTITY, $affine3::default()); 22 }); 23 24 glam_test!(test_affine3_zero, { 25 assert_eq!( 26 $affine3::ZERO.transform_point3($vec3::new(1., 2., 3.)), 27 $vec3::ZERO 28 ); 29 }); 30 31 glam_test!(test_affine3_nan, { 32 assert!($affine3::NAN.is_nan()); 33 assert!(!$affine3::NAN.is_finite()); 34 }); 35 36 glam_test!(test_affine3_from_cols, { 37 let a = $affine3::from_cols( 38 $vec3::from_array(MATRIX2D[0]).into(), 39 $vec3::from_array(MATRIX2D[1]).into(), 40 $vec3::from_array(MATRIX2D[2]).into(), 41 $vec3::from_array(MATRIX2D[3]).into(), 42 ); 43 assert_eq!(MATRIX2D, a.to_cols_array_2d()); 44 45 let a = $affine3::from_cols_array(&MATRIX1D); 46 assert_eq!(MATRIX1D, a.to_cols_array()); 47 48 let a = $affine3::from_cols_array_2d(&MATRIX2D); 49 assert_eq!(MATRIX2D, a.to_cols_array_2d()); 50 }); 51 52 glam_test!(test_affine3_deref, { 53 let a = $affine3::from_cols_array_2d(&MATRIX2D); 54 assert_eq!(MATRIX2D[0], a.x_axis.to_array()); 55 assert_eq!(MATRIX2D[1], a.y_axis.to_array()); 56 assert_eq!(MATRIX2D[2], a.z_axis.to_array()); 57 assert_eq!(MATRIX2D[3], a.w_axis.to_array()); 58 59 let mut b = a; 60 b.x_axis *= 0.0; 61 b.y_axis *= 0.0; 62 b.z_axis *= 0.0; 63 b.w_axis *= 0.0; 64 assert_eq!($affine3::ZERO, b); 65 }); 66 67 glam_test!(test_affine3_from_mat3, { 68 let m = $mat3::from_cols_array_2d(&[MATRIX2D[0], MATRIX2D[1], MATRIX2D[2]]); 69 let a = $affine3::from_mat3(m); 70 assert_eq!(m, a.matrix3.into()); 71 assert_eq!($vec3::ZERO, a.translation.into()); 72 73 let t = $vec3::from_array(MATRIX2D[3]); 74 let a = $affine3::from_mat3_translation(m, t); 75 assert_eq!(MATRIX2D, a.to_cols_array_2d()); 76 }); 77 78 glam_test!(test_affine2_from_mat4, { 79 let m = $mat4::from_cols_array_2d(&[ 80 [1.0, 2.0, 3.0, 0.0], 81 [4.0, 5.0, 6.0, 0.0], 82 [7.0, 8.0, 9.0, 0.0], 83 [10.0, 11.0, 12.0, 1.0], 84 ]); 85 let a = $affine3::from_mat4(m); 86 assert_eq!(MATRIX2D, a.to_cols_array_2d()); 87 88 assert_eq!(m, $mat4::from(a)); 89 }); 90 91 glam_test!(test_affine3_translation, { 92 let translate = $affine3::from_translation($vec3::new(1.0, 2.0, 3.0)); 93 assert_eq!(translate.translation, $vec3::new(1.0, 2.0, 3.0).into()); 94 assert_eq!( 95 translate.transform_point3($vec3::new(2.0, 3.0, 4.0)), 96 $vec3::new(3.0, 5.0, 7.0), 97 ); 98 }); 99 100 glam_test!(test_from_rotation, { 101 let eps = 2.0 * core::f32::EPSILON; 102 let rot_x1 = $affine3::from_rotation_x(deg(180.0)); 103 let rot_x2 = $affine3::from_axis_angle($vec3::X, deg(180.0)); 104 assert_approx_eq!(rot_x1, rot_x2, eps); 105 let rot_y1 = $affine3::from_rotation_y(deg(180.0)); 106 let rot_y2 = $affine3::from_axis_angle($vec3::Y, deg(180.0)); 107 assert_approx_eq!(rot_y1, rot_y2, eps); 108 let rot_z1 = $affine3::from_rotation_z(deg(180.0)); 109 let rot_z2 = $affine3::from_axis_angle($vec3::Z, deg(180.0)); 110 assert_approx_eq!(rot_z1, rot_z2, eps); 111 112 assert_approx_eq!( 113 $affine3::from_rotation_x(deg(180.0)), 114 $affine3::from_quat($quat::from_rotation_x(deg(180.0))) 115 ); 116 117 assert_approx_eq!( 118 $quat::from_affine3(&$affine3::from_rotation_x(deg(180.0))), 119 $quat::from_rotation_x(deg(180.0)) 120 ); 121 122 let m = $affine3::from_rotation_translation( 123 $quat::from_rotation_x(deg(90.0)), 124 $vec3::new(1.0, 2.0, 3.0), 125 ); 126 let result3 = m.transform_vector3($vec3::Y); 127 assert_approx_eq!($vec3::new(0.0, 0.0, 1.0), result3, 1.0e-6); 128 129 should_glam_assert!({ $affine3::from_axis_angle($vec3::ZERO, 0.0) }); 130 should_glam_assert!({ $affine3::from_quat($quat::IDENTITY * 2.0) }); 131 }); 132 133 glam_test!(test_affine3_mul, { 134 let m = $affine3::from_axis_angle($vec3::Z, deg(90.0)); 135 let result3 = m.transform_vector3($vec3::Y); 136 assert_approx_eq!($vec3::new(-1.0, 0.0, 0.0), result3); 137 138 let m = $affine3::from_scale_rotation_translation( 139 $vec3::new(0.5, 1.5, 2.0), 140 $quat::from_rotation_x(deg(90.0)), 141 $vec3::new(1.0, 2.0, 3.0), 142 ); 143 let result3 = m.transform_vector3($vec3::Y); 144 assert_approx_eq!($vec3::new(0.0, 0.0, 1.5), result3, 1.0e-6); 145 146 let result3 = m.transform_point3($vec3::Y); 147 assert_approx_eq!($vec3::new(1.0, 2.0, 4.5), result3, 1.0e-6); 148 }); 149 150 glam_test!(test_from_scale, { 151 let m = $affine3::from_scale($vec3::new(2.0, 4.0, 8.0)); 152 assert_approx_eq!( 153 m.transform_point3($vec3::new(1.0, 1.0, 1.0)), 154 $vec3::new(2.0, 4.0, 8.0) 155 ); 156 }); 157 158 glam_test!(test_affine3_inverse, { 159 let inv = $affine3::IDENTITY.inverse(); 160 assert_approx_eq!($affine3::IDENTITY, inv); 161 162 let rotz = $affine3::from_rotation_z(deg(90.0)); 163 let rotz_inv = rotz.inverse(); 164 assert_approx_eq!($affine3::IDENTITY, rotz * rotz_inv); 165 assert_approx_eq!($affine3::IDENTITY, rotz_inv * rotz); 166 167 let trans = $affine3::from_translation($vec3::new(1.0, 2.0, 3.0)); 168 let trans_inv = trans.inverse(); 169 assert_approx_eq!($affine3::IDENTITY, trans * trans_inv); 170 assert_approx_eq!($affine3::IDENTITY, trans_inv * trans); 171 172 let scale = $affine3::from_scale($vec3::new(4.0, 5.0, 6.0)); 173 let scale_inv = scale.inverse(); 174 assert_approx_eq!($affine3::IDENTITY, scale * scale_inv); 175 assert_approx_eq!($affine3::IDENTITY, scale_inv * scale); 176 177 let m = scale * rotz * trans; 178 let m_inv = m.inverse(); 179 assert_approx_eq!($affine3::IDENTITY, m * m_inv, 1.0e-5); 180 assert_approx_eq!($affine3::IDENTITY, m_inv * m, 1.0e-5); 181 assert_approx_eq!(m_inv, trans_inv * rotz_inv * scale_inv, 1.0e-6); 182 183 // Make sure we can invert a shear matrix: 184 let m = $affine3::from_axis_angle($vec3::X, 0.5) 185 * $affine3::from_scale($vec3::new(1.0, 0.5, 2.0)) 186 * $affine3::from_axis_angle($vec3::X, -0.5); 187 let m_inv = m.inverse(); 188 assert_approx_eq!($affine3::IDENTITY, m * m_inv, 1.0e-5); 189 assert_approx_eq!($affine3::IDENTITY, m_inv * m, 1.0e-5); 190 191 should_glam_assert!({ $affine3::ZERO.inverse() }); 192 }); 193 194 glam_test!(test_affine3_decompose, { 195 // identity 196 let (out_scale, out_rotation, out_translation) = 197 $affine3::IDENTITY.to_scale_rotation_translation(); 198 assert_approx_eq!($vec3::ONE, out_scale); 199 assert!(out_rotation.is_near_identity()); 200 assert_approx_eq!($vec3::ZERO, out_translation); 201 202 // no scale 203 let in_scale = $vec3::ONE; 204 let in_translation = $vec3::new(-2.0, 4.0, -0.125); 205 let in_rotation = $quat::from_euler( 206 glam::EulerRot::YXZ, 207 $t::to_radians(-45.0), 208 $t::to_radians(180.0), 209 $t::to_radians(270.0), 210 ); 211 let in_mat = 212 $affine3::from_scale_rotation_translation(in_scale, in_rotation, in_translation); 213 let (out_scale, out_rotation, out_translation) = in_mat.to_scale_rotation_translation(); 214 assert_approx_eq!(in_scale, out_scale, 1e-6); 215 // out_rotation is different but produces the same matrix 216 // assert_approx_eq!(in_rotation, out_rotation); 217 assert_approx_eq!(in_translation, out_translation); 218 assert_approx_eq!( 219 in_mat, 220 $affine3::from_scale_rotation_translation(out_scale, out_rotation, out_translation), 221 1e-6 222 ); 223 224 // positive scale 225 let in_scale = $vec3::new(1.0, 2.0, 4.0); 226 let in_mat = 227 $affine3::from_scale_rotation_translation(in_scale, in_rotation, in_translation); 228 let (out_scale, out_rotation, out_translation) = in_mat.to_scale_rotation_translation(); 229 assert_approx_eq!(in_scale, out_scale, 1e-6); 230 // out_rotation is different but produces the same matrix 231 // assert_approx_eq!(in_rotation, out_rotation); 232 assert_approx_eq!(in_translation, out_translation); 233 assert_approx_eq!( 234 in_mat, 235 $affine3::from_scale_rotation_translation(out_scale, out_rotation, out_translation), 236 1e-5 237 ); 238 239 // negative scale 240 let in_scale = $vec3::new(-4.0, 1.0, 2.0); 241 let in_mat = 242 $affine3::from_scale_rotation_translation(in_scale, in_rotation, in_translation); 243 let (out_scale, out_rotation, out_translation) = in_mat.to_scale_rotation_translation(); 244 assert_approx_eq!(in_scale, out_scale, 1e-6); 245 // out_rotation is different but produces the same matrix 246 // assert_approx_eq!(in_rotation, out_rotation); 247 assert_approx_eq!(in_translation, out_translation); 248 assert_approx_eq!( 249 in_mat, 250 $affine3::from_scale_rotation_translation(out_scale, out_rotation, out_translation), 251 1e-5 252 ); 253 254 // negative scale 255 let in_scale = $vec3::new(4.0, -1.0, -2.0); 256 let in_mat = 257 $affine3::from_scale_rotation_translation(in_scale, in_rotation, in_translation); 258 let (out_scale, out_rotation, out_translation) = in_mat.to_scale_rotation_translation(); 259 // out_scale and out_rotation are different but they produce the same matrix 260 // assert_approx_eq!(in_scale, out_scale, 1e-6); 261 // assert_approx_eq!(in_rotation, out_rotation); 262 assert_approx_eq!(in_translation, out_translation); 263 assert_approx_eq!( 264 in_mat, 265 $affine3::from_scale_rotation_translation(out_scale, out_rotation, out_translation), 266 1e-6 267 ); 268 }); 269 270 glam_test!(test_affine3_look_at, { 271 let eye = $vec3::new(0.0, 0.0, -5.0); 272 let center = $vec3::new(0.0, 0.0, 0.0); 273 let up = $vec3::new(1.0, 0.0, 0.0); 274 275 let point = $vec3::new(1.0, 0.0, 0.0); 276 277 let lh = $affine3::look_at_lh(eye, center, up); 278 let rh = $affine3::look_at_rh(eye, center, up); 279 assert_approx_eq!(lh.transform_point3(point), $vec3::new(0.0, 1.0, 5.0)); 280 assert_approx_eq!(rh.transform_point3(point), $vec3::new(0.0, 1.0, -5.0)); 281 282 let dir = center - eye; 283 let lh = $affine3::look_to_lh(eye, dir, up); 284 let rh = $affine3::look_to_rh(eye, dir, up); 285 assert_approx_eq!(lh.transform_point3(point), $vec3::new(0.0, 1.0, 5.0)); 286 assert_approx_eq!(rh.transform_point3(point), $vec3::new(0.0, 1.0, -5.0)); 287 288 should_glam_assert!({ $affine3::look_at_lh($vec3::ONE, $vec3::ZERO, $vec3::ZERO) }); 289 should_glam_assert!({ $affine3::look_at_rh($vec3::ONE, $vec3::ZERO, $vec3::ZERO) }); 290 }); 291 292 glam_test!(test_affine3_ops, { 293 let m0 = $affine3::from_cols_array_2d(&MATRIX2D); 294 assert_approx_eq!(m0, m0 * $affine3::IDENTITY); 295 assert_approx_eq!(m0, $affine3::IDENTITY * m0); 296 297 let mut m1 = m0; 298 m1 *= $affine3::IDENTITY; 299 assert_approx_eq!(m1, m0); 300 301 let mat4 = $mat4::from(m0); 302 assert_approx_eq!(mat4, $affine3::IDENTITY * mat4); 303 assert_approx_eq!(mat4, mat4 * $affine3::IDENTITY); 304 }); 305 306 glam_test!(test_affine3_fmt, { 307 let a = $affine3::from_cols_array_2d(&MATRIX2D); 308 assert_eq!( 309 format!("{}", a), 310 "[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]" 311 ); 312 }); 313 314 glam_test!(test_affine3_to_from_slice, { 315 let m = $affine3::from_cols_slice(&MATRIX1D); 316 assert_eq!($affine3::from_cols_array(&MATRIX1D), m); 317 assert_eq!(MATRIX1D, m.to_cols_array()); 318 assert_eq!(MATRIX2D, m.to_cols_array_2d()); 319 let mut out: [$t; 12] = Default::default(); 320 m.write_cols_to_slice(&mut out); 321 assert_eq!(MATRIX1D, out); 322 assert_eq!( 323 m, 324 $affine3::from_cols( 325 MATRIX2D[0].into(), 326 MATRIX2D[1].into(), 327 MATRIX2D[2].into(), 328 MATRIX2D[3].into() 329 ) 330 ); 331 332 should_panic!({ $affine3::from_cols_slice(&[0.0; 11]) }); 333 should_panic!({ $affine3::IDENTITY.write_cols_to_slice(&mut [0.0; 11]) }); 334 }); 335 336 glam_test!(test_product, { 337 let ident = $affine3::IDENTITY; 338 assert_eq!([ident, ident].iter().product::<$affine3>(), ident * ident); 339 }); 340 341 glam_test!(test_affine3_is_finite, { 342 assert!($affine3::from_scale($vec3::new(1.0, 1.0, 1.0)).is_finite()); 343 assert!($affine3::from_scale($vec3::new(0.0, 1.0, 1.0)).is_finite()); 344 assert!(!$affine3::from_scale($vec3::new(1.0, NAN, 1.0)).is_finite()); 345 assert!(!$affine3::from_scale($vec3::new(1.0, 1.0, NEG_INFINITY)).is_finite()); 346 }); 347 }; 348 } 349 350 mod affine3a { 351 use super::support::{deg, FloatCompare}; 352 use glam::{Affine3A, Mat3, Mat4, Quat, Vec3, Vec3A}; 353 354 impl FloatCompare for Affine3A { 355 #[inline] approx_eq(&self, other: &Self, max_abs_diff: f32) -> bool356 fn approx_eq(&self, other: &Self, max_abs_diff: f32) -> bool { 357 self.abs_diff_eq(*other, max_abs_diff) 358 } 359 #[inline] abs_diff(&self, other: &Self) -> Self360 fn abs_diff(&self, other: &Self) -> Self { 361 Self { 362 matrix3: self.matrix3.abs_diff(&other.matrix3), 363 translation: self.translation.abs_diff(&other.translation), 364 } 365 } 366 } 367 368 glam_test!(test_align, { 369 use std::mem; 370 assert_eq!(64, mem::size_of::<Affine3A>()); 371 assert_eq!(mem::align_of::<Vec3A>(), mem::align_of::<Affine3A>()); 372 }); 373 374 glam_test!(test_affine3_mul_vec3a, { 375 let m = Affine3A::from_axis_angle(Vec3::Z, deg(90.0)); 376 let result3 = m.transform_vector3a(Vec3A::Y); 377 assert_approx_eq!(Vec3A::new(-1.0, 0.0, 0.0), result3); 378 379 let m = Affine3A::from_scale_rotation_translation( 380 Vec3::new(0.5, 1.5, 2.0), 381 Quat::from_rotation_x(deg(90.0)), 382 Vec3::new(1.0, 2.0, 3.0), 383 ); 384 let result3 = m.transform_vector3a(Vec3A::Y); 385 assert_approx_eq!(Vec3A::new(0.0, 0.0, 1.5), result3, 1.0e-6); 386 387 let result3 = m.transform_point3a(Vec3A::Y); 388 assert_approx_eq!(Vec3A::new(1.0, 2.0, 4.5), result3, 1.0e-6); 389 }); 390 391 impl_affine3_tests!(f32, Affine3A, Quat, Vec3, Mat3, Mat4); 392 } 393 394 mod daffine3 { 395 use super::support::{deg, FloatCompare}; 396 use glam::{DAffine3, DMat3, DMat4, DQuat, DVec3}; 397 398 impl FloatCompare for DAffine3 { 399 #[inline] approx_eq(&self, other: &Self, max_abs_diff: f32) -> bool400 fn approx_eq(&self, other: &Self, max_abs_diff: f32) -> bool { 401 self.abs_diff_eq(*other, max_abs_diff as f64) 402 } 403 #[inline] abs_diff(&self, other: &Self) -> Self404 fn abs_diff(&self, other: &Self) -> Self { 405 Self { 406 matrix3: self.matrix3.abs_diff(&other.matrix3), 407 translation: self.translation.abs_diff(&other.translation), 408 } 409 } 410 } 411 412 glam_test!(test_align, { 413 use std::mem; 414 assert_eq!(96, mem::size_of::<DAffine3>()); 415 assert_eq!(mem::align_of::<f64>(), mem::align_of::<DAffine3>()); 416 }); 417 418 impl_affine3_tests!(f64, DAffine3, DQuat, DVec3, DMat3, DMat4); 419 } 420