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, 49 insertions, 57 deletions
diff --git a/tests/euler.rs b/tests/euler.rs
index b2d0726..dc4de53 100644
--- a/tests/euler.rs
+++ b/tests/euler.rs
@@ -1,53 +1,47 @@
#[macro_use]
mod support;
-/// 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;
+/// Helper to calculate the inner angle in the range [0, 2*PI)
+trait AngleDiff {
+ type Output;
+ fn angle_diff(self, other: Self) -> Self::Output;
}
-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),
+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)
}
}
}
};
}
-
-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;
+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
+ );
+ }};
}
macro_rules! impl_3axis_test {
@@ -55,9 +49,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 (-180..=180).step_by(15) {
- for v in (-180..=180).step_by(15) {
- for w in (-180..=180).step_by(15) {
+ for u in (-176..=176).step_by(44) {
+ for v in (-88..=88).step_by(44) {
+ for w in (-176..=176).step_by(44) {
let u1 = (u as $t).to_radians();
let v1 = (v as $t).to_radians();
let w1 = (w as $t).to_radians();
@@ -69,21 +63,19 @@ 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.canonical(), q2.canonical(), <$t>::Q_EPS);
+ assert_approx_eq!(q1, q2, 1e-5);
- // Test quat reconstruction from angles
- let (u2, v2, w2) = q2.to_euler(euler);
+ // Test angle reconstruction
+ let (u2, v2, w2) = q1.to_euler(euler);
let q3 = $quat::from_euler(euler, u2, v2, w2).normalize();
- assert_approx_eq!(
- q2.canonical(),
- q3.canonical(),
- <$t>::E_EPS,
- format!(
- "angles {:?} -> {:?}",
- (u, v, w),
- (u2.to_degrees(), v2.to_degrees(), w2.to_degrees())
- )
- );
+
+ 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);
}
}
}
@@ -103,7 +95,7 @@ macro_rules! impl_all_quat_tests_three_axis {
}
mod euler {
- use super::{CanonicalQuat, EulerEpsilon};
+ use super::AngleDiff;
use glam::*;
type ER = EulerRot;