68 lines
1.9 KiB
Rust
68 lines
1.9 KiB
Rust
#![allow(clippy::missing_errors_doc)]
|
|
|
|
use std::fmt::Debug;
|
|
|
|
#[derive(Clone, Default)]
|
|
pub struct InterpLut {
|
|
inner: Vec<(f64, f64)>,
|
|
}
|
|
|
|
impl InterpLut {
|
|
/// Creates a new, empty table.
|
|
#[must_use]
|
|
pub fn new() -> InterpLut {
|
|
Self::default()
|
|
}
|
|
|
|
/// Inserts a new point into the table.
|
|
pub fn insert(&mut self, m: f64, n: f64) {
|
|
match self.binary_search(m) {
|
|
Ok(i) => {
|
|
self.inner[i] = (m, n);
|
|
}
|
|
Err(i) => {
|
|
self.inner.insert(i, (m, n));
|
|
}
|
|
}
|
|
}
|
|
|
|
fn binary_search(&self, n: f64) -> Result<usize, usize> {
|
|
self.inner.binary_search_by(|&(x, _)| x.total_cmp(&n))
|
|
}
|
|
|
|
/// Gets an interpolated value from the table. If n is out of bounds, returns an Err containing
|
|
/// the value at that boundary.
|
|
pub fn get(&self, n: f64) -> Result<f64, f64> {
|
|
match self.binary_search(n) {
|
|
Ok(i) => Ok(self.inner[i].1),
|
|
Err(i) => {
|
|
// value was not found
|
|
if i == 0 || i == self.inner.len() {
|
|
return Err(self.inner[i].1);
|
|
}
|
|
let t = Self::inverse_lerp(self.inner[i - 1].0, self.inner[i].0, n);
|
|
let res = Self::lerp(self.inner[i - 1].1, self.inner[i].1, t);
|
|
Ok(res)
|
|
}
|
|
}
|
|
}
|
|
|
|
fn inverse_lerp(low: f64, high: f64, n: f64) -> f64 {
|
|
let total_distance = high - low;
|
|
let partial_distance = n - low;
|
|
partial_distance / total_distance
|
|
}
|
|
|
|
fn lerp(low: f64, high: f64, t: f64) -> f64 {
|
|
let total_distance = high - low;
|
|
let partial_distance = total_distance * t;
|
|
low + partial_distance
|
|
}
|
|
}
|
|
|
|
impl Debug for InterpLut {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
f.debug_map().entries(self.inner.iter().copied()).finish()
|
|
}
|
|
}
|