traffic_sim/math/
lut.rs

1use crate::util::Interval;
2
3/// A lookup table
4
5#[derive(Clone)]
6pub struct LookupTable<T> {
7    offset: f64,
8    step: f64,
9    values: Vec<T>,
10}
11
12impl<T> LookupTable<T> {
13    /// Creates a lookup table from a sample function.
14    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    /// Samples the lookup table.
27    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}