solstrale/util/
interval.rs1use derive_more::Constructor;
3use std::ops::{Add, Sub};
4
5#[derive(Copy, Clone, PartialEq, Debug, Default, Constructor)]
7pub struct Interval {
8 pub min: f64,
10 pub max: f64,
12}
13
14pub const EMPTY_INTERVAL: Interval = Interval {
16 min: f64::INFINITY,
17 max: f64::NEG_INFINITY,
18};
19pub const UNIVERSE_INTERVAL: Interval = Interval {
21 min: f64::NEG_INFINITY,
22 max: f64::INFINITY,
23};
24pub const RAY_INTERVAL: Interval = Interval {
26 min: 0.001,
27 max: f64::INFINITY,
28};
29
30pub fn combine_intervals(a: Interval, b: Interval) -> Interval {
33 Interval {
34 min: a.min.min(b.min),
35 max: a.max.max(b.max),
36 }
37}
38
39impl Add<f64> for Interval {
40 type Output = Interval;
41
42 fn add(self, rhs: f64) -> Self::Output {
45 Interval {
46 min: self.min + rhs,
47 max: self.max + rhs,
48 }
49 }
50}
51
52impl Sub<f64> for Interval {
53 type Output = Interval;
54
55 fn sub(self, rhs: f64) -> Self::Output {
58 Interval {
59 min: self.min - rhs,
60 max: self.max - rhs,
61 }
62 }
63}
64
65impl Interval {
66 pub fn contains(&self, x: f64) -> bool {
68 self.min <= x && x <= self.max
69 }
70
71 pub fn clamp(&self, x: f64) -> f64 {
73 if x < self.min {
74 return self.min;
75 }
76 if x > self.max {
77 return self.max;
78 }
79 x
80 }
81
82 pub fn size(&self) -> f64 {
84 self.max - self.min
85 }
86
87 pub fn expand(&self, delta: f64) -> Interval {
90 let padding = delta / 2.;
91 Interval {
92 min: self.min - padding,
93 max: self.max + padding,
94 }
95 }
96}
97
98#[cfg(test)]
99mod tests {
100 use crate::util::interval::{Interval, combine_intervals};
101
102 #[test]
103 fn test_combine_intervals() {
104 let mut res = combine_intervals(Interval::new(0., 2.), Interval::new(1., 3.));
105 assert_eq!(Interval::new(0., 3.), res);
106
107 res = combine_intervals(Interval::new(0., 1.), Interval::new(2., 3.));
108 assert_eq!(Interval::new(0., 3.), res);
109
110 res = combine_intervals(Interval::new(3., 3.), Interval::new(-1., -1.));
111 assert_eq!(Interval::new(-1., 3.), res);
112 }
113
114 #[test]
115 fn test_contains() {
116 let interval = Interval::new(-2., 2.);
117 assert!(!interval.contains(-3.));
118 assert!(interval.contains(-2.));
119 assert!(interval.contains(2.));
120 assert!(!interval.contains(3.));
121 }
122
123 #[test]
124 fn test_clamp() {
125 let interval = Interval::new(-2., 2.);
126 assert_eq!(-2., interval.clamp(-3.));
127 assert_eq!(-2., interval.clamp(-2.));
128 assert_eq!(0., interval.clamp(-0.));
129 assert_eq!(2., interval.clamp(2.));
130 assert_eq!(2., interval.clamp(3.));
131 }
132
133 #[test]
134 fn test_size() {
135 assert_eq!(0., Interval::new(0., 0.).size());
136 assert_eq!(2., Interval::new(-1., 1.).size());
137 assert_eq!(-2., Interval::new(1., -1.).size());
138 }
139
140 #[test]
141 fn test_expand() {
142 let interval = Interval::new(-2., 2.);
143 assert_eq!(Interval::new(-3., 3.), interval.expand(2.));
144 assert_eq!(
145 Interval {
146 min: -3.5,
147 max: 3.5
148 },
149 interval.expand(3.)
150 );
151 assert_eq!(Interval::new(-1., 1.), interval.expand(-2.));
152 }
153
154 #[test]
155 fn test_sub_and_add() {
156 let interval = Interval::new(-2., 2.);
157 assert_eq!(Interval::new(0., 4.), interval + 2.);
158 assert_eq!(Interval::new(1., 5.), interval + 3.);
159 assert_eq!(Interval::new(-4., 0.), interval - 2.);
160 }
161}