Skip to main content

blockworx_geom/
range.rs

1use std::ops::RangeInclusive;
2
3use crate::midpoint;
4
5/// An inclusive range of floats — one axis of a [`Rect`](crate::Rect).
6#[derive(Clone, Copy, Debug, PartialEq)]
7pub struct Rangef {
8    pub min: f32,
9    pub max: f32,
10}
11
12impl Rangef {
13    /// -∞ to +∞, inclusive.
14    pub const EVERYTHING: Self = Self {
15        min: f32::NEG_INFINITY,
16        max: f32::INFINITY,
17    };
18
19    /// The inverse of [`Self::EVERYTHING`], containing nothing.
20    pub const NOTHING: Self = Self {
21        min: f32::INFINITY,
22        max: f32::NEG_INFINITY,
23    };
24
25    #[inline]
26    pub const fn new(min: f32, max: f32) -> Self {
27        Self { min, max }
28    }
29
30    /// The degenerate range at a single value.
31    #[inline]
32    pub const fn point(min_and_max: f32) -> Self {
33        Self {
34            min: min_and_max,
35            max: min_and_max,
36        }
37    }
38
39    /// `max - min`.
40    #[inline]
41    pub fn span(self) -> f32 {
42        self.max - self.min
43    }
44
45    #[inline]
46    pub fn center(self) -> f32 {
47        midpoint(self.min, self.max)
48    }
49
50    #[inline]
51    #[must_use]
52    pub fn contains(self, x: f32) -> bool {
53        self.min <= x && x <= self.max
54    }
55
56    #[inline]
57    #[must_use]
58    pub fn clamp(self, x: f32) -> f32 {
59        x.clamp(self.min, self.max)
60    }
61
62    /// Swap the ends if needed, so `min <= max` after.
63    #[inline]
64    #[must_use]
65    pub fn as_positive(self) -> Self {
66        Self {
67            min: self.min.min(self.max),
68            max: self.min.max(self.max),
69        }
70    }
71
72    /// Shrink by `amnt` at each end, keeping the center.
73    #[inline]
74    #[must_use]
75    pub fn shrink(self, amnt: f32) -> Self {
76        Self {
77            min: self.min + amnt,
78            max: self.max - amnt,
79        }
80    }
81
82    /// Grow by `amnt` at each end, keeping the center.
83    #[inline]
84    #[must_use]
85    pub fn expand(self, amnt: f32) -> Self {
86        Self {
87            min: self.min - amnt,
88            max: self.max + amnt,
89        }
90    }
91
92    #[inline]
93    #[must_use]
94    pub fn flip(self) -> Self {
95        Self {
96            min: self.max,
97            max: self.min,
98        }
99    }
100
101    /// The overlap of two ranges. `span() < 0.0` when they do not overlap.
102    #[inline]
103    #[must_use]
104    pub fn intersection(self, other: Self) -> Self {
105        Self {
106            min: self.min.max(other.min),
107            max: self.max.min(other.max),
108        }
109    }
110
111    #[inline]
112    #[must_use]
113    pub fn intersects(self, other: Self) -> bool {
114        other.min <= self.max && self.min <= other.max
115    }
116}
117
118impl From<Rangef> for RangeInclusive<f32> {
119    #[inline]
120    fn from(Rangef { min, max }: Rangef) -> Self {
121        min..=max
122    }
123}
124
125impl From<RangeInclusive<f32>> for Rangef {
126    #[inline]
127    fn from(range: RangeInclusive<f32>) -> Self {
128        Self::new(*range.start(), *range.end())
129    }
130}