#![feature(std_misc)]
extern crate "rustc-serialize" as rustc_serialize;
use std::cmp::Ordering;
use std::fmt::Debug;
use std::num::Float;
pub trait Point: Copy + Clone + Debug {
type F: Float;
fn x(&self) -> <Self as Point>::F;
fn y(&self) -> <Self as Point>::F;
fn curve(&self) -> <Self as Point>::F { Float::zero() }
fn new(x: <Self as Point>::F, y: <Self as Point>::F, curve: <Self as Point>::F) -> Self;
}
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct Envelope<P> {
pub points: Vec<P>
}
impl<P> Envelope<P> where P: Point, <P as Point>::F: Float {
#[inline]
pub fn new() -> Envelope<P> {
Envelope { points: Vec::new() }
}
#[inline]
pub fn from_points(mut points: Vec<P>) -> Envelope<P> {
points.sort_by(|a, b| if a.x() < b.x() { Ordering::Less }
else if a.x() > b.x() { Ordering::Greater }
else { Ordering::Equal });
Envelope { points: points }
}
#[inline]
pub fn zeroed() -> Envelope<P> {
Envelope {
points: vec![Point::new(Float::zero(), Float::zero(), Float::zero()),
Point::new(Float::one(), Float::zero(), Float::zero())]
}
}
pub fn add_point(&mut self, point: P) {
self.points.push(point);
self.points.sort_by(|a, b| if a.x() < b.x() { Ordering::Less }
else if a.x() > b.x() { Ordering::Greater }
else { Ordering::Equal });
}
#[inline]
pub fn y(&self, x: <P as Point>::F) -> <P as Point>::F {
if self.points.len() <= 1 { return Float::zero() }
let mut i = 1;
while i < self.points.len() - 1 && x >= self.points[i].x() {
i += 1;
}
interpolate(x, self.points[i-1], self.points[i])
}
}
#[inline]
fn interpolate<P>(x: <P as Point>::F, start: P, end: P) -> <P as Point>::F
where
P: Point,
<P as Point>::F: Float,
{
let x_pos = x - start.x();
let duration = end.x() - start.x();
let gradient_y = end.y() - start.y();
if gradient_y == Float::zero() { return start.y() }
let half_gradient_y: <P as Point>::F = gradient_y / two();
let y2 = half_gradient_y + start.curve() * half_gradient_y;
let perc_x = x_pos / duration;
let ya = bezier_pt(Float::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<F>(n1: F, n2: F, perc: F) -> F where F: Float {
(n2 - n1) * perc + n1
}
#[inline]
fn two<F>() -> F where F: Float {
let one: F = Float::one();
one + one
}