glissade 0.2.10

Rust library that provides various utilities for animations and transitions
Documentation
use crate::{Distance, Mix};
use cgmath::num_traits::Float;
use cgmath::{
    BaseFloat, Deg, Euler, Matrix2, Matrix3, Matrix4, Point1, Point2, Point3, Quaternion, Rad,
    Vector1, Vector2, Vector3, Vector4,
};

macro_rules! impl_stationary {
    ($($t:ident),*) => {
        $(impl<S: Mix + Clone> crate::Stationary for $t <S> {})*
    };
}

impl_stationary!(
    Deg, Euler, Matrix2, Matrix3, Matrix4, Point1, Point2, Point3, Quaternion, Rad, Vector1,
    Vector2, Vector3, Vector4
);

impl<S: Mix> Mix for Vector1<S> {
    fn mix(self, other: Self, t: f32) -> Self {
        Vector1 {
            x: self.x.mix(other.x, t),
        }
    }
}

impl<S: Mix> Mix for Vector2<S> {
    fn mix(self, other: Self, t: f32) -> Self {
        Vector2 {
            x: self.x.mix(other.x, t),
            y: self.y.mix(other.y, t),
        }
    }
}

impl<S: Mix> Mix for Vector3<S> {
    fn mix(self, other: Self, t: f32) -> Self {
        Vector3 {
            x: self.x.mix(other.x, t),
            y: self.y.mix(other.y, t),
            z: self.z.mix(other.z, t),
        }
    }
}

impl<S: Mix> Mix for Vector4<S> {
    fn mix(self, other: Self, t: f32) -> Self {
        Vector4 {
            x: self.x.mix(other.x, t),
            y: self.y.mix(other.y, t),
            z: self.z.mix(other.z, t),
            w: self.w.mix(other.w, t),
        }
    }
}

impl<S: Float> Distance for Vector1<S> {
    fn distance(self, other: Self) -> f32 {
        (self.x - other.x).abs().to_f32().unwrap()
    }
}

impl<S: Float> Distance for Vector2<S> {
    fn distance(self, other: Self) -> f32 {
        let dx = self.x - other.x;
        let dy = self.y - other.y;
        (dx * dx + dy * dy).sqrt().to_f32().unwrap()
    }
}

impl<S: Float> Distance for Vector3<S> {
    fn distance(self, other: Self) -> f32 {
        let dx = self.x - other.x;
        let dy = self.y - other.y;
        let dz = self.z - other.z;
        (dx * dx + dy * dy + dz * dz).sqrt().to_f32().unwrap()
    }
}

impl<S: From<f32> + BaseFloat> Mix for Quaternion<S> {
    fn mix(self, other: Self, t: f32) -> Self {
        self.slerp(other, t.into())
    }
}

impl<S: Mix> Mix for Deg<S> {
    fn mix(self, other: Self, t: f32) -> Self {
        Deg(self.0.mix(other.0, t))
    }
}

impl<S: Mix> Mix for Rad<S> {
    fn mix(self, other: Self, t: f32) -> Self {
        Rad(self.0.mix(other.0, t))
    }
}

impl<S: Mix> Mix for Euler<S> {
    fn mix(self, other: Self, t: f32) -> Self {
        Euler {
            x: self.x.mix(other.x, t),
            y: self.y.mix(other.y, t),
            z: self.z.mix(other.z, t),
        }
    }
}

impl<S: Mix> Mix for Point1<S> {
    fn mix(self, other: Self, t: f32) -> Self {
        Point1 {
            x: self.x.mix(other.x, t),
        }
    }
}

impl<S: Mix> Mix for Point2<S> {
    fn mix(self, other: Self, t: f32) -> Self {
        Point2 {
            x: self.x.mix(other.x, t),
            y: self.y.mix(other.y, t),
        }
    }
}

impl<S: Mix> Mix for Point3<S> {
    fn mix(self, other: Self, t: f32) -> Self {
        Point3 {
            x: self.x.mix(other.x, t),
            y: self.y.mix(other.y, t),
            z: self.z.mix(other.z, t),
        }
    }
}

impl<S: Float> Distance for Point1<S> {
    fn distance(self, other: Self) -> f32 {
        (self.x - other.x).abs().to_f32().unwrap()
    }
}

impl<S: Float> Distance for Point2<S> {
    fn distance(self, other: Self) -> f32 {
        let dx = self.x - other.x;
        let dy = self.y - other.y;
        (dx * dx + dy * dy).sqrt().to_f32().unwrap()
    }
}

impl<S: Float> Distance for Point3<S> {
    fn distance(self, other: Self) -> f32 {
        let dx = self.x - other.x;
        let dy = self.y - other.y;
        let dz = self.z - other.z;
        (dx * dx + dy * dy + dz * dz).sqrt().to_f32().unwrap()
    }
}

impl<S: Mix> Mix for Matrix2<S> {
    fn mix(self, other: Self, t: f32) -> Self {
        Matrix2 {
            x: self.x.mix(other.x, t),
            y: self.y.mix(other.y, t),
        }
    }
}

impl<S: Mix> Mix for Matrix3<S> {
    fn mix(self, other: Self, t: f32) -> Self {
        Matrix3 {
            x: self.x.mix(other.x, t),
            y: self.y.mix(other.y, t),
            z: self.z.mix(other.z, t),
        }
    }
}

impl<S: Mix> Mix for Matrix4<S> {
    fn mix(self, other: Self, t: f32) -> Self {
        Matrix4 {
            x: self.x.mix(other.x, t),
            y: self.y.mix(other.y, t),
            z: self.z.mix(other.z, t),
            w: self.w.mix(other.w, t),
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::Mix;
    use cgmath::{
        assert_relative_eq, Deg, Euler, Point1, Point2, Point3, Quaternion, Rad, Rotation3,
        Vector1, Vector2, Vector3, Vector4,
    };

    #[test]
    fn test_vector1() {
        let v1 = Vector1 { x: 0.0 };
        let v2 = Vector1 { x: 1.0 };
        let v3 = v1.mix(v2, 0.5);
        assert_eq!(v3, Vector1 { x: 0.5 });
    }

    #[test]
    fn test_vector2() {
        let v1 = Vector2 { x: 0.0, y: 0.0 };
        let v2 = Vector2 { x: 1.0, y: 1.0 };
        let v3 = v1.mix(v2, 0.5);
        assert_eq!(v3, Vector2 { x: 0.5, y: 0.5 });
    }

    #[test]
    fn test_vector3() {
        let v1 = Vector3 {
            x: 0.0,
            y: 0.0,
            z: 0.0,
        };
        let v2 = Vector3 {
            x: 1.0,
            y: 1.0,
            z: 1.0,
        };
        let v3 = v1.mix(v2, 0.5);
        assert_eq!(
            v3,
            Vector3 {
                x: 0.5,
                y: 0.5,
                z: 0.5,
            }
        );
    }

    #[test]
    fn test_vector4() {
        let v1 = Vector4 {
            x: 0.0,
            y: 0.0,
            z: 0.0,
            w: 0.0,
        };
        let v2 = Vector4 {
            x: 1.0,
            y: 1.0,
            z: 1.0,
            w: 1.0,
        };
        let v3 = v1.mix(v2, 0.5);
        assert_eq!(
            v3,
            Vector4 {
                x: 0.5,
                y: 0.5,
                z: 0.5,
                w: 0.5,
            }
        );
    }

    #[test]
    fn test_quaternion() {
        let q1 = Quaternion::from_angle_x(Deg(0.0));
        let q2 = Quaternion::from_angle_x(Deg(90.0));
        let q3 = q1.mix(q2, 0.5);
        assert_relative_eq!(q3, Quaternion::from_angle_x(Deg(45.0)));
    }

    #[test]
    fn test_deg() {
        let d1 = Deg(0.0);
        let d2 = Deg(90.0);
        let d3 = d1.mix(d2, 0.5);
        assert_eq!(d3, Deg(45.0));
    }

    #[test]
    fn test_rad() {
        let r1 = Rad(0.0);
        let r2 = Rad(2.0);
        let r3 = r1.mix(r2, 0.5);
        assert_eq!(r3, Rad(1.0));
    }

    #[test]
    fn test_euler() {
        let e1 = Euler::new(Deg(0.0), Deg(0.0), Deg(0.0));
        let e2 = Euler::new(Deg(90.0), Deg(90.0), Deg(90.0));
        let e3 = e1.mix(e2, 0.5);
        assert_eq!(e3, Euler::new(Deg(45.0), Deg(45.0), Deg(45.0)));
    }

    #[test]
    fn test_point1() {
        let p1 = Point1 { x: 0.0 };
        let p2 = Point1 { x: 1.0 };
        let p3 = p1.mix(p2, 0.5);
        assert_eq!(p3, Point1 { x: 0.5 });
    }

    #[test]
    fn test_point2() {
        let p1 = Point2 { x: 0.0, y: 0.0 };
        let p2 = Point2 { x: 1.0, y: 1.0 };
        let p3 = p1.mix(p2, 0.5);
        assert_eq!(p3, Point2 { x: 0.5, y: 0.5 });
    }

    #[test]
    fn test_point3() {
        let p1 = Point3 {
            x: 0.0,
            y: 0.0,
            z: 0.0,
        };
        let p2 = Point3 {
            x: 1.0,
            y: 1.0,
            z: 1.0,
        };
        let p3 = p1.mix(p2, 0.5);
        assert_eq!(
            p3,
            Point3 {
                x: 0.5,
                y: 0.5,
                z: 0.5,
            }
        );
    }
}