1#[derive(Debug, Clone, Copy, PartialEq)]
9pub struct Rect {
10 pub x1: f64,
11 pub y1: f64,
12 pub x2: f64,
13 pub y2: f64,
14}
15
16impl Rect {
17 pub fn new(x1: f64, y1: f64, x2: f64, y2: f64) -> Self {
19 Self { x1, y1, x2, y2 }
20 }
21
22 pub fn zero() -> Self {
24 Self::new(0.0, 0.0, 0.0, 0.0)
25 }
26
27 pub fn width(&self) -> f64 {
29 self.x2 - self.x1
30 }
31
32 pub fn height(&self) -> f64 {
34 self.y2 - self.y1
35 }
36
37 pub fn normalize(&mut self) {
39 if self.x1 > self.x2 {
40 std::mem::swap(&mut self.x1, &mut self.x2);
41 }
42 if self.y1 > self.y2 {
43 std::mem::swap(&mut self.y1, &mut self.y2);
44 }
45 }
46
47 pub fn normalized(&self) -> Self {
49 let mut r = *self;
50 r.normalize();
51 r
52 }
53
54 pub fn contains(&self, x: f64, y: f64) -> bool {
57 x >= self.x1 && x <= self.x2 && y >= self.y1 && y <= self.y2
58 }
59
60 pub fn intersect(&self, other: &Rect) -> Option<Rect> {
63 let x1 = self.x1.max(other.x1);
64 let y1 = self.y1.max(other.y1);
65 let x2 = self.x2.min(other.x2);
66 let y2 = self.y2.min(other.y2);
67 if x1 <= x2 && y1 <= y2 {
68 Some(Rect { x1, y1, x2, y2 })
69 } else {
70 None
71 }
72 }
73
74 pub fn union(&self, other: &Rect) -> Rect {
76 Rect {
77 x1: self.x1.min(other.x1),
78 y1: self.y1.min(other.y1),
79 x2: self.x2.max(other.x2),
80 y2: self.y2.max(other.y2),
81 }
82 }
83
84 pub fn inflate(&mut self, dx: f64, dy: f64) {
86 self.x1 -= dx;
87 self.y1 -= dy;
88 self.x2 += dx;
89 self.y2 += dy;
90 }
91
92 pub fn inflated(&self, dx: f64, dy: f64) -> Self {
94 let mut r = *self;
95 r.inflate(dx, dy);
96 r
97 }
98}
99
100impl Default for Rect {
101 fn default() -> Self {
102 Self::zero()
103 }
104}
105
106#[cfg(test)]
107mod tests {
108 use super::*;
109
110 #[test]
111 fn test_dimensions() {
112 let r = Rect::new(10.0, 20.0, 110.0, 70.0);
113 assert_eq!(r.width(), 100.0);
114 assert_eq!(r.height(), 50.0);
115 }
116
117 #[test]
118 fn test_normalize() {
119 let r = Rect::new(100.0, 200.0, 10.0, 20.0);
120 let n = r.normalized();
121 assert_eq!(n.x1, 10.0);
122 assert_eq!(n.y1, 20.0);
123 assert_eq!(n.x2, 100.0);
124 assert_eq!(n.y2, 200.0);
125 }
126
127 #[test]
128 fn test_contains() {
129 let r = Rect::new(0.0, 0.0, 100.0, 100.0);
130 assert!(r.contains(50.0, 50.0));
131 assert!(!r.contains(150.0, 50.0));
132 assert!(r.contains(0.0, 0.0)); assert!(r.contains(100.0, 100.0)); }
135
136 #[test]
137 fn test_intersect() {
138 let a = Rect::new(0.0, 0.0, 100.0, 100.0);
139 let b = Rect::new(50.0, 50.0, 150.0, 150.0);
140 let i = a.intersect(&b).unwrap();
141 assert_eq!(i, Rect::new(50.0, 50.0, 100.0, 100.0));
142
143 let c = Rect::new(200.0, 200.0, 300.0, 300.0);
144 assert!(a.intersect(&c).is_none());
145 }
146
147 #[test]
148 fn test_union() {
149 let a = Rect::new(10.0, 10.0, 50.0, 50.0);
150 let b = Rect::new(30.0, 30.0, 80.0, 80.0);
151 let u = a.union(&b);
152 assert_eq!(u, Rect::new(10.0, 10.0, 80.0, 80.0));
153 }
154
155 #[test]
156 fn test_inflate() {
157 let r = Rect::new(10.0, 10.0, 50.0, 50.0);
158 let i = r.inflated(5.0, 5.0);
159 assert_eq!(i, Rect::new(5.0, 5.0, 55.0, 55.0));
160 }
161}