1use crate::{Point, Size};
2
3#[derive(Copy, Clone, Default, Debug, PartialEq)]
16pub struct Rectangle {
17 position: Point,
19
20 size: Size,
21}
22
23impl Rectangle {
24 pub fn new(position: impl Into<Point>, size: impl Into<Size>) -> Self {
26 Rectangle {
27 position: position.into(),
28 size: size.into(),
29 }
30 }
31
32 pub fn x(&self) -> f64 {
34 self.position.x()
35 }
36
37 pub fn set_x(&mut self, x: impl Into<f64>) {
39 self.position.set_x(x);
40 }
41
42 pub fn y(&self) -> f64 {
44 self.position.y()
45 }
46
47 pub fn set_y(&mut self, y: impl Into<f64>) {
49 self.position.set_y(y);
50 }
51
52 pub fn position(&self) -> Point {
54 self.position
55 }
56
57 pub fn set_position(&mut self, position: impl Into<Point>) {
59 self.position = position.into();
60 }
61
62 pub fn width(&self) -> f64 {
64 self.size.width()
65 }
66
67 pub fn set_width(&mut self, width: impl Into<f64>) {
69 self.size.set_width(width.into());
70 }
71
72 pub fn height(&self) -> f64 {
74 self.size.height()
75 }
76
77 pub fn set_height(&mut self, height: impl Into<f64>) {
79 self.size.set_height(height.into());
80 }
81
82 pub fn size(&self) -> Size {
84 self.size
85 }
86
87 pub fn set_size(&mut self, width: impl Into<f64>, height: impl Into<f64>) {
89 self.size.set_width(width.into());
90 self.size.set_height(height.into());
91 }
92
93 pub fn contains(&self, point: impl Into<Point>) -> bool {
95 let point: Point = point.into();
96 point.x() >= self.x()
97 && point.x() <= self.x() + self.width()
98 && point.y() >= self.y()
99 && point.y() <= self.y() + self.height()
100 }
101
102 pub fn contains_rect(&self, rect: &Rectangle) -> bool {
104 let p1 = rect.position();
105 let p2 = (p1.x() + rect.width(), p1.y() + rect.height());
106 self.contains(p1) && self.contains(p2)
107 }
108
109 pub fn intersects(&self, rect: &Rectangle) -> bool {
111 !(rect.x() > (self.x() + self.width())
112 || self.x() > (rect.x() + rect.width())
113 || rect.y() > (self.y() + self.height())
114 || self.y() > (rect.y() + rect.height()))
115 }
116
117 pub fn join_with_rectangle(&mut self, other: &Rectangle) {
120 if other.x() < self.x() {
121 self.set_width(self.width() + self.x() - other.x());
122 self.set_x(other.x());
123 }
124 if other.y() < self.y() {
125 self.set_height(self.height() + self.y() - other.y());
126 self.set_y(other.y());
127 }
128 if other.x() + other.width() > self.x() + self.width() {
129 self.set_width(other.x() + other.width() - self.x());
130 }
131 if other.y() + other.height() > self.y() + self.height() {
132 self.set_height(other.y() + other.height() - self.y());
133 }
134 }
135
136 pub fn join_with_point(&mut self, point: &Point) {
138 if point.x() < self.x() {
139 self.set_width(self.width() + self.x() - point.x());
140 self.set_x(point.x());
141 }
142 if point.y() < self.y() {
143 self.set_height(self.height() + self.y() - point.y());
144 self.set_y(point.y());
145 }
146 if point.x() > self.x() + self.width() {
147 self.set_width(point.x() - self.x());
148 }
149 if point.y() > self.y() + self.height() {
150 self.set_height(point.y() - self.y());
151 }
152 }
153
154 pub fn box_into(&mut self, container: Rectangle) {
156 if self.x() < container.x() {
157 self.set_width(self.width() - (container.x() - self.x()));
158 self.set_x(container.x());
159 }
160 if self.y() < container.y() {
161 self.set_height(self.height() - (container.y() - self.y()));
162 self.set_y(container.y());
163 }
164 if self.x() + self.width() > container.x() + container.width() {
165 self.set_width(container.width() - container.x() + self.x());
166 }
167 if self.y() + self.height() > container.y() + container.height() {
168 self.set_height(container.height() - container.y() + self.y());
169 }
170 }
171}
172
173impl From<(Point, Size)> for Rectangle {
176 fn from(t: (Point, Size)) -> Self {
177 Rectangle::new(t.0, t.1)
178 }
179}
180
181impl From<(i32, i32, i32, i32)> for Rectangle {
182 fn from(t: (i32, i32, i32, i32)) -> Self {
183 Rectangle::new((t.0 as f64, t.1 as f64), (t.2 as f64, t.3 as f64))
184 }
185}
186
187impl From<(f64, f64, f64, f64)> for Rectangle {
188 fn from(t: (f64, f64, f64, f64)) -> Self {
189 Rectangle::new((t.0, t.1), (t.2, t.3))
190 }
191}
192
193#[cfg(test)]
194mod tests {
195 use crate::prelude::*;
196
197 #[test]
198 fn test_new() {
199 let rect = Rectangle::new((5.0, 10.0), (20.0, 30.0));
200
201 assert!(crate::f64_cmp(rect.x(), 5.0));
202 assert!(crate::f64_cmp(rect.y(), 10.0));
203 assert!(crate::f64_cmp(rect.width(), 20.0));
204 assert!(crate::f64_cmp(rect.height(), 30.0));
205 }
206
207 #[test]
208 fn test_contains() {
209 let rect = Rectangle::new((5.0, 10.0), (20.0, 30.0));
210
211 let p = Point::new(5.0, 10.0);
213 assert!(rect.contains(p), "{:?}", p);
214
215 let p = Point::new(25.0, 40.0);
217 assert!(rect.contains(p), "{:?}", p);
218
219 let p = Point::new(15.0, 15.0);
221 assert!(rect.contains(p), "{:?}", p);
222
223 let p = Point::new(30.0, 15.0);
225 assert!(!rect.contains(p), "{:?}", p);
226
227 let p = Point::new(15.0, 50.0);
229 assert!(!rect.contains(p), "{:?}", p);
230
231 let p = Point::new(30.0, 40.0);
233 assert!(!rect.contains(p), "{:?}", p);
234 }
235
236 #[test]
237 fn test_contains_rect() {
238 let rect = Rectangle::new((5.0, 10.0), (20.0, 30.0));
239
240 let r = Rectangle::new((5.0, 10.0), (20.0, 30.0));
242 assert!(rect.contains_rect(&r), "{:?}", r);
243
244 let r = Rectangle::new((5.0, 20.0), (10.0, 20.0));
246 assert!(rect.contains_rect(&r), "{:?}", r);
247
248 let r = Rectangle::new((5.0, 10.0), (10.0, 20.0));
250 assert!(rect.contains_rect(&r), "{:?}", r);
251
252 let r = Rectangle::new((10.0, 20.0), (5.0, 10.0));
254 assert!(rect.contains_rect(&r), "{:?}", r);
255
256 let r = Rectangle::new((20.0, 25.0), (20.0, 30.0));
258 assert!(!rect.contains_rect(&r), "{:?}", r);
259
260 let r = Rectangle::new((50.0, 100.0), (20.0, 30.0));
262 assert!(!rect.contains_rect(&r), "{:?}", r);
263 }
264
265 #[test]
266 fn test_intersects() {
267 let rect = Rectangle::new((5.0, 10.0), (20.0, 30.0));
268
269 let r = Rectangle::new((5.0, 10.0), (20.0, 30.0));
271 assert!(rect.intersects(&r), "{:?}", r);
272
273 let r = Rectangle::new((25.0, 10.0), (20.0, 30.0));
275 assert!(rect.intersects(&r), "{:?}", r);
276
277 let r = Rectangle::new((-15.0, 10.0), (20.0, 30.0));
279 assert!(rect.intersects(&r), "{:?}", r);
280
281 let r = Rectangle::new((5.0, 40.0), (20.0, 30.0));
283 assert!(rect.intersects(&r), "{:?}", r);
284
285 let r = Rectangle::new((5.0, -20.0), (20.0, 30.0));
287 assert!(rect.intersects(&r), "{:?}", r);
288
289 let r = Rectangle::new((30.0, 10.0), (20.0, 30.0));
292 assert!(!rect.intersects(&r), "{:?}", r);
293
294 let r = Rectangle::new((-20.0, 10.0), (20.0, 30.0));
297 assert!(!rect.intersects(&r), "{:?}", r);
298
299 let r = Rectangle::new((5.0, 50.0), (20.0, 30.0));
302 assert!(!rect.intersects(&r), "{:?}", r);
303
304 let r = Rectangle::new((5.0, -30.0), (20.0, 30.0));
307 assert!(!rect.intersects(&r), "{:?}", r);
308 }
309}