use num::Float;
use std::num::{Zero, One};
use std::ops::*;
use cplx::{Complex, from_rect};
pub trait Lerp<A> {
fn lerp(a: A, x: Self, y: Self) -> Self;
}
impl<A: Copy> Lerp<A> for Complex<Complex<A>>
where A: PartialEq + Zero + Add<Output = A> + AddAssign + Neg<Output = A> +
Mul<Output = A> + One + Float {
fn lerp(a: A, x: Self, y: Self) -> Self {
let s = ::quaternion::to_component_matrix(x);
let t = ::quaternion::to_component_matrix(y);
let ω = (|x|x+x)(::linea::dot(s, t).acos());
let r = if <A as Zero>::zero() == ω {
s.scale(<A as One>::one() - a) + t.scale(a)
} else {
(s.scale(((<A as One>::one()-a)*ω).sin()) + t.scale((a*ω).sin()))
.unscale(ω.sin())
};
from_rect(from_rect(r[0], r[1]), from_rect(r[2], r[3]))
}
}
impl<A: Copy + PartialEq + Zero + One, B: Lerp<A>> Lerp<A> for Option<B> {
fn lerp(a: A, x: Self, y: Self) -> Self {
match (x, y, A::zero() == a, <A as One>::one() == a) {
(Some(x), Some(y), _, _) => Some(B::lerp(a, x, y)),
(Some(x), None, true, _) => Some(x),
(None, Some(y), _, true) => Some(y),
_ => None,
}
}
}
impl<A: Copy, B: Lerp<A>> Lerp<A> for Vec<B> {
fn lerp(a: A, x: Self, y: Self) -> Self {
Iterator::zip(x.into_iter(), y.into_iter()).map(|(x, y)| B::lerp(a, x, y)).collect()
}
}