use std::ops::{Add, Mul};
use std::slice::Iter;
extern crate trait_set;
use trait_set::trait_set;
extern crate num_traits;
#[cfg(not(feature = "nalgebra-support"))]
trait_set! {
pub trait Float = num_traits::Float;
}
#[cfg(feature = "nalgebra-support")]
extern crate nalgebra;
#[cfg(feature = "nalgebra-support")]
trait_set! {
pub trait Float = nalgebra::RealField + Copy;
}
pub trait Interpolate<F> {
fn interpolate(&self, other: &Self, t: F) -> Self;
}
impl<T: Mul<F, Output = T> + Add<Output = T> + Copy, F: Float> Interpolate<F> for T {
fn interpolate(&self, other: &Self, t: F) -> Self {
*self * (F::one() - t) + *other * t
}
}
#[derive(Clone, Debug)]
pub struct BSpline<T: Interpolate<F> + Copy, F: Float> {
degree: usize,
control_points: Vec<T>,
knots: Vec<F>,
}
impl<T: Interpolate<F> + Copy, F: Float> BSpline<T, F> {
pub fn new(degree: usize, control_points: Vec<T>, mut knots: Vec<F>) -> BSpline<T, F> {
if control_points.len() <= degree {
panic!("Too few control points for curve");
}
if knots.len() != control_points.len() + degree + 1 {
panic!(
"Invalid number of knots, got {}, expected {}",
knots.len(),
control_points.len() + degree + 1
);
}
knots.sort_by(|a, b| a.partial_cmp(b).unwrap());
BSpline {
degree,
control_points,
knots,
}
}
pub fn point(&self, t: F) -> T {
debug_assert!(t >= self.knot_domain().0 && t <= self.knot_domain().1);
let i = match upper_bounds(&self.knots[..], t) {
Some(x) if x == 0 => self.degree,
Some(x) if x >= self.knots.len() - self.degree - 1 => {
self.knots.len() - self.degree - 1
}
Some(x) => x,
None => self.knots.len() - self.degree - 1,
};
self.de_boor_iterative(t, i)
}
pub fn control_points(&self) -> Iter<T> {
self.control_points.iter()
}
pub fn knots(&self) -> Iter<F> {
self.knots.iter()
}
pub fn knot_domain(&self) -> (F, F) {
(
self.knots[self.degree],
self.knots[self.knots.len() - 1 - self.degree],
)
}
fn de_boor_iterative(&self, t: F, i_start: usize) -> T {
let mut tmp = Vec::with_capacity(self.degree + 1);
for j in 0..=self.degree {
let p = j + i_start - self.degree - 1;
tmp.push(self.control_points[p]);
}
for lvl in 0..self.degree {
let k = lvl + 1;
for j in 0..self.degree - lvl {
let i = j + k + i_start - self.degree;
let alpha =
(t - self.knots[i - 1]) / (self.knots[i + self.degree - k] - self.knots[i - 1]);
debug_assert!(alpha.is_finite());
tmp[j] = tmp[j].interpolate(&tmp[j + 1], alpha);
}
}
tmp[0]
}
}
fn upper_bounds<F: Float>(data: &[F], value: F) -> Option<usize> {
let mut first = 0usize;
let mut step;
let mut count = data.len() as isize;
while count > 0 {
step = count / 2;
let it = first + step as usize;
if !value.lt(&data[it]) {
first = it + 1;
count -= step + 1;
} else {
count = step;
}
}
if first == data.len() {
None
} else {
Some(first)
}
}