Skip to main content

emath/
range.rs

1use core::ops::{RangeFrom, RangeFull, RangeInclusive, RangeToInclusive};
2
3use crate::fast_midpoint;
4
5/// Inclusive range of floats, i.e. `min..=max`, but more ergonomic than [`RangeInclusive`].
6#[repr(C)]
7#[derive(Clone, Copy, Debug, PartialEq)]
8#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
9#[cfg_attr(feature = "bytemuck", derive(bytemuck::Pod, bytemuck::Zeroable))]
10pub struct Rangef {
11    pub min: f32,
12    pub max: f32,
13}
14
15impl Rangef {
16    /// Infinite range that contains everything, from -∞ to +∞, inclusive.
17    pub const EVERYTHING: Self = Self {
18        min: f32::NEG_INFINITY,
19        max: f32::INFINITY,
20    };
21
22    /// The inverse of [`Self::EVERYTHING`]: stretches from positive infinity to negative infinity.
23    /// Contains nothing.
24    pub const NOTHING: Self = Self {
25        min: f32::INFINITY,
26        max: f32::NEG_INFINITY,
27    };
28
29    /// An invalid [`Rangef`] filled with [`f32::NAN`].
30    pub const NAN: Self = Self {
31        min: f32::NAN,
32        max: f32::NAN,
33    };
34
35    #[inline]
36    pub fn new(min: f32, max: f32) -> Self {
37        Self { min, max }
38    }
39
40    #[inline]
41    pub fn point(min_and_max: f32) -> Self {
42        Self {
43            min: min_and_max,
44            max: min_and_max,
45        }
46    }
47
48    /// The length of the range, i.e. `max - min`.
49    #[inline]
50    pub fn span(self) -> f32 {
51        self.max - self.min
52    }
53
54    /// The center of the range
55    #[inline]
56    pub fn center(self) -> f32 {
57        fast_midpoint(self.min, self.max)
58    }
59
60    #[inline]
61    #[must_use]
62    pub fn contains(self, x: f32) -> bool {
63        self.min <= x && x <= self.max
64    }
65
66    /// Equivalent to `x.clamp(min, max)`
67    #[inline]
68    #[must_use]
69    pub fn clamp(self, x: f32) -> f32 {
70        x.clamp(self.min, self.max)
71    }
72
73    /// Flip `min` and `max` if needed, so that `min <= max` after.
74    #[inline]
75    pub fn as_positive(self) -> Self {
76        Self {
77            min: self.min.min(self.max),
78            max: self.min.max(self.max),
79        }
80    }
81
82    /// Shrink by this much on each side, keeping the center
83    #[inline]
84    #[must_use]
85    pub fn shrink(self, amnt: f32) -> Self {
86        Self {
87            min: self.min + amnt,
88            max: self.max - amnt,
89        }
90    }
91
92    /// Expand by this much on each side, keeping the center
93    #[inline]
94    #[must_use]
95    pub fn expand(self, amnt: f32) -> Self {
96        Self {
97            min: self.min - amnt,
98            max: self.max + amnt,
99        }
100    }
101
102    /// Flip the min and the max
103    #[inline]
104    #[must_use]
105    pub fn flip(self) -> Self {
106        Self {
107            min: self.max,
108            max: self.min,
109        }
110    }
111
112    /// The overlap of two ranges, i.e. the range that is contained by both.
113    ///
114    /// If the ranges do not overlap, returns a range with `span() < 0.0`.
115    ///
116    /// ```
117    /// # use emath::Rangef;
118    /// assert_eq!(Rangef::new(0.0, 10.0).intersection(Rangef::new(5.0, 15.0)), Rangef::new(5.0, 10.0));
119    /// assert_eq!(Rangef::new(0.0, 10.0).intersection(Rangef::new(10.0, 20.0)), Rangef::new(10.0, 10.0));
120    /// assert!(Rangef::new(0.0, 10.0).intersection(Rangef::new(20.0, 30.0)).span() < 0.0);
121    /// ```
122    #[inline]
123    #[must_use]
124    pub fn intersection(self, other: Self) -> Self {
125        Self {
126            min: self.min.max(other.min),
127            max: self.max.min(other.max),
128        }
129    }
130
131    /// Do the two ranges intersect?
132    ///
133    /// ```
134    /// # use emath::Rangef;
135    /// assert!(Rangef::new(0.0, 10.0).intersects(Rangef::new(5.0, 15.0)));
136    /// assert!(Rangef::new(0.0, 10.0).intersects(Rangef::new(5.0, 6.0)));
137    /// assert!(Rangef::new(0.0, 10.0).intersects(Rangef::new(10.0, 20.0)));
138    /// assert!(!Rangef::new(0.0, 10.0).intersects(Rangef::new(20.0, 30.0)));
139    /// ```
140    #[inline]
141    #[must_use]
142    pub fn intersects(self, other: Self) -> bool {
143        other.min <= self.max && self.min <= other.max
144    }
145}
146
147impl From<Rangef> for RangeInclusive<f32> {
148    #[inline]
149    fn from(Rangef { min, max }: Rangef) -> Self {
150        min..=max
151    }
152}
153
154impl From<&Rangef> for RangeInclusive<f32> {
155    #[inline]
156    fn from(&Rangef { min, max }: &Rangef) -> Self {
157        min..=max
158    }
159}
160
161impl From<RangeInclusive<f32>> for Rangef {
162    #[inline]
163    fn from(range: RangeInclusive<f32>) -> Self {
164        Self::new(*range.start(), *range.end())
165    }
166}
167
168impl From<&RangeInclusive<f32>> for Rangef {
169    #[inline]
170    fn from(range: &RangeInclusive<f32>) -> Self {
171        Self::new(*range.start(), *range.end())
172    }
173}
174
175/// Makes specifying size ranges slightly more convenient (no need for the extra `.0` suffixes)
176impl From<RangeInclusive<i32>> for Rangef {
177    #[inline]
178    fn from(range: RangeInclusive<i32>) -> Self {
179        Self::new(*range.start() as _, *range.end() as _)
180    }
181}
182
183impl From<RangeFrom<f32>> for Rangef {
184    #[inline]
185    fn from(range: RangeFrom<f32>) -> Self {
186        Self::new(range.start, f32::INFINITY)
187    }
188}
189
190impl From<&RangeFrom<f32>> for Rangef {
191    #[inline]
192    fn from(range: &RangeFrom<f32>) -> Self {
193        Self::new(range.start, f32::INFINITY)
194    }
195}
196
197impl From<RangeFull> for Rangef {
198    #[inline]
199    fn from(_: RangeFull) -> Self {
200        Self::new(f32::NEG_INFINITY, f32::INFINITY)
201    }
202}
203
204impl From<&RangeFull> for Rangef {
205    #[inline]
206    fn from(_: &RangeFull) -> Self {
207        Self::new(f32::NEG_INFINITY, f32::INFINITY)
208    }
209}
210
211impl From<RangeToInclusive<f32>> for Rangef {
212    #[inline]
213    fn from(range: RangeToInclusive<f32>) -> Self {
214        Self::new(f32::NEG_INFINITY, range.end)
215    }
216}
217
218impl PartialEq<RangeInclusive<f32>> for Rangef {
219    #[inline]
220    fn eq(&self, other: &RangeInclusive<f32>) -> bool {
221        self.min == *other.start() && self.max == *other.end()
222    }
223}
224
225impl PartialEq<Rangef> for RangeInclusive<f32> {
226    #[inline]
227    fn eq(&self, other: &Rangef) -> bool {
228        *self.start() == other.min && *self.end() == other.max
229    }
230}