From b1901e019abe52547190e20d8d57b7fceb8b590c Mon Sep 17 00:00:00 2001 From: "Sam H. Smith" Date: Thu, 3 Feb 2022 21:10:06 +0100 Subject: [PATCH] from access angle, multiply operator and test --- src/lib.rs | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 9ae45ba..087c6a0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -38,6 +38,17 @@ impl Quaternion where T : Float { Self { w, x, y, z } } + pub fn from_axis_angle(axis : [T; 3], angle_in_radians : T) -> Self + { + let (sin, cos) = T::sin_cos(angle_in_radians / (T::one() + T::one())); + Quaternion + { + w : cos, + x : axis[0] * sin, + y : axis[1] * sin, + z : axis[2] * sin, + } + } pub fn approx_equal(a : Quaternion, b : Quaternion, close_enough : T) -> bool { (a.w - b.w).abs() < close_enough && @@ -92,6 +103,23 @@ impl Quaternion where T : Float } } +/* +Implementing the multiply operator for quaternion * quaternion +is appropriate because they are associative. +q1 * (q2 * q3) = (q1 * q2) * q3 + +It is not appropriate to implement multiply for scalar * quaternion because +that will have very different results based on the operation order. +(q1 * s) * q2 != q1 * (s * q2) +*/ +impl std::ops::Mul for Quaternion where T : Float +{ + type Output = Self; + + fn mul(self, rhs : Self) -> Self + { Quaternion::mul(self, rhs) } +} + #[cfg(test)] mod tests { use crate::Quaternion; @@ -141,4 +169,25 @@ mod tests { Quaternion::div(Quaternion::mul(Quaternion::new(4.0,3.0,2.0,1.0), Quaternion::new(1.0,2.0,3.0,4.0)), Quaternion::new(1.0,2.0,3.0,4.0)), Quaternion::new(4.0,3.0,2.0,1.0), 0.01)); } + + #[test] + fn test_operator_overloading() + { + let q1 = Quaternion::::new(1.0, 2.0, 4.0, 8.0); + let q2 = Quaternion::::new(0.0, 1.0, 3.0, 9.0); + let q3 = Quaternion::::new(8.0, 4.0, 2.0, 1.0); + + assert_eq!((q1 * q2) * q3, q1 * (q2 * q3)); + assert_ne!((q1 * q2) * q3, q1 * (q3 * q2)); + } + + #[test] + fn test_full_rotation_on_the_4d_hyper_sphere_is_720_degrees() + { + let point = Quaternion::::new(0.0, 2.0, 8.0, 1.0); + let d360 = Quaternion::::from_axis_angle([1.0, 0.0, 0.0], std::f64::consts::PI * 2.0); + + assert!(!Quaternion::approx_equal(point, point * d360, 0.0001)); + assert!(Quaternion::approx_equal(point, point * d360 * d360, 0.0001)); + } } -- 2.43.4