glissade 0.2.10

Rust library that provides various utilities for animations and transitions
Documentation
use nalgebra::{
    ClosedAddAssign, ClosedMulAssign, ClosedSubAssign, Isometry, Matrix1x2, Matrix1x3, Matrix1x4,
    Matrix1x5, Matrix1x6, Matrix2, Matrix2x3, Matrix2x4, Matrix2x5, Matrix2x6, Matrix3, Matrix3x2,
    Matrix3x4, Matrix3x5, Matrix3x6, Matrix4, Matrix4x2, Matrix4x3, Matrix4x5, Matrix4x6, Matrix5,
    Matrix5x2, Matrix5x3, Matrix5x4, Matrix5x6, Matrix6, Matrix6x2, Matrix6x3, Matrix6x4,
    Matrix6x5, Point, Quaternion, RealField, Rotation, Scalar, Scale, Translation, Vector1,
    Vector2, Vector3, Vector4, Vector5, Vector6,
};
use num_traits::{One, Zero};

use crate::mix::Mix;
use crate::{Distance, Stationary};

macro_rules! impl_traits_for_vector {
    ($vector:ident) => {
        impl<T> Mix for $vector<T>
        where
            T: Scalar
                + Zero
                + One
                + ClosedAddAssign
                + ClosedSubAssign
                + ClosedMulAssign
                + From<f32>,
        {
            fn mix(self, other: Self, t: f32) -> Self {
                self.lerp(&other, T::from(t))
            }
        }

        impl<T: Clone> Stationary for $vector<T> {}

        impl<T> Distance for $vector<T>
        where
            T: Scalar
                + Zero
                + One
                + ClosedAddAssign
                + ClosedSubAssign
                + ClosedMulAssign
                + From<f32>,
        {
            fn distance(self, other: Self) -> f32 {
                (self - other).len() as f32
            }
        }
    };
}

impl_traits_for_vector!(Vector1);
impl_traits_for_vector!(Vector2);
impl_traits_for_vector!(Vector3);
impl_traits_for_vector!(Vector4);
impl_traits_for_vector!(Vector5);
impl_traits_for_vector!(Vector6);

macro_rules! impl_mix_for_matrix {
    ($matrix:ident) => {
        impl<T> Mix for $matrix<T>
        where
            T: Scalar + Mix,
        {
            fn mix(self, other: Self, t: f32) -> Self {
                self.zip_map(&other, |a, b| a.mix(b, t))
            }
        }

        impl<T: Clone> Stationary for $matrix<T> {}
    };
}

impl_mix_for_matrix!(Matrix1x2);
impl_mix_for_matrix!(Matrix2);
impl_mix_for_matrix!(Matrix3x2);
impl_mix_for_matrix!(Matrix4x2);
impl_mix_for_matrix!(Matrix5x2);
impl_mix_for_matrix!(Matrix6x2);

impl_mix_for_matrix!(Matrix1x3);
impl_mix_for_matrix!(Matrix2x3);
impl_mix_for_matrix!(Matrix3);
impl_mix_for_matrix!(Matrix4x3);
impl_mix_for_matrix!(Matrix5x3);
impl_mix_for_matrix!(Matrix6x3);

impl_mix_for_matrix!(Matrix1x4);
impl_mix_for_matrix!(Matrix2x4);
impl_mix_for_matrix!(Matrix3x4);
impl_mix_for_matrix!(Matrix4);
impl_mix_for_matrix!(Matrix5x4);
impl_mix_for_matrix!(Matrix6x4);

impl_mix_for_matrix!(Matrix1x5);
impl_mix_for_matrix!(Matrix2x5);
impl_mix_for_matrix!(Matrix3x5);
impl_mix_for_matrix!(Matrix4x5);
impl_mix_for_matrix!(Matrix5);
impl_mix_for_matrix!(Matrix6x5);

impl_mix_for_matrix!(Matrix1x6);
impl_mix_for_matrix!(Matrix2x6);
impl_mix_for_matrix!(Matrix3x6);
impl_mix_for_matrix!(Matrix4x6);
impl_mix_for_matrix!(Matrix5x6);
impl_mix_for_matrix!(Matrix6);

impl<T, const D: usize> Mix for Point<T, D>
where
    T: Scalar + From<f32> + Zero + One + ClosedAddAssign + ClosedSubAssign + ClosedMulAssign,
{
    fn mix(self, other: Self, t: f32) -> Self {
        self.lerp(&other, T::from(t))
    }
}

impl<T, const D: usize> Stationary for Point<T, D> where
    T: Scalar + Zero + One + ClosedAddAssign + ClosedSubAssign + ClosedMulAssign + From<f32>
{
}

impl<T, const D: usize> Mix for Scale<T, D>
where
    T: Scalar + Zero + One + ClosedAddAssign + ClosedSubAssign + ClosedMulAssign + From<f32>,
{
    fn mix(self, other: Self, t: f32) -> Self {
        self.vector.lerp(&other.vector, T::from(t)).into()
    }
}

impl<T, const D: usize> Stationary for Scale<T, D> where T: Clone {}

impl<T> Mix for Rotation<T, 2>
where
    T: Scalar
        + Zero
        + One
        + ClosedAddAssign
        + ClosedSubAssign
        + ClosedMulAssign
        + From<f32>
        + RealField,
{
    fn mix(self, other: Self, t: f32) -> Self {
        self.slerp(&other, T::from(t))
    }
}

impl<T: Clone> Stationary for Rotation<T, 2> {}

impl<T> Mix for Rotation<T, 3>
where
    T: Scalar
        + Zero
        + One
        + ClosedAddAssign
        + ClosedSubAssign
        + ClosedMulAssign
        + From<f32>
        + RealField,
{
    fn mix(self, other: Self, t: f32) -> Self {
        self.slerp(&other, T::from(t))
    }
}

impl<T: Clone> Stationary for Rotation<T, 3> {}

impl<T, const D: usize> Mix for Translation<T, D>
where
    T: Scalar + Zero + One + ClosedAddAssign + ClosedSubAssign + ClosedMulAssign + From<f32>,
{
    fn mix(self, other: Self, t: f32) -> Self {
        self.vector.lerp(&other.vector, T::from(t)).into()
    }
}

impl<T: Clone, const D: usize> Stationary for Translation<T, D> {}

impl<T> Mix for Quaternion<T>
where
    T: Scalar
        + Zero
        + One
        + ClosedAddAssign
        + ClosedSubAssign
        + ClosedMulAssign
        + From<f32>
        + RealField,
{
    fn mix(self, other: Self, t: f32) -> Self {
        self.lerp(&other, T::from(t))
    }
}

impl<T> Stationary for Quaternion<T> where T: Clone {}

impl<T> Mix for Isometry<T, Rotation<T, 2>, 2>
where
    T: Scalar
        + Zero
        + One
        + ClosedAddAssign
        + ClosedSubAssign
        + ClosedMulAssign
        + From<f32>
        + RealField,
{
    fn mix(self, other: Self, t: f32) -> Self {
        self.lerp_slerp(&other, T::from(t))
    }
}

impl<T> Stationary for Isometry<T, Rotation<T, 2>, 2> where T: Clone {}

impl<T> Mix for Isometry<T, Rotation<T, 3>, 3>
where
    T: Scalar
        + Zero
        + One
        + ClosedAddAssign
        + ClosedSubAssign
        + ClosedMulAssign
        + From<f32>
        + RealField,
{
    fn mix(self, other: Self, t: f32) -> Self {
        self.lerp_slerp(&other, T::from(t))
    }
}

impl<T> Stationary for Isometry<T, Rotation<T, 3>, 3> where T: Clone {}

#[cfg(test)]
mod tests {
    use crate::Mix;
    use nalgebra::{
        Point2, Point3, Quaternion, Rotation2, Translation2, Translation3, Vector2, Vector3,
        Vector4,
    };

    #[test]
    fn test_point2_mix() {
        let p1 = Point2::new(1.0, 2.0);
        let p2 = Point2::new(3.0, 4.0);
        let p3 = p1.mix(p2, 0.5);
        assert_eq!(p3, Point2::new(2.0, 3.0));
    }

    #[test]
    fn test_point3_mix() {
        let p1 = Point3::new(1.0, 2.0, 3.0);
        let p2 = Point3::new(4.0, 5.0, 6.0);
        let p3 = p1.mix(p2, 0.5);
        assert_eq!(p3, Point3::new(2.5, 3.5, 4.5));
    }

    #[test]
    fn test_translation2_mix() {
        let t1 = Translation2::new(1.0, 2.0);
        let t2 = Translation2::new(3.0, 4.0);
        let t3 = t1.mix(t2, 0.5);
        assert_eq!(t3, Translation2::new(2.0, 3.0));
    }

    #[test]
    fn test_translation3_mix() {
        let t1 = Translation3::new(1.0, 2.0, 3.0);
        let t2 = Translation3::new(4.0, 5.0, 6.0);
        let t3 = t1.mix(t2, 0.5);
        assert_eq!(t3, Translation3::new(2.5, 3.5, 4.5));
    }

    #[test]
    fn test_rotation2_mix() {
        let r1 = Rotation2::new(0.5);
        let r2 = Rotation2::new(1.0);
        let r3 = r1.mix(r2, 0.5);
        assert_eq!(r3.angle(), 0.75);
    }

    #[test]
    fn test_quaternion_mix() {
        let q1 = Quaternion::new(1.0, 2.0, 3.0, 4.0);
        let q2 = Quaternion::new(5.0, 6.0, 7.0, 8.0);
        let q3 = q1.mix(q2, 0.5);
        assert_eq!(q3, Quaternion::new(3.0, 4.0, 5.0, 6.0));
    }

    #[test]
    fn test_point2_mix_f32() {
        let p1 = Point2::new(1.0f32, 2.0f32);
        let p2 = Point2::new(3.0f32, 4.0f32);
        let p3 = p1.mix(p2, 0.5);
        assert_eq!(p3, Point2::new(2.0, 3.0));
    }

    #[test]
    fn test_point3_mix_f32() {
        let p1 = Point3::new(1.0f32, 2.0f32, 3.0f32);
        let p2 = Point3::new(4.0f32, 5.0f32, 6.0f32);
        let p3 = p1.mix(p2, 0.5);
        assert_eq!(p3, Point3::new(2.5, 3.5, 4.5));
    }

    #[test]
    fn test_translation2_mix_f32() {
        let t1 = Translation2::new(1.0f32, 2.0f32);
        let t2 = Translation2::new(3.0f32, 4.0f32);
        let t3 = t1.mix(t2, 0.5);
        assert_eq!(t3, Translation2::new(2.0, 3.0));
    }

    #[test]
    fn test_translation3_mix_f32() {
        let t1 = Translation3::new(1.0f32, 2.0f32, 3.0f32);
        let t2 = Translation3::new(4.0f32, 5.0f32, 6.0f32);
        let t3 = t1.mix(t2, 0.5);
        assert_eq!(t3, Translation3::new(2.5, 3.5, 4.5));
    }

    #[test]
    fn test_vector2_mix() {
        let v1 = Vector2::new(1.0, 2.0);
        let v2 = Vector2::new(3.0, 4.0);
        let v3 = v1.mix(v2, 0.5);
        assert_eq!(v3, Vector2::new(2.0, 3.0));
    }

    #[test]
    fn test_vector3_mix() {
        let v1 = Vector3::new(1.0, 2.0, 3.0);
        let v2 = Vector3::new(4.0, 5.0, 6.0);
        let v3 = v1.mix(v2, 0.5);
        assert_eq!(v3, Vector3::new(2.5, 3.5, 4.5));
    }

    #[test]
    fn test_vector4_mix() {
        let v1 = Vector4::new(1.0, 2.0, 3.0, 4.0);
        let v2 = Vector4::new(5.0, 6.0, 7.0, 8.0);
        let v3 = v1.mix(v2, 0.5);
        assert_eq!(v3, Vector4::new(3.0, 4.0, 5.0, 6.0));
    }
}