1use std::fmt;
2
3use crate::{lerp, pos2, vec2, Div, Mul, Pos2, Rangef, Rot2, Vec2};
4
5#[repr(C)]
21#[derive(Clone, Copy, Eq, PartialEq)]
22#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
23#[cfg_attr(feature = "bytemuck", derive(bytemuck::Pod, bytemuck::Zeroable))]
24pub struct Rect {
25 pub min: Pos2,
27
28 pub max: Pos2,
30}
31
32impl Rect {
33 pub const EVERYTHING: Self = Self {
35 min: pos2(-f32::INFINITY, -f32::INFINITY),
36 max: pos2(f32::INFINITY, f32::INFINITY),
37 };
38
39 pub const NOTHING: Self = Self {
55 min: pos2(f32::INFINITY, f32::INFINITY),
56 max: pos2(-f32::INFINITY, -f32::INFINITY),
57 };
58
59 pub const NAN: Self = Self {
61 min: pos2(f32::NAN, f32::NAN),
62 max: pos2(f32::NAN, f32::NAN),
63 };
64
65 pub const ZERO: Self = Self {
67 min: Pos2::ZERO,
68 max: Pos2::ZERO,
69 };
70
71 #[inline(always)]
72 pub const fn from_min_max(min: Pos2, max: Pos2) -> Self {
73 Self { min, max }
74 }
75
76 #[inline(always)]
78 pub fn from_min_size(min: Pos2, size: Vec2) -> Self {
79 Self {
80 min,
81 max: min + size,
82 }
83 }
84
85 #[inline(always)]
86 pub fn from_center_size(center: Pos2, size: Vec2) -> Self {
87 Self {
88 min: center - size * 0.5,
89 max: center + size * 0.5,
90 }
91 }
92
93 #[inline(always)]
94 pub fn from_x_y_ranges(x_range: impl Into<Rangef>, y_range: impl Into<Rangef>) -> Self {
95 let x_range = x_range.into();
96 let y_range = y_range.into();
97 Self {
98 min: pos2(x_range.min, y_range.min),
99 max: pos2(x_range.max, y_range.max),
100 }
101 }
102
103 #[inline]
105 pub fn from_two_pos(a: Pos2, b: Pos2) -> Self {
106 Self {
107 min: pos2(a.x.min(b.x), a.y.min(b.y)),
108 max: pos2(a.x.max(b.x), a.y.max(b.y)),
109 }
110 }
111
112 #[inline]
114 pub fn from_pos(point: Pos2) -> Self {
115 Self {
116 min: point,
117 max: point,
118 }
119 }
120
121 pub fn from_points(points: &[Pos2]) -> Self {
123 let mut rect = Self::NOTHING;
124 for &p in points {
125 rect.extend_with(p);
126 }
127 rect
128 }
129
130 #[inline]
132 pub fn everything_right_of(left_x: f32) -> Self {
133 let mut rect = Self::EVERYTHING;
134 rect.set_left(left_x);
135 rect
136 }
137
138 #[inline]
140 pub fn everything_left_of(right_x: f32) -> Self {
141 let mut rect = Self::EVERYTHING;
142 rect.set_right(right_x);
143 rect
144 }
145
146 #[inline]
148 pub fn everything_below(top_y: f32) -> Self {
149 let mut rect = Self::EVERYTHING;
150 rect.set_top(top_y);
151 rect
152 }
153
154 #[inline]
156 pub fn everything_above(bottom_y: f32) -> Self {
157 let mut rect = Self::EVERYTHING;
158 rect.set_bottom(bottom_y);
159 rect
160 }
161
162 #[must_use]
163 #[inline]
164 pub fn with_min_x(mut self, min_x: f32) -> Self {
165 self.min.x = min_x;
166 self
167 }
168
169 #[must_use]
170 #[inline]
171 pub fn with_min_y(mut self, min_y: f32) -> Self {
172 self.min.y = min_y;
173 self
174 }
175
176 #[must_use]
177 #[inline]
178 pub fn with_max_x(mut self, max_x: f32) -> Self {
179 self.max.x = max_x;
180 self
181 }
182
183 #[must_use]
184 #[inline]
185 pub fn with_max_y(mut self, max_y: f32) -> Self {
186 self.max.y = max_y;
187 self
188 }
189
190 #[must_use]
192 pub fn expand(self, amnt: f32) -> Self {
193 self.expand2(Vec2::splat(amnt))
194 }
195
196 #[must_use]
198 pub fn expand2(self, amnt: Vec2) -> Self {
199 Self::from_min_max(self.min - amnt, self.max + amnt)
200 }
201
202 #[must_use]
204 pub fn scale_from_center(self, scale_factor: f32) -> Self {
205 self.scale_from_center2(Vec2::splat(scale_factor))
206 }
207
208 #[must_use]
210 pub fn scale_from_center2(self, scale_factor: Vec2) -> Self {
211 Self::from_center_size(self.center(), self.size() * scale_factor)
212 }
213
214 #[must_use]
216 pub fn shrink(self, amnt: f32) -> Self {
217 self.shrink2(Vec2::splat(amnt))
218 }
219
220 #[must_use]
222 pub fn shrink2(self, amnt: Vec2) -> Self {
223 Self::from_min_max(self.min + amnt, self.max - amnt)
224 }
225
226 #[must_use]
227 #[inline]
228 pub fn translate(self, amnt: Vec2) -> Self {
229 Self::from_min_size(self.min + amnt, self.size())
230 }
231
232 #[must_use]
234 #[inline]
235 pub fn rotate_bb(self, rot: Rot2) -> Self {
236 let a = rot * self.left_top().to_vec2();
237 let b = rot * self.right_top().to_vec2();
238 let c = rot * self.left_bottom().to_vec2();
239 let d = rot * self.right_bottom().to_vec2();
240
241 Self::from_min_max(
242 a.min(b).min(c).min(d).to_pos2(),
243 a.max(b).max(c).max(d).to_pos2(),
244 )
245 }
246
247 #[must_use]
248 #[inline]
249 pub fn intersects(self, other: Self) -> bool {
250 self.min.x <= other.max.x
251 && other.min.x <= self.max.x
252 && self.min.y <= other.max.y
253 && other.min.y <= self.max.y
254 }
255
256 pub fn set_width(&mut self, w: f32) {
258 self.max.x = self.min.x + w;
259 }
260
261 pub fn set_height(&mut self, h: f32) {
263 self.max.y = self.min.y + h;
264 }
265
266 pub fn set_center(&mut self, center: Pos2) {
268 *self = self.translate(center - self.center());
269 }
270
271 #[must_use]
272 #[inline(always)]
273 pub fn contains(&self, p: Pos2) -> bool {
274 self.min.x <= p.x && p.x <= self.max.x && self.min.y <= p.y && p.y <= self.max.y
275 }
276
277 #[must_use]
278 pub fn contains_rect(&self, other: Self) -> bool {
279 self.contains(other.min) && self.contains(other.max)
280 }
281
282 #[must_use]
285 pub fn clamp(&self, p: Pos2) -> Pos2 {
286 p.clamp(self.min, self.max)
287 }
288
289 #[inline(always)]
290 pub fn extend_with(&mut self, p: Pos2) {
291 self.min = self.min.min(p);
292 self.max = self.max.max(p);
293 }
294
295 #[inline(always)]
296 pub fn extend_with_x(&mut self, x: f32) {
298 self.min.x = self.min.x.min(x);
299 self.max.x = self.max.x.max(x);
300 }
301
302 #[inline(always)]
303 pub fn extend_with_y(&mut self, y: f32) {
305 self.min.y = self.min.y.min(y);
306 self.max.y = self.max.y.max(y);
307 }
308
309 #[inline(always)]
312 #[must_use]
313 pub fn union(self, other: Self) -> Self {
314 Self {
315 min: self.min.min(other.min),
316 max: self.max.max(other.max),
317 }
318 }
319
320 #[inline]
322 #[must_use]
323 pub fn intersect(self, other: Self) -> Self {
324 Self {
325 min: self.min.max(other.min),
326 max: self.max.min(other.max),
327 }
328 }
329
330 #[inline(always)]
331 pub fn center(&self) -> Pos2 {
332 Pos2 {
333 x: (self.min.x + self.max.x) / 2.0,
334 y: (self.min.y + self.max.y) / 2.0,
335 }
336 }
337
338 #[inline(always)]
340 pub fn size(&self) -> Vec2 {
341 self.max - self.min
342 }
343
344 #[inline(always)]
345 pub fn width(&self) -> f32 {
346 self.max.x - self.min.x
347 }
348
349 #[inline(always)]
350 pub fn height(&self) -> f32 {
351 self.max.y - self.min.y
352 }
353
354 pub fn aspect_ratio(&self) -> f32 {
360 self.width() / self.height()
361 }
362
363 pub fn square_proportions(&self) -> Vec2 {
367 let w = self.width();
368 let h = self.height();
369 if w > h {
370 vec2(w / h, 1.0)
371 } else {
372 vec2(1.0, h / w)
373 }
374 }
375
376 #[inline(always)]
377 pub fn area(&self) -> f32 {
378 self.width() * self.height()
379 }
380
381 #[inline]
387 pub fn distance_to_pos(&self, pos: Pos2) -> f32 {
388 self.distance_sq_to_pos(pos).sqrt()
389 }
390
391 #[inline]
397 pub fn distance_sq_to_pos(&self, pos: Pos2) -> f32 {
398 if self.is_negative() {
399 return f32::INFINITY;
400 }
401
402 let dx = if self.min.x > pos.x {
403 self.min.x - pos.x
404 } else if pos.x > self.max.x {
405 pos.x - self.max.x
406 } else {
407 0.0
408 };
409
410 let dy = if self.min.y > pos.y {
411 self.min.y - pos.y
412 } else if pos.y > self.max.y {
413 pos.y - self.max.y
414 } else {
415 0.0
416 };
417
418 dx * dx + dy * dy
419 }
420
421 pub fn signed_distance_to_pos(&self, pos: Pos2) -> f32 {
435 if self.is_negative() {
436 return f32::INFINITY;
437 }
438
439 let edge_distances = (pos - self.center()).abs() - self.size() * 0.5;
440 let inside_dist = edge_distances.max_elem().min(0.0);
441 let outside_dist = edge_distances.max(Vec2::ZERO).length();
442 inside_dist + outside_dist
443 }
444
445 #[inline]
448 pub fn lerp_inside(&self, t: Vec2) -> Pos2 {
449 Pos2 {
450 x: lerp(self.min.x..=self.max.x, t.x),
451 y: lerp(self.min.y..=self.max.y, t.y),
452 }
453 }
454
455 #[inline]
457 pub fn lerp_towards(&self, other: &Self, t: f32) -> Self {
458 Self {
459 min: self.min.lerp(other.min, t),
460 max: self.max.lerp(other.max, t),
461 }
462 }
463
464 #[inline(always)]
465 pub fn x_range(&self) -> Rangef {
466 Rangef::new(self.min.x, self.max.x)
467 }
468
469 #[inline(always)]
470 pub fn y_range(&self) -> Rangef {
471 Rangef::new(self.min.y, self.max.y)
472 }
473
474 #[inline(always)]
475 pub fn bottom_up_range(&self) -> Rangef {
476 Rangef::new(self.max.y, self.min.y)
477 }
478
479 #[inline(always)]
481 pub fn is_negative(&self) -> bool {
482 self.max.x < self.min.x || self.max.y < self.min.y
483 }
484
485 #[inline(always)]
487 pub fn is_positive(&self) -> bool {
488 self.min.x < self.max.x && self.min.y < self.max.y
489 }
490
491 #[inline(always)]
493 pub fn is_finite(&self) -> bool {
494 self.min.is_finite() && self.max.is_finite()
495 }
496
497 #[inline(always)]
499 pub fn any_nan(self) -> bool {
500 self.min.any_nan() || self.max.any_nan()
501 }
502}
503
504impl Rect {
506 #[inline(always)]
508 pub fn left(&self) -> f32 {
509 self.min.x
510 }
511
512 #[inline(always)]
514 pub fn left_mut(&mut self) -> &mut f32 {
515 &mut self.min.x
516 }
517
518 #[inline(always)]
520 pub fn set_left(&mut self, x: f32) {
521 self.min.x = x;
522 }
523
524 #[inline(always)]
526 pub fn right(&self) -> f32 {
527 self.max.x
528 }
529
530 #[inline(always)]
532 pub fn right_mut(&mut self) -> &mut f32 {
533 &mut self.max.x
534 }
535
536 #[inline(always)]
538 pub fn set_right(&mut self, x: f32) {
539 self.max.x = x;
540 }
541
542 #[inline(always)]
544 pub fn top(&self) -> f32 {
545 self.min.y
546 }
547
548 #[inline(always)]
550 pub fn top_mut(&mut self) -> &mut f32 {
551 &mut self.min.y
552 }
553
554 #[inline(always)]
556 pub fn set_top(&mut self, y: f32) {
557 self.min.y = y;
558 }
559
560 #[inline(always)]
562 pub fn bottom(&self) -> f32 {
563 self.max.y
564 }
565
566 #[inline(always)]
568 pub fn bottom_mut(&mut self) -> &mut f32 {
569 &mut self.max.y
570 }
571
572 #[inline(always)]
574 pub fn set_bottom(&mut self, y: f32) {
575 self.max.y = y;
576 }
577
578 #[inline(always)]
579 #[doc(alias = "top_left")]
580 pub fn left_top(&self) -> Pos2 {
581 pos2(self.left(), self.top())
582 }
583
584 #[inline(always)]
585 pub fn center_top(&self) -> Pos2 {
586 pos2(self.center().x, self.top())
587 }
588
589 #[inline(always)]
590 #[doc(alias = "top_right")]
591 pub fn right_top(&self) -> Pos2 {
592 pos2(self.right(), self.top())
593 }
594
595 #[inline(always)]
596 pub fn left_center(&self) -> Pos2 {
597 pos2(self.left(), self.center().y)
598 }
599
600 #[inline(always)]
601 pub fn right_center(&self) -> Pos2 {
602 pos2(self.right(), self.center().y)
603 }
604
605 #[inline(always)]
606 #[doc(alias = "bottom_left")]
607 pub fn left_bottom(&self) -> Pos2 {
608 pos2(self.left(), self.bottom())
609 }
610
611 #[inline(always)]
612 pub fn center_bottom(&self) -> Pos2 {
613 pos2(self.center().x, self.bottom())
614 }
615
616 #[inline(always)]
617 #[doc(alias = "bottom_right")]
618 pub fn right_bottom(&self) -> Pos2 {
619 pos2(self.right(), self.bottom())
620 }
621
622 pub fn split_left_right_at_fraction(&self, t: f32) -> (Self, Self) {
624 self.split_left_right_at_x(lerp(self.min.x..=self.max.x, t))
625 }
626
627 pub fn split_left_right_at_x(&self, split_x: f32) -> (Self, Self) {
629 let left = Self::from_min_max(self.min, Pos2::new(split_x, self.max.y));
630 let right = Self::from_min_max(Pos2::new(split_x, self.min.y), self.max);
631 (left, right)
632 }
633
634 pub fn split_top_bottom_at_fraction(&self, t: f32) -> (Self, Self) {
636 self.split_top_bottom_at_y(lerp(self.min.y..=self.max.y, t))
637 }
638
639 pub fn split_top_bottom_at_y(&self, split_y: f32) -> (Self, Self) {
641 let top = Self::from_min_max(self.min, Pos2::new(self.max.x, split_y));
642 let bottom = Self::from_min_max(Pos2::new(self.min.x, split_y), self.max);
643 (top, bottom)
644 }
645}
646
647impl Rect {
648 pub fn intersects_ray(&self, o: Pos2, d: Vec2) -> bool {
652 debug_assert!(
653 d.is_normalized(),
654 "expected normalized direction, but `d` has length {}",
655 d.length()
656 );
657
658 let mut tmin = -f32::INFINITY;
659 let mut tmax = f32::INFINITY;
660
661 if d.x != 0.0 {
662 let tx1 = (self.min.x - o.x) / d.x;
663 let tx2 = (self.max.x - o.x) / d.x;
664
665 tmin = tmin.max(tx1.min(tx2));
666 tmax = tmax.min(tx1.max(tx2));
667 }
668
669 if d.y != 0.0 {
670 let ty1 = (self.min.y - o.y) / d.y;
671 let ty2 = (self.max.y - o.y) / d.y;
672
673 tmin = tmin.max(ty1.min(ty2));
674 tmax = tmax.min(ty1.max(ty2));
675 }
676
677 0.0 <= tmax && tmin <= tmax
678 }
679
680 pub fn intersects_ray_from_center(&self, d: Vec2) -> Pos2 {
684 debug_assert!(
685 d.is_normalized(),
686 "expected normalized direction, but `d` has length {}",
687 d.length()
688 );
689
690 let mut tmin = f32::NEG_INFINITY;
691 let mut tmax = f32::INFINITY;
692
693 for i in 0..2 {
694 let inv_d = 1.0 / -d[i];
695 let mut t0 = (self.min[i] - self.center()[i]) * inv_d;
696 let mut t1 = (self.max[i] - self.center()[i]) * inv_d;
697
698 if inv_d < 0.0 {
699 std::mem::swap(&mut t0, &mut t1);
700 }
701
702 tmin = tmin.max(t0);
703 tmax = tmax.min(t1);
704 }
705
706 let t = tmax.min(tmin);
707 self.center() + t * -d
708 }
709}
710
711impl fmt::Debug for Rect {
712 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
713 write!(f, "[{:?} - {:?}]", self.min, self.max)
714 }
715}
716
717impl fmt::Display for Rect {
718 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
719 f.write_str("[")?;
720 self.min.fmt(f)?;
721 f.write_str(" - ")?;
722 self.max.fmt(f)?;
723 f.write_str("]")?;
724 Ok(())
725 }
726}
727
728impl From<[Pos2; 2]> for Rect {
730 #[inline]
731 fn from([min, max]: [Pos2; 2]) -> Self {
732 Self { min, max }
733 }
734}
735
736impl Mul<f32> for Rect {
737 type Output = Self;
738
739 #[inline]
740 fn mul(self, factor: f32) -> Self {
741 Self {
742 min: self.min * factor,
743 max: self.max * factor,
744 }
745 }
746}
747
748impl Mul<Rect> for f32 {
749 type Output = Rect;
750
751 #[inline]
752 fn mul(self, vec: Rect) -> Rect {
753 Rect {
754 min: self * vec.min,
755 max: self * vec.max,
756 }
757 }
758}
759
760impl Div<f32> for Rect {
761 type Output = Self;
762
763 #[inline]
764 fn div(self, factor: f32) -> Self {
765 Self {
766 min: self.min / factor,
767 max: self.max / factor,
768 }
769 }
770}
771
772#[cfg(test)]
773mod tests {
774 use super::*;
775
776 #[test]
777 fn test_rect() {
778 let r = Rect::from_min_max(pos2(10.0, 10.0), pos2(20.0, 20.0));
779 assert_eq!(r.distance_sq_to_pos(pos2(15.0, 15.0)), 0.0);
780 assert_eq!(r.distance_sq_to_pos(pos2(10.0, 15.0)), 0.0);
781 assert_eq!(r.distance_sq_to_pos(pos2(10.0, 10.0)), 0.0);
782
783 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); }
789
790 #[test]
791 fn scale_rect() {
792 let c = pos2(100.0, 50.0);
793 let r = Rect::from_center_size(c, vec2(30.0, 60.0));
794
795 assert_eq!(
796 r.scale_from_center(2.0),
797 Rect::from_center_size(c, vec2(60.0, 120.0))
798 );
799 assert_eq!(
800 r.scale_from_center(0.5),
801 Rect::from_center_size(c, vec2(15.0, 30.0))
802 );
803 assert_eq!(
804 r.scale_from_center2(vec2(2.0, 3.0)),
805 Rect::from_center_size(c, vec2(60.0, 180.0))
806 );
807 }
808
809 #[test]
810 fn test_ray_intersection() {
811 let rect = Rect::from_min_max(pos2(1.0, 1.0), pos2(3.0, 3.0));
812
813 println!("Righward ray from left:");
814 assert!(rect.intersects_ray(pos2(0.0, 2.0), Vec2::RIGHT));
815
816 println!("Righward ray from center:");
817 assert!(rect.intersects_ray(pos2(2.0, 2.0), Vec2::RIGHT));
818
819 println!("Righward ray from right:");
820 assert!(!rect.intersects_ray(pos2(4.0, 2.0), Vec2::RIGHT));
821
822 println!("Leftward ray from left:");
823 assert!(!rect.intersects_ray(pos2(0.0, 2.0), Vec2::LEFT));
824
825 println!("Leftward ray from center:");
826 assert!(rect.intersects_ray(pos2(2.0, 2.0), Vec2::LEFT));
827
828 println!("Leftward ray from right:");
829 assert!(rect.intersects_ray(pos2(4.0, 2.0), Vec2::LEFT));
830 }
831
832 #[test]
833 fn test_ray_from_center_intersection() {
834 let rect = Rect::from_min_max(pos2(1.0, 1.0), pos2(3.0, 3.0));
835
836 assert_eq!(
837 rect.intersects_ray_from_center(Vec2::RIGHT),
838 pos2(3.0, 2.0),
839 "rightward ray"
840 );
841
842 assert_eq!(
843 rect.intersects_ray_from_center(Vec2::UP),
844 pos2(2.0, 1.0),
845 "upward ray"
846 );
847
848 assert_eq!(
849 rect.intersects_ray_from_center(Vec2::LEFT),
850 pos2(1.0, 2.0),
851 "leftward ray"
852 );
853
854 assert_eq!(
855 rect.intersects_ray_from_center(Vec2::DOWN),
856 pos2(2.0, 3.0),
857 "downward ray"
858 );
859
860 assert_eq!(
861 rect.intersects_ray_from_center((Vec2::LEFT + Vec2::DOWN).normalized()),
862 pos2(1.0, 3.0),
863 "bottom-left corner ray"
864 );
865
866 assert_eq!(
867 rect.intersects_ray_from_center((Vec2::LEFT + Vec2::UP).normalized()),
868 pos2(1.0, 1.0),
869 "top-left corner ray"
870 );
871
872 assert_eq!(
873 rect.intersects_ray_from_center((Vec2::RIGHT + Vec2::DOWN).normalized()),
874 pos2(3.0, 3.0),
875 "bottom-right corner ray"
876 );
877
878 assert_eq!(
879 rect.intersects_ray_from_center((Vec2::RIGHT + Vec2::UP).normalized()),
880 pos2(3.0, 1.0),
881 "top-right corner ray"
882 );
883 }
884}