use num_traits::Float;
use crate::trajectory::{PiecewisePolynomial, ReferenceTrajectory, Trajectory, TrajectoryProfile};
use crate::Polynomial;
pub mod piecewise_polynomial;
pub fn normalized_coefficients<T: Float>(k: usize) -> Vec<T> {
let mut coeffs = vec![T::zero(); 2 * k + 2];
let mut c_kj = T::one(); for j in 0..=k {
if j > 0 {
c_kj = c_kj * T::from(k + j).unwrap() / T::from(j).unwrap();
}
let mut c_ji = T::one(); for i in 0..=j {
if i > 0 {
c_ji = c_ji * T::from(j - i + 1).unwrap() / T::from(i).unwrap();
}
let sign = if i % 2 == 0 { T::one() } else { -T::one() };
coeffs[k + 1 + i] = coeffs[k + 1 + i] + sign * c_kj * c_ji;
}
}
coeffs
}
pub fn piecewise<T: Float>(distance: T, duration: T, start: T, smoothness: usize) -> PiecewisePolynomial<T> {
let mut scale = distance;
let descending: Vec<T> = normalized_coefficients::<T>(smoothness)
.into_iter()
.map(|c| {
let v = c * scale;
scale = scale / duration;
v
})
.collect::<Vec<T>>()
.into_iter()
.rev()
.collect();
PiecewisePolynomial::new(start, vec![(duration, Polynomial(descending))], Polynomial(vec![distance]))
}
#[derive(Clone, Copy, Debug)]
pub struct SmoothPolynomial {
pub smoothness: usize,
}
impl<T: Float> Trajectory<T> for SmoothPolynomial {
fn profile(&self, distance: T, x: T) -> TrajectoryProfile<T> {
if x < T::zero() {
return TrajectoryProfile::rest(T::zero());
}
if x > T::one() {
return TrajectoryProfile::rest(distance);
}
let coeffs = normalized_coefficients::<T>(self.smoothness);
let (mut p, mut dp, mut ddp) = (T::zero(), T::zero(), T::zero());
for &c in coeffs.iter().rev() {
ddp = ddp * x + dp + dp;
dp = dp * x + p;
p = p * x + c;
}
TrajectoryProfile { s: distance * p, v: distance * dp, a: distance * ddp }
}
}
impl<T: Float> ReferenceTrajectory<T> for SmoothPolynomial {
type Reference = PiecewisePolynomial<T>;
fn reference(&self, distance: T, duration: T, start: T) -> PiecewisePolynomial<T> {
piecewise(distance, duration, start, self.smoothness)
}
}