1use crate::{Affine2, Affine3, Affine3A, Mat2, Mat3, Mat3A, Mat4, Quat, Vec2, Vec3, Vec3A, Vec4};
2#[cfg(feature = "f64")]
3use crate::{DAffine2, DAffine3, DMat2, DMat3, DMat4, DQuat, DVec2, DVec3, DVec4};
4use approx_05::{AbsDiffEq, RelativeEq, UlpsEq};
5
6macro_rules! impl_approx_as_ref {
7 ($prim:ident, $type:ty) => {
8 impl AbsDiffEq for $type {
9 type Epsilon = <$prim as AbsDiffEq>::Epsilon;
10 fn default_epsilon() -> Self::Epsilon {
11 $prim::default_epsilon()
12 }
13 fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
14 self.as_ref().abs_diff_eq(other.as_ref(), epsilon)
15 }
16 }
17
18 impl RelativeEq for $type {
19 fn default_max_relative() -> Self::Epsilon {
20 $prim::default_max_relative()
21 }
22 fn relative_eq(
23 &self,
24 other: &Self,
25 epsilon: Self::Epsilon,
26 max_relative: Self::Epsilon,
27 ) -> bool {
28 self.as_ref()
29 .relative_eq(other.as_ref(), epsilon, max_relative)
30 }
31 }
32
33 impl UlpsEq for $type {
34 fn default_max_ulps() -> u32 {
35 $prim::default_max_ulps()
36 }
37 fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
38 self.as_ref().ulps_eq(other.as_ref(), epsilon, max_ulps)
39 }
40 }
41 };
42}
43
44macro_rules! impl_approx_xzy_axes {
45 ($prim:ident, $type:ty) => {
46 impl AbsDiffEq for $type {
47 type Epsilon = <$prim as AbsDiffEq>::Epsilon;
48 fn default_epsilon() -> Self::Epsilon {
49 $prim::default_epsilon()
50 }
51 fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
52 AbsDiffEq::abs_diff_eq(&self.x_axis, &other.x_axis, epsilon)
53 && AbsDiffEq::abs_diff_eq(&self.y_axis, &other.y_axis, epsilon)
54 && AbsDiffEq::abs_diff_eq(&self.z_axis, &other.z_axis, epsilon)
55 }
56 }
57
58 impl RelativeEq for $type {
59 fn default_max_relative() -> Self::Epsilon {
60 $prim::default_max_relative()
61 }
62 fn relative_eq(
63 &self,
64 other: &Self,
65 epsilon: Self::Epsilon,
66 max_relative: Self::Epsilon,
67 ) -> bool {
68 RelativeEq::relative_eq(&self.x_axis, &other.x_axis, epsilon, max_relative)
69 && RelativeEq::relative_eq(&self.y_axis, &other.y_axis, epsilon, max_relative)
70 && RelativeEq::relative_eq(&self.z_axis, &other.z_axis, epsilon, max_relative)
71 }
72 }
73
74 impl UlpsEq for $type {
75 fn default_max_ulps() -> u32 {
76 $prim::default_max_ulps()
77 }
78 fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
79 UlpsEq::ulps_eq(&self.x_axis, &other.x_axis, epsilon, max_ulps)
80 && UlpsEq::ulps_eq(&self.y_axis, &other.y_axis, epsilon, max_ulps)
81 && UlpsEq::ulps_eq(&self.z_axis, &other.z_axis, epsilon, max_ulps)
82 }
83 }
84 };
85}
86
87macro_rules! impl_approx_xzyw_axes {
88 ($prim:ident, $type:ty) => {
89 impl AbsDiffEq for $type {
90 type Epsilon = <$prim as AbsDiffEq>::Epsilon;
91 fn default_epsilon() -> Self::Epsilon {
92 $prim::default_epsilon()
93 }
94 fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
95 AbsDiffEq::abs_diff_eq(&self.x_axis, &other.x_axis, epsilon)
96 && AbsDiffEq::abs_diff_eq(&self.y_axis, &other.y_axis, epsilon)
97 && AbsDiffEq::abs_diff_eq(&self.z_axis, &other.z_axis, epsilon)
98 && AbsDiffEq::abs_diff_eq(&self.w_axis, &other.w_axis, epsilon)
99 }
100 }
101
102 impl RelativeEq for $type {
103 fn default_max_relative() -> Self::Epsilon {
104 $prim::default_max_relative()
105 }
106 fn relative_eq(
107 &self,
108 other: &Self,
109 epsilon: Self::Epsilon,
110 max_relative: Self::Epsilon,
111 ) -> bool {
112 RelativeEq::relative_eq(&self.x_axis, &other.x_axis, epsilon, max_relative)
113 && RelativeEq::relative_eq(&self.y_axis, &other.y_axis, epsilon, max_relative)
114 && RelativeEq::relative_eq(&self.z_axis, &other.z_axis, epsilon, max_relative)
115 && RelativeEq::relative_eq(&self.w_axis, &other.w_axis, epsilon, max_relative)
116 }
117 }
118
119 impl UlpsEq for $type {
120 fn default_max_ulps() -> u32 {
121 $prim::default_max_ulps()
122 }
123 fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
124 UlpsEq::ulps_eq(&self.x_axis, &other.x_axis, epsilon, max_ulps)
125 && UlpsEq::ulps_eq(&self.y_axis, &other.y_axis, epsilon, max_ulps)
126 && UlpsEq::ulps_eq(&self.z_axis, &other.z_axis, epsilon, max_ulps)
127 && UlpsEq::ulps_eq(&self.w_axis, &other.w_axis, epsilon, max_ulps)
128 }
129 }
130 };
131}
132
133impl_approx_as_ref!(f32, Mat2);
134impl_approx_as_ref!(f32, Mat3);
135impl_approx_as_ref!(f32, Mat4);
136impl_approx_as_ref!(f32, Quat);
137impl_approx_as_ref!(f32, Vec2);
138impl_approx_as_ref!(f32, Vec3);
139impl_approx_as_ref!(f32, Vec4);
140impl_approx_as_ref!(f32, Vec3A);
141
142impl_approx_xzy_axes!(f32, Affine2);
143impl_approx_xzyw_axes!(f32, Affine3);
144impl_approx_xzyw_axes!(f32, Affine3A);
145impl_approx_xzy_axes!(f32, Mat3A);
146
147#[cfg(feature = "f64")]
148impl_approx_xzy_axes!(f64, DAffine2);
149#[cfg(feature = "f64")]
150impl_approx_xzyw_axes!(f64, DAffine3);
151#[cfg(feature = "f64")]
152impl_approx_as_ref!(f64, DMat2);
153#[cfg(feature = "f64")]
154impl_approx_as_ref!(f64, DMat3);
155#[cfg(feature = "f64")]
156impl_approx_as_ref!(f64, DMat4);
157#[cfg(feature = "f64")]
158impl_approx_as_ref!(f64, DQuat);
159#[cfg(feature = "f64")]
160impl_approx_as_ref!(f64, DVec2);
161#[cfg(feature = "f64")]
162impl_approx_as_ref!(f64, DVec3);
163#[cfg(feature = "f64")]
164impl_approx_as_ref!(f64, DVec4);
165
166#[cfg(test)]
167mod test {
168 use crate::*;
169 use approx_05::{self as approx, *};
170
171 macro_rules! impl_approx_test {
172 ($prim:ident, $type:ident, $ones:expr) => {
173 let one_eps = $ones * $type::default_epsilon();
174 let two_eps = one_eps + one_eps;
175
176 let one_ulp = $ones * $prim::from_bits($prim::to_bits(1.0) + 1);
177 let four_ulp = $ones * $prim::from_bits($prim::to_bits(1.0) + 16);
178
179 approx::assert_abs_diff_eq!($ones, $ones);
180 approx::assert_abs_diff_eq!($ones, $ones + one_eps);
181 approx::assert_abs_diff_eq!($ones, $ones - one_eps);
182
183 approx::assert_abs_diff_ne!($ones, $ones + two_eps);
184 approx::assert_abs_diff_ne!($ones, $ones - two_eps);
185
186 approx::assert_relative_eq!($ones, $ones);
187 approx::assert_relative_ne!($ones, $ones - $ones);
188
189 approx::assert_ulps_eq!($ones, one_ulp);
191 approx::assert_ulps_ne!($ones, four_ulp);
192 };
193 ($prim:ident, $type:ident) => {
194 impl_approx_test!($prim, $type, $type::ONE)
195 };
196 }
197
198 macro_rules! impl_affine_approx_test {
199 ($prim:ident, $type:ident, $from:ident, $mat:ident, $ones:expr) => {
200 let ones = $mat::from($ones);
201 let one_eps = ones * $mat::default_epsilon();
202 let two_eps = one_eps + one_eps;
203
204 let one_ulp = ones * $prim::from_bits($prim::to_bits(1.0) + 1);
205 let four_ulp = ones * $prim::from_bits($prim::to_bits(1.0) + 16);
206
207 approx::assert_abs_diff_eq!($type::$from(ones), $type::$from(ones));
208 approx::assert_abs_diff_eq!($type::$from(ones), $type::$from(ones + one_eps));
209 approx::assert_abs_diff_eq!($type::$from(ones), $type::$from(ones - one_eps));
210
211 approx::assert_abs_diff_ne!($type::$from(ones), $type::$from(ones + two_eps));
212 approx::assert_abs_diff_ne!($type::$from(ones), $type::$from(ones - two_eps));
213
214 approx::assert_relative_eq!($type::$from(ones), $type::$from(ones));
215 approx::assert_relative_ne!($type::$from(ones), $type::$from(ones - ones));
216
217 approx::assert_ulps_eq!($type::$from(ones), $type::$from(one_ulp));
219 approx::assert_ulps_ne!($type::$from(ones), $type::$from(four_ulp));
220 };
221 }
222 #[test]
223 fn test_approx() {
224 const ONESF32: [f32; 16] = [1.0; 16];
225
226 impl_approx_test!(f32, Vec2);
227 impl_approx_test!(f32, Vec3);
228 impl_approx_test!(f32, Vec3A);
229 impl_approx_test!(f32, Vec4);
230 impl_approx_test!(f32, Quat, Quat::from_slice(&ONESF32));
231 impl_approx_test!(f32, Mat2, Mat2::from_cols_slice(&ONESF32));
232 impl_approx_test!(f32, Mat3, Mat3::from_cols_slice(&ONESF32));
233 impl_approx_test!(f32, Mat3A, Mat3A::from_cols_slice(&ONESF32));
234 impl_approx_test!(f32, Mat4, Mat4::from_cols_slice(&ONESF32));
235 impl_affine_approx_test!(
236 f32,
237 Affine2,
238 from_mat3,
239 Mat3,
240 Affine2::from_cols_slice(&ONESF32)
241 );
242 impl_affine_approx_test!(
243 f32,
244 Affine3,
245 from_mat4,
246 Mat4,
247 Affine3::from_cols_slice(&ONESF32)
248 );
249 impl_affine_approx_test!(
250 f32,
251 Affine3A,
252 from_mat4,
253 Mat4,
254 Affine3A::from_cols_slice(&ONESF32)
255 );
256
257 #[cfg(feature = "f64")]
258 {
259 const ONESF64: [f64; 16] = [1.0; 16];
260 impl_approx_test!(f64, DVec2);
261 impl_approx_test!(f64, DVec3);
262 impl_approx_test!(f64, DVec4);
263 impl_approx_test!(f64, DQuat, DQuat::from_slice(&ONESF64));
264 impl_approx_test!(f64, DMat2, DMat2::from_cols_slice(&ONESF64));
265 impl_approx_test!(f64, DMat3, DMat3::from_cols_slice(&ONESF64));
266 impl_approx_test!(f64, DMat4, DMat4::from_cols_slice(&ONESF64));
267 impl_affine_approx_test!(
268 f64,
269 DAffine2,
270 from_mat3,
271 DMat3,
272 DAffine2::from_cols_slice(&ONESF64)
273 );
274 impl_affine_approx_test!(
275 f64,
276 DAffine3,
277 from_mat4,
278 DMat4,
279 DAffine3::from_cols_slice(&ONESF64)
280 );
281 }
282 }
283}