1use crate::math::vect::Vect;
2use std::mem;
3use crate::math::{Intersection, IntersectionPoints};
4use crate::math::circle::Circ;
5use crate::Ray;
6
7
8#[derive(Copy, Clone, Debug)]
10pub struct Rect {
11 pub min: Vect,
12 pub max: Vect,
13}
14
15pub enum Sides {
16 Right, Left, Top, Bottom, In
17}
18
19impl Rect {
20 pub const ZERO: Rect = Rect{min: Vect::ZERO, max: Vect::ZERO};
21 pub const INVERTED_MAX_RECT: Rect = Rect{min: Vect::MAX, max: Vect::MIN};
22 pub const MAX_RECT: Rect = Rect{min: Vect::MIN, max: Vect::MAX};
23
24 #[inline]
26 pub fn new(x0: f32, y0: f32, x1: f32, y1: f32) -> Rect {
27 Rect {
28 min: Vect { x: x0, y: y0 },
29 max: Vect { x: x1, y: y1 },
30 }
31 }
32
33 #[inline]
35 pub fn wh(x: f32, y: f32, w: f32, h: f32) -> Rect {
36 Rect {
37 min: Vect { x, y },
38 max: Vect { x: x + w, y: y + h },
39 }
40 }
41
42 #[inline]
44 pub fn centered(c: Vect, mut w: f32, mut h: f32) -> Rect {
45 w /= 2f32;
46 h /= 2f32;
47 Rect {
48 min: Vect { x: c.x - w, y: c.y - h },
49 max: Vect { x: c.x + w, y: c.y + h },
50 }
51 }
52
53 #[inline]
56 pub fn cube(c: Vect, rad: f32) -> Rect {
57 Rect {
58 min: Vect { x: c.x - rad, y: c.y - rad },
59 max: Vect { x: c.x + rad, y: c.y + rad },
60 }
61 }
62
63 #[inline]
66 pub fn from_vec(v: Vect) -> Rect {
67 Rect {
68 min: Vect::ZERO,
69 max: v,
70 }
71 }
72
73 #[inline]
75 pub fn bounds_for(points: &[Vect]) -> Rect {
76 if points.is_empty() {
77 return Self::ZERO;
78 }
79
80 let mut bounds = Self::INVERTED_MAX_RECT;
81
82 for p in points {
83 if p.x > bounds.max.x {
84 bounds.max.x = p.x;
85 }
86 if p.x < bounds.min.x {
87 bounds.min.x = p.x;
88 }
89 if p.y > bounds.max.y {
90 bounds.max.y = p.y;
91 }
92 if p.y < bounds.min.y {
93 bounds.min.y = p.y;
94 }
95 }
96
97 bounds
98 }
99
100 #[inline]
102 pub fn verts(&self) -> [Vect; 4] {
103 [
104 self.min,
105 Vect { x: self.min.x, y: self.max.y },
106 self.max,
107 Vect { x: self.max.x, y: self.min.y }
108 ]
109 }
110
111 #[inline]
113 pub fn union(&self, o: &Rect) -> Rect {
114 Rect {
115 min: Vect { x: self.min.x.min(o.min.x), y: self.min.y.min(o.min.y) },
116 max: Vect { x: self.max.x.max(o.max.x), y: self.max.y.max(o.max.y) },
117 }
118 }
119
120 #[inline]
122 pub fn center(&self) -> Vect {
123 self.min + (self.max - self.min) / 2f32
124 }
125
126 #[inline]
128 pub fn loc_verts(&self) -> [Vect; 4] {
129 let c = self.center();
130 let mut verts = self.verts();
131 for i in 0..4 {
132 verts[i] -= c;
133 }
134 verts
135 }
136
137 #[inline]
139 pub fn to_local(&self) -> Rect {
140 Self::centered(Vect::ZERO, self.width(), self.height())
141 }
142
143 #[inline]
145 pub fn width(&self) -> f32 {
146 self.max.x - self.min.x
147 }
148
149 #[inline]
151 pub fn height(&self) -> f32 {
152 self.max.y - self.min.y
153 }
154
155 pub fn respective(&self, pos: Vect) -> Sides {
157 if pos.x < self.min.x {
158 return Sides::Left;
159 }
160 if pos.x > self.max.x {
161 return Sides::Right;
162 }
163 if pos.y < self.min.y {
164 return Sides::Bottom;
165 }
166 if pos.y > self.max.y {
167 return Sides::Top;
168 }
169 Sides::In
170 }
171
172 #[inline]
174 pub fn normalized(mut self) -> Rect {
175 if self.min.x > self.max.x {
176 mem::swap(&mut self.min.x , &mut self.max.x)
177 }
178
179 if self.min.y > self.max.y {
180 mem::swap(&mut self.min.y , &mut self.max.y)
181 }
182
183 self
184 }
185
186 #[inline]
188 pub fn contains(&self, pos: Vect) -> bool {
189 self.max.x > pos.x && self.min.x < pos.x && self.max.y > pos.y && self.min.y < pos.y
190 }
191
192 #[inline]
194 pub fn fits_in(&self, o: &Rect) -> bool {
195 self.max.x <= o.max.x && self.max.y <= o.max.y && o.min.x <= self.min.x && o.min.y <= self.min.y
196 }
197
198 #[inline]
200 pub fn radius(&self) -> f32 {
201 (self.max - self.min).len() / 2f32
202 }
203
204 #[inline]
206 pub fn moved(&self, delta: Vect) -> Self {
207 Rect {
208 min: self.min + delta,
209 max: self.max + delta,
210 }
211 }
212
213 #[inline]
214 pub fn centered_to(&self, pos: Vect) -> Self {
215 Self::centered(pos, self.width(), self.height())
216 }
217
218 #[inline]
219 pub fn area(&self) -> f32 {
220 self.width() * self.height()
221 }
222
223 pub fn to_rays(&self) -> [Ray; 4] {
224 let verts = self.verts();
225 [
226 Ray::from_points(verts[0], verts[1]),
227 Ray::from_points(verts[1], verts[2]),
228 Ray::from_points(verts[2], verts[3]),
229 Ray::from_points(verts[3], verts[0]),
230 ]
231 }
232}
233
234impl Intersection<Rect> for Rect {
235 #[inline]
237 fn intersects(&self, o: &Rect) -> bool {
238 !(self.max.x < o.min.x || self.max.y < o.min.y || o.max.x < self.min.x || o.max.y < self.min.y)
239 }
240}
241
242impl Intersection<Circ> for Rect {
243 #[inline]
245 fn intersects(&self, o: &Circ) -> bool {
246 let left = self.min.x > o.c.x;
247 let right = self.max.x < o.c.x;
248 let bottom = self.min.y > o.c.y;
249 let top = self.max.y < o.c.y;
250
251 if !left && !right {
252 return !(self.min.y > o.c.y + o.r || self.max.y < o.c.y - o.r)
253 } else if !top && !bottom {
254 return !(self.min.x > o.c.x + o.r || self.max.x < o.c.x - o.r)
255 } else if left && bottom {
256 return o.contains(self.min)
257 } else if right && top {
258 return o.contains(self.max)
259 } else if right && bottom {
260 return o.contains(Vect::new(self.max.x, self.min.y))
261 } else if left && top {
262 return o.contains(Vect::new(self.min.x, self.max.y))
263 }
264
265 false
266 }
267}
268
269impl Intersection<Ray> for Rect {
270 #[inline]
272 fn intersects(&self, o: &Ray) -> bool {
273 o.intersects(self)
274 }
275}
276
277impl IntersectionPoints<Ray> for Rect {
278 #[inline]
280 fn intersects_points(&self, o: &Ray) -> [Option<Vect>; 2] {
281 o.intersects_points(self)
282 }
283}
284
285impl Default for Rect {
286 fn default() -> Self {
287 Rect::ZERO
288 }
289}
290
291#[cfg(test)]
292mod tests {
293 use crate::math::rect::Rect;
294 use crate::math::Intersection;
295 use crate::Vect;
296 use crate::math::circle::Circ;
297
298 #[test]
299 fn intersects_test() {
300 let base = Rect::new(0f32, 0f32, 10f32, 10f32);
301 assert!(base.intersects(&base));
302 assert!(base.intersects(&Rect::new(10f32, 10f32, 100f32, 100f32)));
303 assert!(!base.intersects(&Rect::new(100f32, 100f32, 1000f32, 1000f32)));
304 }
305
306 #[test]
307 fn intersects_circle_test() {
308 let base = rect!(0, 0, 100, 100);
309 assert!(base.intersects(&circ!(0, 0; 0)));
310 assert!(base.intersects(&circ!(10, 10; 10)));
311 assert!(base.intersects(&circ!(-10, -10; 10f32.hypot(10.0))));
312 assert!(base.intersects(&circ!(110, 50; 10)));
313 assert!(!base.intersects(&circ!(-10, -10; 10.0)));
314
315 }
316}