1use crate::util::Interval;
2
3#[derive(Clone)]
6pub struct LookupTable<T> {
7 offset: f64,
8 step: f64,
9 values: Vec<T>,
10}
11
12impl<T> LookupTable<T> {
13 pub fn from_samples(range: Interval<f64>, step: f64, f: impl FnMut(f64) -> T) -> Self {
15 let offset = range.min;
16 let num_samples = (range.length() / step).ceil() as usize;
17 let xs = (0..num_samples).map(|i| offset + ((i as f64) + 0.5) * step);
18 let values = xs.map(f).collect();
19 Self {
20 offset,
21 step,
22 values,
23 }
24 }
25
26 pub fn sample(&self, x: f64) -> &T {
28 let idx = (x - self.offset) / self.step;
29 let idx = usize::min(idx as u32 as usize, self.values.len() - 1);
30 &self.values[idx]
31 }
32}
33
34#[cfg(test)]
35mod test {
36 use super::LookupTable;
37 use crate::util::Interval;
38
39 #[test]
40 fn basic_lut() {
41 let range = Interval::new(50.0, 200.0);
42 let lut = LookupTable::from_samples(range, 5.0, |x| 2.0 * x);
43
44 assert_eq!(*lut.sample(20.0), 105.0);
45
46 assert_eq!(*lut.sample(50.0), 105.0);
47 assert_eq!(*lut.sample(52.0), 105.0);
48 assert_eq!(*lut.sample(54.0), 105.0);
49
50 assert_eq!(*lut.sample(90.0), 185.0);
51 assert_eq!(*lut.sample(92.0), 185.0);
52 assert_eq!(*lut.sample(94.0), 185.0);
53
54 assert_eq!(*lut.sample(195.0), 395.0);
55 assert_eq!(*lut.sample(197.0), 395.0);
56 assert_eq!(*lut.sample(199.0), 395.0);
57
58 assert_eq!(*lut.sample(888.0), 395.0);
59 }
60}