~samhsmith/quatmaths

b1901e019abe52547190e20d8d57b7fceb8b590c — Sam H. Smith 2 years ago 34ba538 master
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]
    fn test_operator_overloading()
    {
        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));
    }
}