use interpolation::Spatial;
use num::{Float, NumCast};
use std::fmt::Debug;
use point::Point;
#[derive(Debug, Clone, Copy, RustcEncodable, RustcDecodable)]
pub struct BezierPoint<X, Y>
where
X: NumCast + Clone + Copy + Debug,
Y: Float + Debug,
{
pub x: X,
pub y: Y,
pub curve: Y,
}
impl<X, Y> BezierPoint<X, Y>
where
X: NumCast + Clone + Copy + Debug,
Y: Float + Debug,
{
#[inline]
pub fn new(x: X, y: Y, curve: Y) -> BezierPoint<X, Y> {
BezierPoint {
x: x,
y: y,
curve: curve,
}
}
}
impl<X, Y> Point<X, Y> for BezierPoint<X, Y>
where
X: NumCast + Clone + Copy + Debug,
Y: Spatial + Float + Debug,
Y::Scalar: Float,
{
#[inline(always)]
fn x_to_scalar(x: X) -> Y::Scalar {
NumCast::from(x).unwrap()
}
#[inline(always)]
fn x(&self) -> X { self.x }
#[inline(always)]
fn y(&self) -> Y { self.y }
#[inline(always)]
fn interpolate(x: X, start: &BezierPoint<X, Y>, end: &BezierPoint<X, Y>) -> Y {
if start.y == end.y { return start.y }
let x: Y = NumCast::from(x).unwrap();
let start_x: Y = NumCast::from(start.x()).unwrap();
let end_x: Y = NumCast::from(end.x()).unwrap();
let x_pos = x - start_x;
let duration = end_x - start_x;
let gradient_y = end.y - start.y;
let half_gradient_y: Y = gradient_y / two();
let y2 = half_gradient_y + start.curve * half_gradient_y;
let perc_x = x_pos / duration;
let ya = bezier_pt(Y::zero(), y2, perc_x);
let yb = bezier_pt(y2, gradient_y, perc_x);
bezier_pt(ya, yb, perc_x) + start.y
}
}
#[inline]
fn bezier_pt<A>(n1: A, n2: A, perc: A) -> A
where
A: Float
{
(n2 - n1) * perc + n1
}
#[inline]
fn two<F>() -> F
where
F: Float
{
let one: F = F::one();
one + one
}