use num_traits::Float;
use crate::woltring::search::find_knot_interval;
pub(crate) fn evaluate_spline<T: Float>(derivative_order: usize, half_order: usize, point: T, knots: &Vec<T>,
coefficients: &Vec<T>, knot_guess: usize) -> T {
let num_knots = knots.len();
let order = half_order as i32 * 2 - derivative_order as i32;
if order < 1 {
return T::from(0.).expect("Cannot convert to type from f64");
}
let knot_interval = find_knot_interval(&knots, point, knot_guess);
let mut tableau = vec![T::from(0.).expect("Cannot convert to type from f64"); 2 * half_order];
let mut lower_index = knot_interval as i32 + 1;
let upper_index = knot_interval as i32 + half_order as i32 * 2;
let mut inner_index = num_knots - 2 * half_order;
for index in lower_index ..= upper_index {
if index >= half_order as i32 + 1 && index <= num_knots as i32 + half_order as i32 {
tableau[(index - knot_interval as i32 - 1) as usize] =
coefficients[(index - half_order as i32 - 1) as usize];
} else {
tableau[(index - knot_interval as i32 - 1) as usize] =
T::from(0.).expect("Cannot convert to type from f64");
}
}
if derivative_order > 0 {
lower_index -= half_order as i32 * 2;
let index_bound = half_order as i32 * 2 - knot_interval as i32;
for der_index in 1 ..= derivative_order {
lower_index += 1;
inner_index += 1;
let idx_1 = 1.max(lower_index) as usize;
let idx_2 = knot_interval.min(inner_index);
let mut idx = idx_2 + 1;
if idx_1 <= idx_2 {
for _ in idx_1 ..= idx_2 {
idx -= 1;
let work_idx = (index_bound + idx as i32) as usize;
tableau[work_idx - 1] = (tableau[work_idx - 1] - tableau[work_idx - 2])
/ (knots[idx + half_order * 2 - der_index - 1] - knots[idx - 1]);
}
}
if lower_index < 1 {
idx = (index_bound + 1) as usize;
if der_index as i32 + 1 <= index_bound {
for _ in der_index as i32 + 1 ..= index_bound {
idx -= 1;
tableau[idx - 1] = -T::from(1.).expect("Cannot convert to type from f64")
* tableau[idx - 2];
}
}
}
}
for idx in 1 ..= order {
tableau[idx as usize - 1] = tableau[idx as usize + derivative_order - 1];
}
}
let mut solution;
if order - 1 >= 1 { for idx in 1 ..= order as usize - 1 {
let order_idx = (num_knots as i32 - order) as usize + idx;
let mut working_idx = order as usize;
let mut knot_idx = knot_interval;
if knot_interval >= order_idx + 1 {
for _ in order_idx + 1 ..= knot_interval {
tableau[working_idx - 1] = tableau[working_idx - 2] + (point - knots[knot_idx - 1])
* tableau[working_idx - 1];
knot_idx -= 1;
working_idx -= 1;
}
}
let idx_1 = 1.max(knot_interval as i32 - order + 1 + idx as i32);
let idx_2 = knot_interval.min(order_idx) as i32;
if idx_1 <= idx_2 {
for _ in idx_1 ..= idx_2 {
let working_knot = knots[(knot_idx as i32 + order - idx as i32 - 1) as usize];
solution = tableau[working_idx - 1];
tableau[working_idx - 1] = solution + (working_knot - point)
* (tableau[working_idx - 2] - solution) / (working_knot - knots[knot_idx - 1]);
working_idx -= 1;
knot_idx -= 1;
}
}
if knot_interval as i32 - order + 1 + idx as i32 <= 0 {
knot_idx = (order - idx as i32) as usize;
for _ in 1 ..= 1 - (knot_interval as i32 - order + 1 + idx as i32) {
tableau[working_idx - 1] = tableau[working_idx - 1]
+ (knots[knot_idx - 1] - point) * tableau[working_idx - 2];
knot_idx -= 1;
working_idx -= 1;
}
}
}
}
solution = tableau[order as usize - 1];
if derivative_order > 0 {
for idx in order ..= 2 * half_order as i32 - 1 {
let index = idx as usize;
solution = solution * T::from(index).expect("Cannot convert to type from usize");
}
}
solution
}