lerpify 1.0.0

Interpolation traits
Documentation
use std::ops::*;


mod bezier;


pub use bezier::curve::Curve1;
pub use bezier::curve::Curve2;
pub use bezier::curve::Curve3;
pub use bezier::curve::Curve4;
pub use bezier::surface::Surface2;
pub use bezier::surface::Surface3;


type Dif<T, U = T> = <T as Sub<U>>::Output;
type Quot<T, U = T> = <T as Div<U>>::Output;
type Prod<T, U = T> = <T as Mul<U>>::Output;
type Sum<T, U = T> = <T as Add<U>>::Output;




pub fn lerp<T: Copy+Sub+Mul<Dif<T>>>(t: T, a: T, b: T) -> Sum<Prod<T, Dif<T>>, T>
where
    Prod<T, Dif<T>>: Add<T>
{
    t * (b-a) + a
}

pub fn unlerp<T: Copy+Sub>(t: T, a: T, b: T) -> Quot<Dif<T>>
where
    Dif<T>: Div,
{
    (t-a) / (b-a)
}


pub trait Unlerp: Copy {
    
    fn unlerp(self, a: Self, b: Self) -> Self;
}

impl Unlerp for f32 { 
                
    fn unlerp(self, a: Self, b: Self) -> Self { unlerp(self, a, b) } 
}

impl Unlerp for f64 { 
                
    fn unlerp(self, a: Self, b: Self) -> Self { unlerp(self, a, b) } 
}

pub trait BezierT: Sized+Copy {
    fn pow(self, pow: i32) -> Self;
    fn comp(self) -> Self;
    fn prod(self, coeff: i32) -> Self;
    fn mul(self, other: Self) -> Self;
    fn coeff(self, comp: i32, pow: i32, coeff: i32) -> Self {
        self.comp().pow(comp).mul(self.pow(pow)).prod(coeff)
    }
}

impl BezierT for f32 {
    fn pow(self, pow: i32) -> Self { self.powi(pow) }
    fn comp(self) -> Self { 1. - self }
    fn prod(self, coeff: i32) -> Self { self * coeff as Self }
    fn mul(self, other: Self) -> Self { self * other }
}

impl BezierT for f64 {
    fn pow(self, pow: i32) -> Self { self.powi(pow) }
    fn comp(self) -> Self { 1. - self }
    fn prod(self, coeff: i32) -> Self { self * coeff as Self }
    fn mul(self, other: Self) -> Self { self * other }
}

pub trait LinearCombination<S>: Sized {
    fn linear_combination<const N: usize>(terms: [(Self, S); N]) -> Self;
}

impl LinearCombination<Self> for f32 {
    fn linear_combination<const N: usize>(terms: [(Self, Self); N]) -> Self {
        terms.into_iter().fold(0., |c, n| c + n.1 * n.0)
    }
}

impl LinearCombination<Self> for f64 {
    fn linear_combination<const N: usize>(terms: [(Self, Self); N]) -> Self {
        terms.into_iter().fold(0., |c, n| c + n.1 * n.0)
    }
}

pub trait Bezier<V>: Copy+Sized {
    fn lerp(self, a: V, b: V) -> V;
    fn bezier2(self, a: V, h: V, b: V) -> V;
    fn bezier3(self, a: V, h0: V, h1: V, b: V) -> V;
    fn bezier4(self, a: V, h0: V, h1: V, h2: V, b: V) -> V;
}

impl<T: Copy+BezierT, V: LinearCombination<T>> Bezier<V> for T {
    fn lerp(self, a: V, b: V) -> V {
        V::linear_combination([(a, self.comp()), (b, self)])
    }

    fn bezier2(self, a: V, h: V, b: V) -> V {
        V::linear_combination([(a, self.comp().pow(2)), (h, self.coeff(1, 1, 2)), (b, self.pow(2))])
    }

    fn bezier3(self, a: V, h0: V, h1: V, b: V) -> V {
        V::linear_combination([(a, self.comp().pow(3)), (h0, self.coeff(2, 1, 3)), (h1, self.coeff(1, 2, 3)), (b, self.pow(3))])
    }

    fn bezier4(self, a: V, h0: V, h1: V, h2: V, b: V) -> V {
        V::linear_combination([(a, self.comp().pow(4)), (h0, self.coeff(3, 1, 4)), (h1, self.coeff(2, 2, 6)), (h2, self.coeff(1, 3, 4)), (b, self.pow(4))])
    }
}