1#[derive(Debug, Clone, Copy, PartialEq)]
22pub struct Range {
26 min: f64,
28 max: f64,
30}
31
32impl std::fmt::Display for Range {
34 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
36 write!(f, "({} to {})", self.min, self.max)
37 }
38}
39
40impl std::default::Default for Range {
42 fn default() -> Self {
43 Self::none()
44 }
45}
46
47impl Range {
49 #[must_use]
52 #[inline]
53 pub fn new(min: f64, max: f64) -> Self {
54 Self { min, max }
55 }
56
57 #[must_use]
60 #[inline]
61 pub const fn none() -> Self {
62 Self { min: 0., max: -1. }
63 }
64
65 #[inline]
68 pub fn is_none(&self) -> bool {
69 self.min > self.max
70 }
71
72 #[must_use]
74 #[inline]
75 pub fn of_pts(a: f64, b: f64) -> Self {
76 if a < b {
77 Self::new(a, b)
78 } else {
79 Self::new(b, a)
80 }
81 }
82
83 #[inline]
86 pub fn size(&self) -> f64 {
87 if self.is_none() {
88 0.
89 } else {
90 self.max - self.min
91 }
92 }
93
94 #[inline]
97 pub fn center(&self) -> f64 {
98 (self.max + self.min) / 2.0
99 }
100
101 #[must_use]
104 #[inline]
105 pub fn include(mut self, x: f64) -> Self {
106 if self.is_none() {
107 self.min = x;
108 self.max = x;
109 } else {
110 if x < self.min {
111 self.min = x;
112 }
113 if x > self.max {
114 self.max = x;
115 }
116 }
117 self
118 }
119
120 #[must_use]
123 #[inline]
124 pub fn enlarge(mut self, value: f64) -> Self {
125 if !self.is_none() {
126 self.min -= value;
127 self.max += value;
128 }
129 self
130 }
131
132 #[must_use]
135 #[inline]
136 pub fn reduce(mut self, value: f64) -> Self {
137 if !self.is_none() {
138 self.min += value;
139 self.max -= value;
140 }
141 self
142 }
143
144 #[must_use]
148 #[inline]
149 pub fn union(mut self, other: &Range) -> Self {
150 if other.is_none() {
151 self
152 } else if self.is_none() {
153 self.min = other.min;
154 self.max = other.max;
155 self
156 } else {
157 if other.min < self.min {
158 self.min = other.min;
159 }
160 if other.max > self.max {
161 self.max = other.max;
162 }
163 self
164 }
165 }
166
167 #[must_use]
171 #[inline]
172 pub fn intersect(mut self, other: &Range) -> Self {
173 if other.is_none() {
174 self
175 } else if self.is_none() {
176 self.min = other.min;
177 self.max = other.max;
178 self
179 } else {
180 if other.min > self.min {
181 self.min = other.min;
182 }
183 if other.max < self.max {
184 self.max = other.max;
185 }
186 self
187 }
188 }
189}
190
191impl std::ops::Add<f64> for Range {
193 type Output = Self;
194 fn add(self, scale: f64) -> Self {
195 Self {
196 min: self.min + scale,
197 max: self.max + scale,
198 }
199 }
200}
201
202impl std::ops::AddAssign<f64> for Range {
204 fn add_assign(&mut self, delta: f64) {
205 self.min += delta;
206 self.max += delta;
207 }
208}
209
210impl std::ops::Sub<f64> for Range {
212 type Output = Self;
213 fn sub(self, scale: f64) -> Self {
214 Self {
215 min: self.min - scale,
216 max: self.max - scale,
217 }
218 }
219}
220
221impl std::ops::SubAssign<f64> for Range {
223 fn sub_assign(&mut self, delta: f64) {
224 self.min -= delta;
225 self.max -= delta;
226 }
227}
228
229impl std::ops::Mul<f64> for Range {
231 type Output = Self;
232 fn mul(self, scale: f64) -> Self {
233 if scale < 0. {
234 Self {
235 min: self.max * scale,
236 max: self.min * scale,
237 }
238 } else {
239 Self {
240 min: self.min * scale,
241 max: self.max * scale,
242 }
243 }
244 }
245}
246impl std::ops::MulAssign<f64> for Range {
248 fn mul_assign(&mut self, scale: f64) {
249 self.max *= scale;
250 self.min *= scale;
251 }
252}
253
254impl std::ops::Div<f64> for Range {
256 type Output = Self;
257 fn div(self, scale: f64) -> Self {
258 if scale < 0. {
259 Self {
260 min: self.max / scale,
261 max: self.min / scale,
262 }
263 } else {
264 Self {
265 min: self.min / scale,
266 max: self.max / scale,
267 }
268 }
269 }
270}
271impl std::ops::DivAssign<f64> for Range {
273 fn div_assign(&mut self, scale: f64) {
274 self.max /= scale;
275 self.min /= scale;
276 }
277}
278
279impl std::ops::Index<usize> for Range {
281 type Output = f64;
282
283 #[inline]
284 fn index(&self, index: usize) -> &Self::Output {
285 assert!(index < 2);
286 if index == 0 {
287 &self.min
288 } else {
289 &self.max
290 }
291 }
292}
293
294#[cfg(test)]
297mod test_range {
298 use super::*;
299 pub fn rng_eq(rng: &Range, min: f64, max: f64) {
300 assert!(
301 (rng.min - min).abs() < 1E-8,
302 "mismatch in x {:?} {} {}",
303 rng,
304 min,
305 max
306 );
307 assert!(
308 (rng.max - max).abs() < 1E-8,
309 "mismatch in x {:?} {} {}",
310 rng,
311 min,
312 max
313 );
314 }
315 #[test]
316 fn test_simple() {
317 assert!(Range::none().is_none());
318 rng_eq(&Range::new(1., 2.), 1., 2.);
319 assert!(Range::new(0.1, 0.).is_none());
320 assert!(!Range::new(0., 0.1).is_none());
321 rng_eq(&(Range::new(1., 2.) * 3.), 3., 6.);
322 rng_eq(&(Range::new(3., 6.) / 3.), 1., 2.);
323
324 assert_eq!(Range::none().size(), 0.);
325 assert_eq!(Range::new(1., 0.).size(), 0.);
326 assert_eq!(Range::new(0., 1.).size(), 1.);
327 assert_eq!(Range::new(2., 0.).size(), 0.);
328 assert_eq!(Range::new(0., 2.).size(), 2.);
329 }
330 #[test]
331 fn test_union() {
332 rng_eq(&Range::new(0., 4.).union(&Range::new(0., 4.)), 0., 4.);
333 rng_eq(&Range::new(0., 4.).union(&Range::new(0., 5.)), 0., 5.);
334 rng_eq(&Range::new(0., 4.).union(&Range::new(2., 5.)), 0., 5.);
335 rng_eq(&Range::new(0., 4.).union(&Range::new(2., 3.)), 0., 4.);
336 rng_eq(&Range::new(0., 4.).union(&Range::new(-1., 3.)), -1., 4.);
337 rng_eq(&Range::new(0., 4.).union(&Range::new(-1., 5.)), -1., 5.);
338 }
339 #[test]
340 fn test_intersect() {
341 rng_eq(&Range::new(0., 4.).intersect(&Range::new(0., 4.)), 0., 4.);
342 rng_eq(&Range::new(0., 4.).intersect(&Range::new(0., 5.)), 0., 4.);
343 rng_eq(&Range::new(0., 4.).intersect(&Range::new(2., 5.)), 2., 4.);
344 rng_eq(&Range::new(0., 4.).intersect(&Range::new(2., 3.)), 2., 3.);
345 rng_eq(&Range::new(0., 4.).intersect(&Range::new(-1., 3.)), 0., 3.);
346 rng_eq(&Range::new(0., 4.).intersect(&Range::new(-1., 5.)), 0., 4.);
347 }
348}