use super::*;
#[derive(Debug)]
pub struct CardinalSpline<T> {
pub points: Vec<vec2<T>>,
pub tension: T,
}
impl<T> CardinalSpline<T> {
pub fn new(points: Vec<vec2<T>>, tension: T) -> Self {
Self { points, tension }
}
}
impl<F: Float> CubicHermiteCurve<F> for CardinalSpline<F> {
fn intervals(&self) -> Vec<CurveInterval<F>> {
let len = self.points.len();
let mut m = Vec::with_capacity(len);
if len > 1 {
m.push((
0,
(self.points[1] - self.points[0]) / (F::ONE - F::ZERO) * (F::ONE - self.tension),
));
}
m.extend(
self.points
.iter()
.zip(self.points.iter().skip(2))
.map(|(&p0, &p2)| (p2 - p0) / (F::ONE - F::ZERO) * (F::ONE - self.tension))
.enumerate()
.map(|(i, m)| (i + 1, m)),
);
if len > 2 {
m.push((
len - 1,
(self.points[len - 1] - self.points[len - 2]) / (F::ONE - F::ZERO)
* (F::ONE - self.tension),
));
}
let mut m = m.into_iter();
let (_, mut prev) = match m.next() {
Some(first) => first,
None => return Vec::new(),
};
let mut intervals = Vec::with_capacity(len - 1);
for (index, next) in m {
intervals.push(CurveInterval {
point_start: self.points[index - 1],
point_end: self.points[index],
tangent_start: prev,
tangent_end: next,
});
prev = next;
}
intervals
}
}