1 #[macro_use] 2 mod support; 3 4 macro_rules! impl_affine2_tests { 5 ($t:ident, $affine2:ident, $vec2:ident, $mat2:ident, $mat3:ident) => { 6 const MATRIX1D: [$t; 6] = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0]; 7 const MATRIX2D: [[$t; 2]; 3] = [[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]]; 8 9 use core::$t::NAN; 10 use core::$t::NEG_INFINITY; 11 12 glam_test!(test_affine2_identity, { 13 assert_eq!($affine2::IDENTITY, $affine2::IDENTITY * $affine2::IDENTITY); 14 assert_eq!($affine2::IDENTITY, $affine2::default()); 15 }); 16 17 glam_test!(test_affine2_zero, { 18 assert_eq!( 19 $affine2::ZERO.transform_point2($vec2::new(1., 2.)), 20 $vec2::ZERO 21 ); 22 }); 23 24 glam_test!(test_affine2_nan, { 25 assert!($affine2::NAN.is_nan()); 26 assert!(!$affine2::NAN.is_finite()); 27 }); 28 29 glam_test!(test_affine2_from_cols, { 30 let a = $affine2::from_cols( 31 $vec2::from_array(MATRIX2D[0]), 32 $vec2::from_array(MATRIX2D[1]), 33 $vec2::from_array(MATRIX2D[2]), 34 ); 35 assert_eq!(MATRIX2D, a.to_cols_array_2d()); 36 37 let a = $affine2::from_cols_array(&MATRIX1D); 38 assert_eq!(MATRIX1D, a.to_cols_array()); 39 40 let a = $affine2::from_cols_array_2d(&MATRIX2D); 41 assert_eq!(MATRIX2D, a.to_cols_array_2d()); 42 }); 43 44 glam_test!(test_affine2_deref, { 45 let a = $affine2::from_cols_array_2d(&MATRIX2D); 46 assert_eq!(MATRIX2D[0], a.x_axis.to_array()); 47 assert_eq!(MATRIX2D[1], a.y_axis.to_array()); 48 assert_eq!(MATRIX2D[2], a.z_axis.to_array()); 49 50 let mut b = a; 51 b.x_axis *= 0.0; 52 b.y_axis *= 0.0; 53 b.z_axis *= 0.0; 54 assert_eq!($affine2::ZERO, b); 55 }); 56 57 glam_test!(test_affine2_from_mat2, { 58 let m = $mat2::from_cols_array_2d(&[MATRIX2D[0], MATRIX2D[1]]); 59 let a = $affine2::from_mat2(m); 60 assert_eq!(m, a.matrix2); 61 assert_eq!($vec2::ZERO, a.translation); 62 63 let t = $vec2::from_array(MATRIX2D[2]); 64 let a = $affine2::from_mat2_translation(m, t); 65 assert_eq!(MATRIX2D, a.to_cols_array_2d()); 66 }); 67 68 glam_test!(test_affine2_from_mat3, { 69 let m = $mat3::from_cols_array_2d(&[[1.0, 2.0, 0.0], [3.0, 4.0, 0.0], [5.0, 6.0, 1.0]]); 70 let a = $affine2::from_mat3(m); 71 assert_eq!(MATRIX2D, a.to_cols_array_2d()); 72 73 assert_eq!(m, $mat3::from(a)); 74 }); 75 76 glam_test!(test_affine2_translation, { 77 let translate = $affine2::from_translation($vec2::new(1.0, 2.0)); 78 assert_eq!(translate.translation, $vec2::new(1.0, 2.0).into()); 79 assert_eq!( 80 translate.transform_point2($vec2::new(2.0, 3.0)), 81 $vec2::new(3.0, 5.0), 82 ); 83 }); 84 85 glam_test!(test_affine2_mul, { 86 let m = $affine2::from_angle(deg(90.0)); 87 let result3 = m.transform_vector2($vec2::Y); 88 assert_approx_eq!($vec2::new(-1.0, 0.0), result3); 89 90 let m = $affine2::from_angle_translation(deg(90.0), $vec2::new(1.0, 2.0)); 91 let result3 = m.transform_vector2($vec2::Y); 92 assert_approx_eq!($vec2::new(-1.0, 0.0), result3, 1.0e-6); 93 94 let m = $affine2::from_scale_angle_translation( 95 $vec2::new(0.5, 1.5), 96 deg(90.0), 97 $vec2::new(1.0, 2.0), 98 ); 99 let result3 = m.transform_vector2($vec2::Y); 100 assert_approx_eq!($vec2::new(-1.5, 0.0), result3, 1.0e-6); 101 102 let result3 = m.transform_point2($vec2::Y); 103 assert_approx_eq!($vec2::new(-0.5, 2.0), result3, 1.0e-6); 104 }); 105 106 glam_test!(test_from_scale, { 107 let m = $affine2::from_scale($vec2::new(2.0, 4.0)); 108 assert_approx_eq!( 109 m.transform_point2($vec2::new(1.0, 1.0)), 110 $vec2::new(2.0, 4.0) 111 ); 112 }); 113 114 glam_test!(test_affine2_inverse, { 115 let inv = $affine2::IDENTITY.inverse(); 116 assert_approx_eq!($affine2::IDENTITY, inv); 117 118 let rot = $affine2::from_angle(deg(90.0)); 119 let rot_inv = rot.inverse(); 120 assert_approx_eq!($affine2::IDENTITY, rot * rot_inv); 121 assert_approx_eq!($affine2::IDENTITY, rot_inv * rot); 122 123 let trans = $affine2::from_translation($vec2::new(1.0, 2.0)); 124 let trans_inv = trans.inverse(); 125 assert_approx_eq!($affine2::IDENTITY, trans * trans_inv); 126 assert_approx_eq!($affine2::IDENTITY, trans_inv * trans); 127 128 let scale = $affine2::from_scale($vec2::new(4.0, 5.0)); 129 let scale_inv = scale.inverse(); 130 assert_approx_eq!($affine2::IDENTITY, scale * scale_inv); 131 assert_approx_eq!($affine2::IDENTITY, scale_inv * scale); 132 133 let m = scale * rot * trans; 134 let m_inv = m.inverse(); 135 assert_approx_eq!($affine2::IDENTITY, m * m_inv, 1.0e-5); 136 assert_approx_eq!($affine2::IDENTITY, m_inv * m, 1.0e-5); 137 assert_approx_eq!(m_inv, trans_inv * rot_inv * scale_inv, 1.0e-6); 138 139 // Make sure we can invert a shear matrix: 140 let m = $affine2::from_angle(0.5) 141 * $affine2::from_scale($vec2::new(1.0, 0.5)) 142 * $affine2::from_angle(-0.5); 143 let m_inv = m.inverse(); 144 assert_approx_eq!($affine2::IDENTITY, m * m_inv, 1.0e-5); 145 assert_approx_eq!($affine2::IDENTITY, m_inv * m, 1.0e-5); 146 147 should_glam_assert!({ $affine2::ZERO.inverse() }); 148 }); 149 150 glam_test!(test_affine2_decompose, { 151 // identity 152 let (out_scale, out_rotation, out_translation) = 153 $affine2::IDENTITY.to_scale_angle_translation(); 154 assert_approx_eq!($vec2::ONE, out_scale); 155 assert_eq!(out_rotation, 0.0); 156 assert_approx_eq!($vec2::ZERO, out_translation); 157 158 // no scale 159 let in_scale = $vec2::ONE; 160 let in_translation = $vec2::new(-2.0, 4.0); 161 let in_rotation = $t::to_radians(-45.0); 162 let in_mat = 163 $affine2::from_scale_angle_translation(in_scale, in_rotation, in_translation); 164 let (out_scale, out_rotation, out_translation) = in_mat.to_scale_angle_translation(); 165 assert_approx_eq!(in_scale, out_scale, 1e-6); 166 assert_approx_eq!(in_rotation, out_rotation); 167 assert_approx_eq!(in_translation, out_translation); 168 assert_approx_eq!( 169 in_mat, 170 $affine2::from_scale_angle_translation(out_scale, out_rotation, out_translation), 171 1e-6 172 ); 173 174 // positive scale 175 let in_scale = $vec2::new(1.0, 2.0); 176 let in_mat = 177 $affine2::from_scale_angle_translation(in_scale, in_rotation, in_translation); 178 let (out_scale, out_rotation, out_translation) = in_mat.to_scale_angle_translation(); 179 assert_approx_eq!(in_scale, out_scale, 1e-6); 180 assert_approx_eq!(in_rotation, out_rotation); 181 assert_approx_eq!(in_translation, out_translation); 182 assert_approx_eq!( 183 in_mat, 184 $affine2::from_scale_angle_translation(out_scale, out_rotation, out_translation), 185 1e-5 186 ); 187 188 // negative scale 189 let in_scale = $vec2::new(-4.0, 1.0); 190 let in_mat = 191 $affine2::from_scale_angle_translation(in_scale, in_rotation, in_translation); 192 let (out_scale, out_rotation, out_translation) = in_mat.to_scale_angle_translation(); 193 assert_approx_eq!(in_scale, out_scale, 1e-6); 194 assert_approx_eq!(in_rotation, out_rotation); 195 assert_approx_eq!(in_translation, out_translation); 196 assert_approx_eq!( 197 in_mat, 198 $affine2::from_scale_angle_translation(out_scale, out_rotation, out_translation), 199 1e-5 200 ); 201 202 // negative scale 203 let in_scale = $vec2::new(4.0, -1.0); 204 let in_mat = 205 $affine2::from_scale_angle_translation(in_scale, in_rotation, in_translation); 206 let (out_scale, out_rotation, out_translation) = in_mat.to_scale_angle_translation(); 207 // out_scale and out_rotation are different but they produce the same matrix 208 // assert_approx_eq!(in_scale, out_scale, 1e-6); 209 // assert_approx_eq!(in_rotation, out_rotation); 210 assert_approx_eq!(in_translation, out_translation); 211 assert_approx_eq!( 212 in_mat, 213 $affine2::from_scale_angle_translation(out_scale, out_rotation, out_translation), 214 1e-6 215 ); 216 }); 217 218 glam_test!(test_affine2_ops, { 219 let m0 = $affine2::from_cols_array_2d(&MATRIX2D); 220 assert_approx_eq!(m0, m0 * $affine2::IDENTITY); 221 assert_approx_eq!(m0, $affine2::IDENTITY * m0); 222 223 let mut m1 = m0; 224 m1 *= $affine2::IDENTITY; 225 assert_approx_eq!(m1, m0); 226 227 let mat3 = $mat3::from(m0); 228 assert_approx_eq!(mat3, $affine2::IDENTITY * mat3); 229 assert_approx_eq!(mat3, mat3 * $affine2::IDENTITY); 230 }); 231 232 glam_test!(test_affine2_fmt, { 233 let a = $affine2::from_cols_array_2d(&MATRIX2D); 234 assert_eq!(format!("{}", a), "[[1, 2], [3, 4], [5, 6]]"); 235 }); 236 237 glam_test!(test_affine2_to_from_slice, { 238 let m = $affine2::from_cols_slice(&MATRIX1D); 239 assert_eq!($affine2::from_cols_array(&MATRIX1D), m); 240 assert_eq!(MATRIX1D, m.to_cols_array()); 241 assert_eq!(MATRIX2D, m.to_cols_array_2d()); 242 let mut out: [$t; 6] = Default::default(); 243 m.write_cols_to_slice(&mut out); 244 assert_eq!(MATRIX1D, out); 245 assert_eq!( 246 m, 247 $affine2::from_cols(MATRIX2D[0].into(), MATRIX2D[1].into(), MATRIX2D[2].into()) 248 ); 249 250 should_panic!({ $affine2::from_cols_slice(&[0.0; 5]) }); 251 should_panic!({ $affine2::IDENTITY.write_cols_to_slice(&mut [0.0; 5]) }); 252 }); 253 254 glam_test!(test_product, { 255 let ident = $affine2::IDENTITY; 256 assert_eq!([ident, ident].iter().product::<$affine2>(), ident * ident); 257 }); 258 259 glam_test!(test_affine2_is_finite, { 260 assert!($affine2::from_scale($vec2::new(1.0, 1.0)).is_finite()); 261 assert!($affine2::from_scale($vec2::new(0.0, 1.0)).is_finite()); 262 assert!(!$affine2::from_scale($vec2::new(1.0, NAN)).is_finite()); 263 assert!(!$affine2::from_scale($vec2::new(1.0, NEG_INFINITY)).is_finite()); 264 }); 265 }; 266 } 267 268 mod affine2 { 269 use super::support::{deg, FloatCompare}; 270 use glam::{Affine2, Mat2, Mat3, Vec2}; 271 272 impl FloatCompare for Affine2 { 273 #[inline] approx_eq(&self, other: &Self, max_abs_diff: f32) -> bool274 fn approx_eq(&self, other: &Self, max_abs_diff: f32) -> bool { 275 self.abs_diff_eq(*other, max_abs_diff) 276 } 277 #[inline] abs_diff(&self, other: &Self) -> Self278 fn abs_diff(&self, other: &Self) -> Self { 279 Self { 280 matrix2: self.matrix2.abs_diff(&other.matrix2), 281 translation: self.translation.abs_diff(&other.translation), 282 } 283 } 284 } 285 286 glam_test!(test_align, { 287 use std::mem; 288 if cfg!(not(feature = "scalar-math")) { 289 assert_eq!(32, mem::size_of::<Affine2>()); 290 assert_eq!(16, mem::align_of::<Affine2>()); 291 } else if cfg!(feature = "cuda") { 292 assert_eq!(24, mem::size_of::<Affine2>()); 293 assert_eq!(8, mem::align_of::<Affine2>()); 294 } else { 295 assert_eq!(24, mem::size_of::<Affine2>()); 296 assert_eq!(4, mem::align_of::<Affine2>()); 297 } 298 }); 299 300 glam_test!(test_affine2_from_mat3a, { 301 use glam::Mat3A; 302 let m = Mat3A::from_cols_array_2d(&[[1.0, 2.0, 0.0], [3.0, 4.0, 0.0], [5.0, 6.0, 1.0]]); 303 let a = Affine2::from_mat3a(m); 304 assert_eq!(MATRIX2D, a.to_cols_array_2d()); 305 306 assert_eq!(m, Mat3A::from(a)); 307 }); 308 309 impl_affine2_tests!(f32, Affine2, Vec2, Mat2, Mat3); 310 } 311 312 mod daffine2 { 313 use super::support::{deg, FloatCompare}; 314 use glam::{DAffine2, DMat2, DMat3, DVec2}; 315 316 impl FloatCompare for DAffine2 { 317 #[inline] approx_eq(&self, other: &Self, max_abs_diff: f32) -> bool318 fn approx_eq(&self, other: &Self, max_abs_diff: f32) -> bool { 319 self.abs_diff_eq(*other, max_abs_diff as f64) 320 } 321 #[inline] abs_diff(&self, other: &Self) -> Self322 fn abs_diff(&self, other: &Self) -> Self { 323 Self { 324 matrix2: self.matrix2.abs_diff(&other.matrix2), 325 translation: self.translation.abs_diff(&other.translation), 326 } 327 } 328 } 329 330 #[cfg(not(feature = "cuda"))] 331 glam_test!(test_align, { 332 use std::mem; 333 assert_eq!(48, mem::size_of::<DAffine2>()); 334 assert_eq!(mem::align_of::<f64>(), mem::align_of::<DAffine2>()); 335 }); 336 337 #[cfg(feature = "cuda")] 338 glam_test!(test_align, { 339 use std::mem; 340 assert_eq!(48, mem::size_of::<DAffine2>()); 341 assert_eq!(16, mem::align_of::<DAffine2>()); 342 }); 343 344 impl_affine2_tests!(f64, DAffine2, DVec2, DMat2, DMat3); 345 } 346