traffic_sim/
util.rs

1//! Miscellaneous utility structs and functions.
2
3use std::fmt::Debug;
4
5use cgmath::num_traits::Float;
6use serde::{Deserialize, Serialize};
7
8/// An interval on the real number line.
9#[derive(Copy, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
10pub struct Interval<T> {
11    /// The smallest value in the interval.
12    pub min: T,
13    /// The largest value in the interval.
14    pub max: T,
15}
16
17impl<T> Interval<T> {
18    /// Creates a new interval.
19    pub const fn new(min: T, max: T) -> Self {
20        Self { min, max }
21    }
22}
23
24impl<T: std::cmp::PartialOrd> Interval<T> {
25    /// Returns true if this interval overlaps with the other.
26    pub fn overlaps(&self, other: &Self) -> bool {
27        self.max > other.min && other.max > self.min
28    }
29
30    /// Returns true if this interval contains the value.
31    pub fn contains(&self, value: T) -> bool {
32        value >= self.min && value <= self.max
33    }
34}
35
36impl<T: std::ops::Sub<T, Output = T> + Copy> Interval<T> {
37    /// Gets the magnitude of the interval.
38    pub fn length(&self) -> T {
39        self.max - self.min
40    }
41}
42
43impl<T: Copy> Interval<T> {
44    /// Gets the interval as an array.
45    pub fn as_array(&self) -> [T; 2] {
46        [self.min, self.max]
47    }
48}
49
50impl<T: Float> Interval<T> {
51    /// Creates an interval with the given centre and radius.
52    pub fn disc(centre: T, radius: T) -> Self {
53        Self {
54            min: centre - radius,
55            max: centre + radius,
56        }
57    }
58
59    /// Returns the centre/mid-point of the interval.
60    pub fn midpoint(&self) -> T {
61        T::from(0.5).unwrap() * (self.min + self.max)
62    }
63
64    /// Computes the gap between two intervals.
65    /// Will be negative if the intervals overlap.
66    pub fn clearance_with(&self, other: &Self) -> T {
67        T::max(other.min - self.max, self.min - other.max)
68    }
69
70    /// Computes the distance between a point and the interval.
71    /// Will be negative if the point is within the interval.
72    pub fn distance(&self, other: T) -> T {
73        T::max(other - self.max, self.min - other)
74    }
75
76    /// Interpolates between the two endpoints of the interval,
77    /// where `t=0` will yield `self.min` and `t=1` will yield `self.max`.
78    pub fn lerp(&self, t: T) -> T {
79        self.min + t * (self.max - self.min)
80    }
81
82    /// Performs the inverse operation of [`Self::lerp`], such that providing
83    /// an input of `self.min` will yield `0` and an input of `self.max` will yield `1`.
84    pub fn inv_lerp(&self, value: T) -> T {
85        (value - self.min) / (self.max - self.min)
86    }
87}
88
89impl<T: Float> std::ops::Add<T> for Interval<T> {
90    type Output = Interval<T>;
91
92    fn add(self, rhs: T) -> Self::Output {
93        Self {
94            min: self.min + rhs,
95            max: self.max + rhs,
96        }
97    }
98}
99
100impl<T: Float> std::ops::Sub<T> for Interval<T> {
101    type Output = Interval<T>;
102
103    fn sub(self, rhs: T) -> Self::Output {
104        Self {
105            min: self.min - rhs,
106            max: self.max - rhs,
107        }
108    }
109}
110
111impl<T: Debug> Debug for Interval<T> {
112    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
113        write!(f, "Interval({:?}, {:?})", &self.min, &self.max)
114    }
115}
116
117pub fn rotated_range(count: usize, start: usize) -> impl Iterator<Item = usize> {
118    (0..count)
119        .map(move |i| i + start)
120        .map(move |i| if i >= count { i - count } else { i })
121}