use std::iter::repeat;
use crate::dierckx::curfit_;
use spliny::SplineCurve;
use super::FitError;
use crate::Result;
pub struct SplineCurveFit<const K: usize> {
x: Vec<f64>,
y: Vec<f64>,
w: Vec<f64>,
t: Vec<f64>,
c: Vec<f64>,
n: i32,
e_rms: Option<f64>,
wrk: Vec<f64>,
iwrk: Vec<i32>,
}
impl<const K: usize> SplineCurveFit<K> {
pub fn new(x: Vec<f64>, y: Vec<f64>) -> Self {
let m = x.len();
let w_vec = vec![1.0; m];
assert!(y.len() == m);
let nest = m * K + 1;
let t_vec = vec![0.0; nest];
let c_vec = vec![0.0; nest];
let n = nest as i32;
let iwrk_vec = vec![0i32; nest];
let lwrk = m * (K + 1) + nest * (7 + 3 * K);
let wrk_vec = vec![0f64; lwrk];
Self { x, y, w: w_vec, t: t_vec, c: c_vec, n, wrk: wrk_vec, iwrk: iwrk_vec, e_rms: None }
}
pub fn set_weights(mut self, weights: Vec<f64>) -> Result<Self> {
if weights.len() == self.x.len() {
self.w = weights;
Ok(self)
} else {
Err(FitError::new(203).into())
}
}
fn curfit(&mut self, iopt: i32, e_rms: Option<f64>, knots: Option<Vec<f64>>) -> i32 {
let k = K as i32;
let m = self.x.len() as i32;
if let Some(knots) = knots {
self.n = knots.len() as i32;
self.t = knots;
}
let nest = self.t.len() as i32;
let lwrk = self.wrk.len() as i32;
let mut fp = 0.0;
let s = if let Some(e) = e_rms { m as f64 * e.powi(2) } else { 0.0 };
let mut ierr = 0;
unsafe {
curfit_(
&iopt, &m,
self.x.as_ptr(), self.y.as_ptr(), self.w.as_ptr(),
&self.x[0], &self.x[m as usize - 1],
&k, &s, &nest, &mut self.n,
self.t.as_mut_ptr(), self.c.as_mut_ptr(),
&mut fp,
self.wrk.as_mut_ptr(), &lwrk, self.iwrk.as_mut_ptr(),
&mut ierr,
);
}
self.e_rms = Some((fp / m as f64).sqrt());
ierr
}
pub fn cardinal_spline(mut self, dt: f64) -> Result<SplineCurve<K, 1>> {
let m = self.x.len();
let tb = (self.x[0] / dt).ceil() * dt;
let te = (self.x[m - 1] / dt).floor() * dt;
let n = ((te - tb) / dt).round() as usize;
if n == 0 { return Err(FitError::new(205).into()) }
let mut t: Vec<f64> = Vec::with_capacity(n + 2 * (K + 1) + 1);
t.extend(
repeat(tb).take(K + 1)
.chain(repeat(dt).scan(tb + dt, |s, dx| {
let t = *s;
*s += dx;
if t < te { Some(t) } else { None }
}))
.chain(repeat(te).take(K + 1)),
);
let ierr = self.curfit(-1, Some(0.0), Some(t));
if ierr <= 0 { Ok(self.into()) } else { Err(FitError::new(ierr).into()) }
}
pub fn interpolating_spline(mut self) -> Result<SplineCurve<K, 1>> {
let ierr = self.curfit(0, Some(0.0), None);
if ierr <= 0 { Ok(self.into()) } else { Err(FitError::new(ierr).into()) }
}
pub fn smoothing_spline(mut self, rms: f64) -> Result<SplineCurve<K, 1>> {
let ierr = self.curfit(0, Some(rms), None);
if ierr <= 0 { Ok(self.into()) } else { Err(FitError::new(ierr).into()) }
}
}
impl<const K: usize> From<SplineCurveFit<K>> for SplineCurve<K, 1> {
fn from(mut sp: SplineCurveFit<K>) -> Self {
sp.t.truncate(sp.n as usize);
sp.t.shrink_to_fit();
sp.c.truncate(sp.n as usize - (K + 1));
sp.c.shrink_to_fit();
Self::new(sp.t, sp.c)
}
}