1use std::f32::INFINITY;
2use std::fmt;
3
4use crate::*;
5
6#[repr(C)]
22#[derive(Clone, Copy, Eq, PartialEq)]
23#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
24#[cfg_attr(feature = "bytemuck", derive(bytemuck::Pod, bytemuck::Zeroable))]
25pub struct Rect {
26 pub min: Pos2,
28
29 pub max: Pos2,
31}
32
33impl Rect {
34 pub const EVERYTHING: Self = Self {
36 min: pos2(-INFINITY, -INFINITY),
37 max: pos2(INFINITY, INFINITY),
38 };
39
40 pub const NOTHING: Self = Self {
56 min: pos2(INFINITY, INFINITY),
57 max: pos2(-INFINITY, -INFINITY),
58 };
59
60 pub const NAN: Self = Self {
62 min: pos2(f32::NAN, f32::NAN),
63 max: pos2(f32::NAN, f32::NAN),
64 };
65
66 pub const ZERO: Self = Self {
68 min: Pos2::ZERO,
69 max: Pos2::ZERO,
70 };
71
72 #[inline(always)]
73 pub const fn from_min_max(min: Pos2, max: Pos2) -> Self {
74 Self { min, max }
75 }
76
77 #[inline(always)]
79 pub fn from_min_size(min: Pos2, size: Vec2) -> Self {
80 Self {
81 min,
82 max: min + size,
83 }
84 }
85
86 #[inline(always)]
87 pub fn from_center_size(center: Pos2, size: Vec2) -> Self {
88 Self {
89 min: center - size * 0.5,
90 max: center + size * 0.5,
91 }
92 }
93
94 #[inline(always)]
95 pub fn from_x_y_ranges(x_range: impl Into<Rangef>, y_range: impl Into<Rangef>) -> Self {
96 let x_range = x_range.into();
97 let y_range = y_range.into();
98 Self {
99 min: pos2(x_range.min, y_range.min),
100 max: pos2(x_range.max, y_range.max),
101 }
102 }
103
104 #[inline]
106 pub fn from_two_pos(a: Pos2, b: Pos2) -> Self {
107 Self {
108 min: pos2(a.x.min(b.x), a.y.min(b.y)),
109 max: pos2(a.x.max(b.x), a.y.max(b.y)),
110 }
111 }
112
113 #[inline]
115 pub fn from_pos(point: Pos2) -> Self {
116 Self {
117 min: point,
118 max: point,
119 }
120 }
121
122 pub fn from_points(points: &[Pos2]) -> Self {
124 let mut rect = Self::NOTHING;
125 for &p in points {
126 rect.extend_with(p);
127 }
128 rect
129 }
130
131 #[inline]
133 pub fn everything_right_of(left_x: f32) -> Self {
134 let mut rect = Self::EVERYTHING;
135 rect.set_left(left_x);
136 rect
137 }
138
139 #[inline]
141 pub fn everything_left_of(right_x: f32) -> Self {
142 let mut rect = Self::EVERYTHING;
143 rect.set_right(right_x);
144 rect
145 }
146
147 #[inline]
149 pub fn everything_below(top_y: f32) -> Self {
150 let mut rect = Self::EVERYTHING;
151 rect.set_top(top_y);
152 rect
153 }
154
155 #[inline]
157 pub fn everything_above(bottom_y: f32) -> Self {
158 let mut rect = Self::EVERYTHING;
159 rect.set_bottom(bottom_y);
160 rect
161 }
162
163 #[must_use]
164 #[inline]
165 pub fn with_min_x(mut self, min_x: f32) -> Self {
166 self.min.x = min_x;
167 self
168 }
169
170 #[must_use]
171 #[inline]
172 pub fn with_min_y(mut self, min_y: f32) -> Self {
173 self.min.y = min_y;
174 self
175 }
176
177 #[must_use]
178 #[inline]
179 pub fn with_max_x(mut self, max_x: f32) -> Self {
180 self.max.x = max_x;
181 self
182 }
183
184 #[must_use]
185 #[inline]
186 pub fn with_max_y(mut self, max_y: f32) -> Self {
187 self.max.y = max_y;
188 self
189 }
190
191 #[must_use]
193 pub fn expand(self, amnt: f32) -> Self {
194 self.expand2(Vec2::splat(amnt))
195 }
196
197 #[must_use]
199 pub fn expand2(self, amnt: Vec2) -> Self {
200 Self::from_min_max(self.min - amnt, self.max + amnt)
201 }
202
203 #[must_use]
205 pub fn shrink(self, amnt: f32) -> Self {
206 self.shrink2(Vec2::splat(amnt))
207 }
208
209 #[must_use]
211 pub fn shrink2(self, amnt: Vec2) -> Self {
212 Self::from_min_max(self.min + amnt, self.max - amnt)
213 }
214
215 #[must_use]
216 #[inline]
217 pub fn translate(self, amnt: Vec2) -> Self {
218 Self::from_min_size(self.min + amnt, self.size())
219 }
220
221 #[must_use]
223 #[inline]
224 pub fn rotate_bb(self, rot: Rot2) -> Self {
225 let a = rot * self.left_top().to_vec2();
226 let b = rot * self.right_top().to_vec2();
227 let c = rot * self.left_bottom().to_vec2();
228 let d = rot * self.right_bottom().to_vec2();
229
230 Self::from_min_max(
231 a.min(b).min(c).min(d).to_pos2(),
232 a.max(b).max(c).max(d).to_pos2(),
233 )
234 }
235
236 #[must_use]
237 #[inline]
238 pub fn intersects(self, other: Self) -> bool {
239 self.min.x <= other.max.x
240 && other.min.x <= self.max.x
241 && self.min.y <= other.max.y
242 && other.min.y <= self.max.y
243 }
244
245 pub fn set_width(&mut self, w: f32) {
247 self.max.x = self.min.x + w;
248 }
249
250 pub fn set_height(&mut self, h: f32) {
252 self.max.y = self.min.y + h;
253 }
254
255 pub fn set_center(&mut self, center: Pos2) {
257 *self = self.translate(center - self.center());
258 }
259
260 #[must_use]
261 #[inline(always)]
262 pub fn contains(&self, p: Pos2) -> bool {
263 self.min.x <= p.x && p.x <= self.max.x && self.min.y <= p.y && p.y <= self.max.y
264 }
265
266 #[must_use]
267 pub fn contains_rect(&self, other: Self) -> bool {
268 self.contains(other.min) && self.contains(other.max)
269 }
270
271 #[must_use]
274 pub fn clamp(&self, p: Pos2) -> Pos2 {
275 p.clamp(self.min, self.max)
276 }
277
278 #[inline(always)]
279 pub fn extend_with(&mut self, p: Pos2) {
280 self.min = self.min.min(p);
281 self.max = self.max.max(p);
282 }
283
284 #[inline(always)]
285 pub fn extend_with_x(&mut self, x: f32) {
287 self.min.x = self.min.x.min(x);
288 self.max.x = self.max.x.max(x);
289 }
290
291 #[inline(always)]
292 pub fn extend_with_y(&mut self, y: f32) {
294 self.min.y = self.min.y.min(y);
295 self.max.y = self.max.y.max(y);
296 }
297
298 #[inline(always)]
301 #[must_use]
302 pub fn union(self, other: Self) -> Self {
303 Self {
304 min: self.min.min(other.min),
305 max: self.max.max(other.max),
306 }
307 }
308
309 #[inline]
311 #[must_use]
312 pub fn intersect(self, other: Self) -> Self {
313 Self {
314 min: self.min.max(other.min),
315 max: self.max.min(other.max),
316 }
317 }
318
319 #[inline(always)]
320 pub fn center(&self) -> Pos2 {
321 Pos2 {
322 x: (self.min.x + self.max.x) / 2.0,
323 y: (self.min.y + self.max.y) / 2.0,
324 }
325 }
326
327 #[inline(always)]
329 pub fn size(&self) -> Vec2 {
330 self.max - self.min
331 }
332
333 #[inline(always)]
334 pub fn width(&self) -> f32 {
335 self.max.x - self.min.x
336 }
337
338 #[inline(always)]
339 pub fn height(&self) -> f32 {
340 self.max.y - self.min.y
341 }
342
343 pub fn aspect_ratio(&self) -> f32 {
349 self.width() / self.height()
350 }
351
352 pub fn square_proportions(&self) -> Vec2 {
356 let w = self.width();
357 let h = self.height();
358 if w > h {
359 vec2(w / h, 1.0)
360 } else {
361 vec2(1.0, h / w)
362 }
363 }
364
365 #[inline(always)]
366 pub fn area(&self) -> f32 {
367 self.width() * self.height()
368 }
369
370 #[inline]
376 pub fn distance_to_pos(&self, pos: Pos2) -> f32 {
377 self.distance_sq_to_pos(pos).sqrt()
378 }
379
380 #[inline]
386 pub fn distance_sq_to_pos(&self, pos: Pos2) -> f32 {
387 if self.is_negative() {
388 return f32::INFINITY;
389 }
390
391 let dx = if self.min.x > pos.x {
392 self.min.x - pos.x
393 } else if pos.x > self.max.x {
394 pos.x - self.max.x
395 } else {
396 0.0
397 };
398
399 let dy = if self.min.y > pos.y {
400 self.min.y - pos.y
401 } else if pos.y > self.max.y {
402 pos.y - self.max.y
403 } else {
404 0.0
405 };
406
407 dx * dx + dy * dy
408 }
409
410 pub fn signed_distance_to_pos(&self, pos: Pos2) -> f32 {
424 if self.is_negative() {
425 return f32::INFINITY;
426 }
427
428 let edge_distances = (pos - self.center()).abs() - self.size() * 0.5;
429 let inside_dist = edge_distances.max_elem().min(0.0);
430 let outside_dist = edge_distances.max(Vec2::ZERO).length();
431 inside_dist + outside_dist
432 }
433
434 #[inline]
437 pub fn lerp_inside(&self, t: Vec2) -> Pos2 {
438 Pos2 {
439 x: lerp(self.min.x..=self.max.x, t.x),
440 y: lerp(self.min.y..=self.max.y, t.y),
441 }
442 }
443
444 #[inline]
446 pub fn lerp_towards(&self, other: &Self, t: f32) -> Self {
447 Self {
448 min: self.min.lerp(other.min, t),
449 max: self.max.lerp(other.max, t),
450 }
451 }
452
453 #[inline(always)]
454 pub fn x_range(&self) -> Rangef {
455 Rangef::new(self.min.x, self.max.x)
456 }
457
458 #[inline(always)]
459 pub fn y_range(&self) -> Rangef {
460 Rangef::new(self.min.y, self.max.y)
461 }
462
463 #[inline(always)]
464 pub fn bottom_up_range(&self) -> Rangef {
465 Rangef::new(self.max.y, self.min.y)
466 }
467
468 #[inline(always)]
470 pub fn is_negative(&self) -> bool {
471 self.max.x < self.min.x || self.max.y < self.min.y
472 }
473
474 #[inline(always)]
476 pub fn is_positive(&self) -> bool {
477 self.min.x < self.max.x && self.min.y < self.max.y
478 }
479
480 #[inline(always)]
482 pub fn is_finite(&self) -> bool {
483 self.min.is_finite() && self.max.is_finite()
484 }
485
486 #[inline(always)]
488 pub fn any_nan(self) -> bool {
489 self.min.any_nan() || self.max.any_nan()
490 }
491}
492
493impl Rect {
495 #[inline(always)]
497 pub fn left(&self) -> f32 {
498 self.min.x
499 }
500
501 #[inline(always)]
503 pub fn left_mut(&mut self) -> &mut f32 {
504 &mut self.min.x
505 }
506
507 #[inline(always)]
509 pub fn set_left(&mut self, x: f32) {
510 self.min.x = x;
511 }
512
513 #[inline(always)]
515 pub fn right(&self) -> f32 {
516 self.max.x
517 }
518
519 #[inline(always)]
521 pub fn right_mut(&mut self) -> &mut f32 {
522 &mut self.max.x
523 }
524
525 #[inline(always)]
527 pub fn set_right(&mut self, x: f32) {
528 self.max.x = x;
529 }
530
531 #[inline(always)]
533 pub fn top(&self) -> f32 {
534 self.min.y
535 }
536
537 #[inline(always)]
539 pub fn top_mut(&mut self) -> &mut f32 {
540 &mut self.min.y
541 }
542
543 #[inline(always)]
545 pub fn set_top(&mut self, y: f32) {
546 self.min.y = y;
547 }
548
549 #[inline(always)]
551 pub fn bottom(&self) -> f32 {
552 self.max.y
553 }
554
555 #[inline(always)]
557 pub fn bottom_mut(&mut self) -> &mut f32 {
558 &mut self.max.y
559 }
560
561 #[inline(always)]
563 pub fn set_bottom(&mut self, y: f32) {
564 self.max.y = y;
565 }
566
567 #[inline(always)]
568 #[doc(alias = "top_left")]
569 pub fn left_top(&self) -> Pos2 {
570 pos2(self.left(), self.top())
571 }
572
573 #[inline(always)]
574 pub fn center_top(&self) -> Pos2 {
575 pos2(self.center().x, self.top())
576 }
577
578 #[inline(always)]
579 #[doc(alias = "top_right")]
580 pub fn right_top(&self) -> Pos2 {
581 pos2(self.right(), self.top())
582 }
583
584 #[inline(always)]
585 pub fn left_center(&self) -> Pos2 {
586 pos2(self.left(), self.center().y)
587 }
588
589 #[inline(always)]
590 pub fn right_center(&self) -> Pos2 {
591 pos2(self.right(), self.center().y)
592 }
593
594 #[inline(always)]
595 #[doc(alias = "bottom_left")]
596 pub fn left_bottom(&self) -> Pos2 {
597 pos2(self.left(), self.bottom())
598 }
599
600 #[inline(always)]
601 pub fn center_bottom(&self) -> Pos2 {
602 pos2(self.center().x, self.bottom())
603 }
604
605 #[inline(always)]
606 #[doc(alias = "bottom_right")]
607 pub fn right_bottom(&self) -> Pos2 {
608 pos2(self.right(), self.bottom())
609 }
610
611 pub fn split_left_right_at_fraction(&self, t: f32) -> (Self, Self) {
613 self.split_left_right_at_x(lerp(self.min.x..=self.max.x, t))
614 }
615
616 pub fn split_left_right_at_x(&self, split_x: f32) -> (Self, Self) {
618 let left = Self::from_min_max(self.min, Pos2::new(split_x, self.max.y));
619 let right = Self::from_min_max(Pos2::new(split_x, self.min.y), self.max);
620 (left, right)
621 }
622
623 pub fn split_top_bottom_at_fraction(&self, t: f32) -> (Self, Self) {
625 self.split_top_bottom_at_y(lerp(self.min.y..=self.max.y, t))
626 }
627
628 pub fn split_top_bottom_at_y(&self, split_y: f32) -> (Self, Self) {
630 let top = Self::from_min_max(self.min, Pos2::new(self.max.x, split_y));
631 let bottom = Self::from_min_max(Pos2::new(self.min.x, split_y), self.max);
632 (top, bottom)
633 }
634}
635
636impl Rect {
637 pub fn intersects_ray(&self, o: Pos2, d: Vec2) -> bool {
641 let mut tmin = -f32::INFINITY;
642 let mut tmax = f32::INFINITY;
643
644 if d.x != 0.0 {
645 let tx1 = (self.min.x - o.x) / d.x;
646 let tx2 = (self.max.x - o.x) / d.x;
647
648 tmin = tmin.max(tx1.min(tx2));
649 tmax = tmax.min(tx1.max(tx2));
650 }
651
652 if d.y != 0.0 {
653 let ty1 = (self.min.y - o.y) / d.y;
654 let ty2 = (self.max.y - o.y) / d.y;
655
656 tmin = tmin.max(ty1.min(ty2));
657 tmax = tmax.min(ty1.max(ty2));
658 }
659
660 0.0 <= tmax && tmin <= tmax
661 }
662}
663
664impl fmt::Debug for Rect {
665 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
666 write!(f, "[{:?} - {:?}]", self.min, self.max)
667 }
668}
669
670impl fmt::Display for Rect {
671 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
672 f.write_str("[")?;
673 self.min.fmt(f)?;
674 f.write_str(" - ")?;
675 self.max.fmt(f)?;
676 f.write_str("]")?;
677 Ok(())
678 }
679}
680
681impl From<[Pos2; 2]> for Rect {
683 #[inline]
684 fn from([min, max]: [Pos2; 2]) -> Self {
685 Self { min, max }
686 }
687}
688
689impl Mul<f32> for Rect {
690 type Output = Self;
691
692 #[inline]
693 fn mul(self, factor: f32) -> Self {
694 Self {
695 min: self.min * factor,
696 max: self.max * factor,
697 }
698 }
699}
700
701impl Mul<Rect> for f32 {
702 type Output = Rect;
703
704 #[inline]
705 fn mul(self, vec: Rect) -> Rect {
706 Rect {
707 min: self * vec.min,
708 max: self * vec.max,
709 }
710 }
711}
712
713impl Div<f32> for Rect {
714 type Output = Self;
715
716 #[inline]
717 fn div(self, factor: f32) -> Self {
718 Self {
719 min: self.min / factor,
720 max: self.max / factor,
721 }
722 }
723}
724
725#[cfg(test)]
726mod tests {
727 use super::*;
728
729 #[test]
730 fn test_rect() {
731 let r = Rect::from_min_max(pos2(10.0, 10.0), pos2(20.0, 20.0));
732 assert_eq!(r.distance_sq_to_pos(pos2(15.0, 15.0)), 0.0);
733 assert_eq!(r.distance_sq_to_pos(pos2(10.0, 15.0)), 0.0);
734 assert_eq!(r.distance_sq_to_pos(pos2(10.0, 10.0)), 0.0);
735
736 assert_eq!(r.distance_sq_to_pos(pos2(5.0, 15.0)), 25.0); assert_eq!(r.distance_sq_to_pos(pos2(25.0, 15.0)), 25.0); assert_eq!(r.distance_sq_to_pos(pos2(15.0, 5.0)), 25.0); assert_eq!(r.distance_sq_to_pos(pos2(15.0, 25.0)), 25.0); assert_eq!(r.distance_sq_to_pos(pos2(25.0, 5.0)), 50.0); }
742
743 #[test]
744 fn test_ray_intersection() {
745 let rect = Rect::from_min_max(pos2(1.0, 1.0), pos2(3.0, 3.0));
746
747 eprintln!("Righward ray from left:");
748 assert!(rect.intersects_ray(pos2(0.0, 2.0), Vec2::RIGHT));
749
750 eprintln!("Righward ray from center:");
751 assert!(rect.intersects_ray(pos2(2.0, 2.0), Vec2::RIGHT));
752
753 eprintln!("Righward ray from right:");
754 assert!(!rect.intersects_ray(pos2(4.0, 2.0), Vec2::RIGHT));
755
756 eprintln!("Leftward ray from left:");
757 assert!(!rect.intersects_ray(pos2(0.0, 2.0), Vec2::LEFT));
758
759 eprintln!("Leftward ray from center:");
760 assert!(rect.intersects_ray(pos2(2.0, 2.0), Vec2::LEFT));
761
762 eprintln!("Leftward ray from right:");
763 assert!(rect.intersects_ray(pos2(4.0, 2.0), Vec2::LEFT));
764 }
765}