## ~samhsmith/quatmaths

b1901e019abe52547190e20d8d57b7fceb8b590c — Sam H. Smith 2 years ago
```from access angle, multiply operator and test
```
```1 files changed, 49 insertions(+), 0 deletions(-)

M src/lib.rs
```
`M src/lib.rs => src/lib.rs +49 -0`
```@@ 38,6 38,17 @@ impl<T> Quaternion<T> 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<T>, b : Quaternion<T>, close_enough : T) -> bool
{
(a.w - b.w).abs() < close_enough &&

@@ 92,6 103,23 @@ impl<T> Quaternion<T> 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<T> std::ops::Mul for Quaternion<T> 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]
+    {
+        let q1 = Quaternion::<f32>::new(1.0, 2.0, 4.0, 8.0);
+        let q2 = Quaternion::<f32>::new(0.0, 1.0, 3.0, 9.0);
+        let q3 = Quaternion::<f32>::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::<f64>::new(0.0, 2.0, 8.0, 1.0);
+        let d360 = Quaternion::<f64>::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));
+    }
}

```