aboutsummaryrefslogtreecommitdiff
path: root/tests/euler.rs
diff options
context:
space:
mode:
Diffstat (limited to 'tests/euler.rs')
-rw-r--r--tests/euler.rs106
1 files changed, 57 insertions, 49 deletions
diff --git a/tests/euler.rs b/tests/euler.rs
index dc4de53..b2d0726 100644
--- a/tests/euler.rs
+++ b/tests/euler.rs
@@ -1,47 +1,53 @@
#[macro_use]
mod support;
-/// Helper to calculate the inner angle in the range [0, 2*PI)
-trait AngleDiff {
- type Output;
- fn angle_diff(self, other: Self) -> Self::Output;
+/// Helper to get the 'canonical' version of a `Quat`. We define the canonical of quat `q` as:
+/// * `q`, if q.w > epsilon
+/// * `-q`, if q.w < -epsilon
+/// * `(0, 0, 0, 1)` otherwise
+/// The rationale is that q and -q represent the same rotation, and any (_, _, _, 0) respresent no rotation at all.
+trait CanonicalQuat: Copy {
+ fn canonical(self) -> Self;
}
-macro_rules! impl_angle_diff {
- ($t:ty, $pi:expr) => {
- impl AngleDiff for $t {
- type Output = $t;
- fn angle_diff(self, other: $t) -> $t {
- const PI2: $t = $pi + $pi;
- let s = self.rem_euclid(PI2);
- let o = other.rem_euclid(PI2);
- if s > o {
- (s - o).min(PI2 + o - s)
- } else {
- (o - s).min(PI2 + s - o)
+macro_rules! impl_canonical_quat {
+ ($t:ty) => {
+ impl CanonicalQuat for $t {
+ fn canonical(self) -> Self {
+ match self {
+ _ if self.w >= 1e-5 => self,
+ _ if self.w <= -1e-5 => -self,
+ _ => <$t>::from_xyzw(0.0, 0.0, 0.0, 1.0),
}
}
}
};
}
-impl_angle_diff!(f32, std::f32::consts::PI);
-impl_angle_diff!(f64, std::f64::consts::PI);
-
-macro_rules! assert_approx_angle {
- ($a:expr, $b:expr, $eps:expr) => {{
- let (a, b) = ($a, $b);
- let eps = $eps;
- let diff = a.angle_diff(b);
- assert!(
- diff < $eps,
- "assertion failed: `(left !== right)` \
- (left: `{:?}`, right: `{:?}`, expect diff: `{:?}`, real diff: `{:?}`)",
- a,
- b,
- eps,
- diff
- );
- }};
+
+impl_canonical_quat!(glam::Quat);
+impl_canonical_quat!(glam::DQuat);
+
+/// Helper to set some alternative epsilons based on the floating point type used
+trait EulerEpsilon {
+ /// epsilon for comparing quaterions built from eulers and axis-angles
+ const Q_EPS: f32;
+
+ /// epsilon for comparing quaternion round-tripped through eulers (quat -> euler -> quat)
+ const E_EPS: f32;
+}
+impl EulerEpsilon for f32 {
+ const Q_EPS: f32 = 1e-5;
+
+ // The scalar-math and wasm paths seems to use a particularly bad implementation of the trig functions
+ #[cfg(any(feature = "scalar-math", target_arch = "wasm32"))]
+ const E_EPS: f32 = 2e-4;
+
+ #[cfg(not(any(feature = "scalar-math", target_arch = "wasm32")))]
+ const E_EPS: f32 = 1e-5;
+}
+impl EulerEpsilon for f64 {
+ const Q_EPS: f32 = 1e-8;
+ const E_EPS: f32 = 1e-8;
}
macro_rules! impl_3axis_test {
@@ -49,9 +55,9 @@ macro_rules! impl_3axis_test {
glam_test!($name, {
let euler = $euler;
assert!($U != $W); // First and last axis must be different for three axis
- for u in (-176..=176).step_by(44) {
- for v in (-88..=88).step_by(44) {
- for w in (-176..=176).step_by(44) {
+ for u in (-180..=180).step_by(15) {
+ for v in (-180..=180).step_by(15) {
+ for w in (-180..=180).step_by(15) {
let u1 = (u as $t).to_radians();
let v1 = (v as $t).to_radians();
let w1 = (w as $t).to_radians();
@@ -63,19 +69,21 @@ macro_rules! impl_3axis_test {
// Test if the rotation is the expected
let q2: $quat = $quat::from_euler(euler, u1, v1, w1).normalize();
- assert_approx_eq!(q1, q2, 1e-5);
+ assert_approx_eq!(q1.canonical(), q2.canonical(), <$t>::Q_EPS);
- // Test angle reconstruction
- let (u2, v2, w2) = q1.to_euler(euler);
+ // Test quat reconstruction from angles
+ let (u2, v2, w2) = q2.to_euler(euler);
let q3 = $quat::from_euler(euler, u2, v2, w2).normalize();
-
- assert_approx_angle!(u1, u2, 1e-4 as $t);
- assert_approx_angle!(v1, v2, 1e-4 as $t);
- assert_approx_angle!(w1, w2, 1e-4 as $t);
-
- assert_approx_eq!(q1 * $vec::X, q3 * $vec::X, 1e-4);
- assert_approx_eq!(q1 * $vec::Y, q3 * $vec::Y, 1e-4);
- assert_approx_eq!(q1 * $vec::Z, q3 * $vec::Z, 1e-4);
+ assert_approx_eq!(
+ q2.canonical(),
+ q3.canonical(),
+ <$t>::E_EPS,
+ format!(
+ "angles {:?} -> {:?}",
+ (u, v, w),
+ (u2.to_degrees(), v2.to_degrees(), w2.to_degrees())
+ )
+ );
}
}
}
@@ -95,7 +103,7 @@ macro_rules! impl_all_quat_tests_three_axis {
}
mod euler {
- use super::AngleDiff;
+ use super::{CanonicalQuat, EulerEpsilon};
use glam::*;
type ER = EulerRot;