#[inline]
pub(crate) fn lerp(a: f64, b: f64, t: f64) -> f64 {
a + t * (b - a)
}
pub(crate) fn linear_interpolator(stops: Vec<f64>) -> impl Fn(f64) -> f64 {
let classes = build_classes(&stops);
move |t: f64| {
let n = classes.len();
if n == 0 {
return f64::NAN;
}
let cls = t * n as f64;
let idx = if t >= 1.0 {
n - 1
} else {
(cls.floor() as isize).max(0) as usize
};
let local_t = cls - idx as f64;
match classes[idx] {
Some((a, b)) => lerp(a, b, local_t),
None => f64::NAN,
}
}
}
fn build_classes(arr: &[f64]) -> Vec<Option<(f64, f64)>> {
if arr.len() < 2 {
return Vec::new();
}
let mut out = Vec::with_capacity(arr.len() - 1);
for i in 0..arr.len() - 1 {
let a = arr[i];
let b = arr[i + 1];
let a_def = !a.is_nan();
let b_def = !b.is_nan();
let pair = match (a_def, b_def) {
(false, false) => None,
(true, true) => Some((a, b)),
(true, false) => Some((a, a)),
(false, true) => Some((b, b)),
};
out.push(pair);
}
out
}