1use crate::{
2 Circle, Float, Line, Num, Polygonal, Projection, Ray, RayHit, Shape, Signed, Vec2, extract_on,
3 impl_approx, impl_bytemuck, impl_casts, impl_interp, impl_serde, impl_tuple_arr, line,
4 overlaps_on, vec2,
5};
6use std::fmt::{Display, Formatter};
7use std::ops::{Add, AddAssign, Sub, SubAssign};
8
9use super::Quad;
10
11pub type RectF = Rect<f32>;
12pub type RectI = Rect<i32>;
13pub type RectU = Rect<u32>;
14
15#[repr(C)]
21#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
22pub struct Rect<T> {
23 pub x: T,
24 pub y: T,
25 pub w: T,
26 pub h: T,
27}
28
29impl_tuple_arr!(
30 NAME = Rect
31 LEN = 4
32 FIELDS = (x, y, w, h)
33 TUPLE = (T, T, T, T)
34);
35
36impl_approx!(
37 NAME = Rect
38 FIELDS = (x, y, w, h)
39);
40
41impl_serde!(
42 NAME = Rect
43 FIELDS = (x, y, w, h)
44);
45
46impl_bytemuck!(Rect);
47
48impl_casts!(
49 NAME = Rect
50 FIELDS = (x, y, w, h)
51);
52
53impl_interp!(
54 NAME = Rect
55 FIELDS = (x, y, w, h)
56);
57
58#[inline]
60pub const fn rect<T>(x: T, y: T, w: T, h: T) -> Rect<T> {
61 Rect { x, y, w, h }
62}
63
64impl<T> Rect<T> {
65 #[inline]
67 pub const fn new(x: T, y: T, w: T, h: T) -> Self {
68 Self { x, y, w, h }
69 }
70
71 #[inline]
73 pub fn map<U, F: FnMut(T) -> U>(self, mut f: F) -> Rect<U> {
74 rect(f(self.x), f(self.y), f(self.w), f(self.h))
75 }
76}
77
78impl<T: Copy> Rect<T> {
79 #[inline]
81 pub fn size(&self) -> Vec2<T> {
82 vec2(self.w, self.h)
83 }
84
85 #[inline]
87 pub fn left(&self) -> T {
88 self.x
89 }
90
91 #[inline]
93 pub fn top(&self) -> T {
94 self.y
95 }
96
97 #[inline]
99 pub fn top_left(&self) -> Vec2<T> {
100 vec2(self.left(), self.top())
101 }
102}
103
104impl<T: Num> Rect<T> {
105 pub const ZERO: Self = rect(T::ZERO, T::ZERO, T::ZERO, T::ZERO);
107
108 #[inline]
110 pub const fn sized(size: Vec2<T>) -> Self {
111 rect(T::ZERO, T::ZERO, size.x, size.y)
112 }
113
114 #[inline]
116 pub const fn pos_size(pos: Vec2<T>, size: Vec2<T>) -> Self {
117 rect(pos.x, pos.y, size.x, size.y)
118 }
119
120 #[inline]
122 pub fn right(&self) -> T {
123 self.x + self.w
124 }
125
126 #[inline]
128 pub fn bottom(&self) -> T {
129 self.y + self.h
130 }
131
132 #[inline]
134 pub fn top_right(&self) -> Vec2<T> {
135 vec2(self.right(), self.top())
136 }
137
138 #[inline]
140 pub fn bottom_right(&self) -> Vec2<T> {
141 vec2(self.right(), self.bottom())
142 }
143
144 #[inline]
146 pub fn bottom_left(&self) -> Vec2<T> {
147 vec2(self.left(), self.bottom())
148 }
149
150 #[inline]
152 pub fn center_x(&self) -> T {
153 self.x + self.w / T::TWO
154 }
155
156 #[inline]
158 pub fn center_y(&self) -> T {
159 self.y + self.h / T::TWO
160 }
161
162 #[inline]
164 pub fn center(&self) -> Vec2<T> {
165 vec2(self.center_x(), self.center_y())
166 }
167
168 #[inline]
170 pub fn top_center(&self) -> Vec2<T> {
171 vec2(self.center_x(), self.top())
172 }
173
174 #[inline]
176 pub fn bottom_center(&self) -> Vec2<T> {
177 vec2(self.center_x(), self.bottom())
178 }
179
180 #[inline]
182 pub fn right_center(&self) -> Vec2<T> {
183 vec2(self.right(), self.center_y())
184 }
185
186 #[inline]
188 pub fn left_center(&self) -> Vec2<T> {
189 vec2(self.left(), self.center_y())
190 }
191
192 #[inline]
194 pub fn area(&self) -> T {
195 self.w * self.h
196 }
197
198 #[inline]
200 pub fn perimeter(&self) -> T {
201 self.w + self.w + self.h + self.h
202 }
203
204 #[inline]
206 pub fn contains(&self, p: Vec2<T>) -> bool {
207 p.x >= self.x && p.y >= self.y && p.x < self.right() && p.y < self.bottom()
208 }
209
210 #[inline]
212 pub fn translate(&self, amount: &Vec2<T>) -> Self {
213 rect(self.x + amount.x, self.y + amount.y, self.w, self.h)
214 }
215
216 #[inline]
218 pub fn top_edge(&self) -> Line<T> {
219 line(self.top_left(), self.top_right())
220 }
221
222 #[inline]
224 pub fn right_edge(&self) -> Line<T> {
225 line(self.top_right(), self.bottom_right())
226 }
227
228 #[inline]
230 pub fn bottom_edge(&self) -> Line<T> {
231 line(self.bottom_right(), self.bottom_left())
232 }
233
234 #[inline]
236 pub fn left_edge(&self) -> Line<T> {
237 line(self.bottom_left(), self.top_left())
238 }
239
240 #[inline]
242 pub fn corners(&self) -> [Vec2<T>; 4] {
243 let r = self.right();
244 let b = self.bottom();
245 [
246 vec2(self.x, self.y),
247 vec2(r, self.y),
248 vec2(r, b),
249 vec2(self.x, b),
250 ]
251 }
252
253 #[inline]
255 pub fn edges(&self) -> [Line<T>; 4] {
256 let [a, b, c, d] = self.corners();
257 [line(a, b), line(b, c), line(c, d), line(d, a)]
258 }
259
260 #[inline]
262 pub fn inflate(self, amount: impl Into<Vec2<T>>) -> Self {
263 let amount = amount.into();
264 rect(
265 self.x - amount.x,
266 self.y - amount.y,
267 self.w + amount.x + amount.x,
268 self.h + amount.y + amount.y,
269 )
270 }
271
272 #[inline]
274 pub fn min_x(&self) -> T {
275 T::min(self.x, self.right())
276 }
277
278 #[inline]
280 pub fn min_y(&self) -> T {
281 T::min(self.y, self.bottom())
282 }
283
284 #[inline]
286 pub fn max_x(&self) -> T {
287 T::max(self.x, self.right())
288 }
289
290 #[inline]
292 pub fn max_y(&self) -> T {
293 T::max(self.y, self.bottom())
294 }
295
296 #[inline]
298 pub fn min_pos(&self) -> Vec2<T> {
299 vec2(self.min_x(), self.min_y())
300 }
301
302 #[inline]
304 pub fn max_pos(&self) -> Vec2<T> {
305 vec2(self.max_x(), self.max_y())
306 }
307
308 #[inline]
310 pub fn contains_rect(&self, r: &Self) -> bool {
311 r.x >= self.x && r.y >= self.y && r.right() <= self.right() && r.bottom() <= self.bottom()
312 }
313
314 #[inline]
316 pub fn overlaps(&self, r: &Self) -> bool {
317 self.x < r.right() && self.y < r.bottom() && self.right() > r.x && self.bottom() > r.y
318 }
319
320 #[inline]
323 pub fn overlap(&self, r: &Self) -> Option<Self> {
324 let min = self.top_left().max(r.top_left());
325 let max = self.bottom_right().min(r.bottom_right());
326 if max.x > min.x && max.y > min.y {
327 Some(rect(min.x, min.y, max.x - min.x, max.y - min.y))
328 } else {
329 None
330 }
331 }
332
333 #[inline]
337 pub fn conflate(&self, r: &Self) -> Self {
338 let min = self.min_pos().min(r.min_pos());
339 let max = self.max_pos().max(r.max_pos());
340 rect(min.x, min.y, max.x - min.x, max.y - min.y)
341 }
342
343 pub fn clamp_inside(&self, outer: &Self) -> Self {
347 let mut rect = *self;
348 if rect.right() > outer.right() {
349 rect.x -= rect.right() - outer.right();
350 }
351 if rect.bottom() > outer.bottom() {
352 rect.y -= rect.bottom() - outer.bottom();
353 }
354 if rect.x < outer.x {
355 rect.w -= outer.x - rect.x;
356 rect.x = outer.x;
357 }
358 if rect.y < outer.y {
359 rect.h -= outer.y - rect.y;
360 rect.y = outer.y;
361 }
362 rect
363 }
364}
365
366impl<T: Signed> Rect<T> {
367 #[inline]
369 pub fn is_positive(&self) -> bool {
370 self.w >= T::ZERO && self.h >= T::ZERO
371 }
372
373 #[inline]
376 pub fn non_neg(mut self) -> Self {
377 if self.w < T::ZERO {
378 self.x += self.w;
379 self.w = -self.w;
380 }
381 if self.h < T::ZERO {
382 self.y += self.h;
383 self.h = -self.h;
384 }
385 self
386 }
387}
388
389impl<T: Float> Rect<T> {
390 #[inline]
392 pub fn transform_by(&self, f: impl FnMut(Vec2<T>) -> Vec2<T>) -> Quad<T> {
393 Quad(self.corners().map(f))
394 }
395
396 #[inline]
398 pub fn transform_by_retain(&self, mut f: impl FnMut(Vec2<T>) -> Vec2<T>) -> Rect<T> {
399 self + f(Vec2::ZERO)
403 }
404}
405
406impl<T: Display> Display for Rect<T> {
407 #[inline]
408 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
409 self.x.fmt(f)?;
410 f.write_str(", ")?;
411 self.y.fmt(f)?;
412 f.write_str(", ")?;
413 self.w.fmt(f)?;
414 f.write_str(", ")?;
415 self.h.fmt(f)
416 }
417}
418
419impl<T: Float> Shape<T> for Rect<T> {
420 #[inline]
421 fn centroid(&self) -> Vec2<T> {
422 self.center()
423 }
424
425 #[inline]
426 fn contains(&self, p: Vec2<T>) -> bool {
427 p.x >= self.x && p.y >= self.y && p.x < self.right() && p.y < self.bottom()
428 }
429
430 #[inline]
431 fn bounds(&self) -> Rect<T> {
432 *self
433 }
434
435 #[inline]
436 fn project_onto_axis(&self, axis: Vec2<T>) -> Projection<T> {
437 let dot1 = self.top_left().dot(axis);
438 let dot2 = self.top_right().dot(axis);
439 let dot3 = self.bottom_right().dot(axis);
440 let dot4 = self.bottom_left().dot(axis);
441 let min = T::min(dot1, T::min(dot2, T::min(dot3, dot4)));
442 let max = T::max(dot1, T::max(dot2, T::max(dot3, dot4)));
443 Projection { min, max }
444 }
445
446 #[inline]
447 fn project_point(&self, p: Vec2<T>) -> Vec2<T> {
448 let projections = [
449 self.top_edge().project_point(p),
450 self.right_edge().project_point(p),
451 self.bottom_edge().project_point(p),
452 self.left_edge().project_point(p),
453 ];
454 let (i, _) = projections
456 .iter()
457 .enumerate()
458 .map(|(i, proj)| (i, proj.sqr_dist(p)))
459 .min_by(|(_, a), (_, b)| a.partial_cmp(b).unwrap())
460 .unwrap();
461 projections[i]
462 }
463
464 #[inline]
465 fn rayhit(&self, ray: &Ray<T>) -> bool {
466 self.edges().iter().any(|edge| edge.raycast(ray).is_some())
467 }
468
469 fn raycast(&self, ray: &Ray<T>) -> Option<RayHit<T>> {
470 let edges = self.edges();
472 let hit_dists = [
473 edges[0].raycast(ray).map(|d| (0, d)),
474 edges[1].raycast(ray).map(|d| (1, d)),
475 edges[2].raycast(ray).map(|d| (2, d)),
476 edges[3].raycast(ray).map(|d| (3, d)),
477 ];
478
479 let crossings = hit_dists.iter().flatten().count();
481 if crossings > 0 && (crossings % 2) == 0 {
482 hit_dists
483 .iter()
484 .flatten()
485 .min_by(|(_, a), (_, b)| a.partial_cmp(b).unwrap())
486 .map(|&(i, d)| RayHit::new(edges[i].norm().turn_left(), d))
487 } else {
488 None
489 }
490 }
491
492 #[inline]
493 fn overlaps_rect(&self, rect: &Rect<T>) -> bool {
494 self.x < rect.right()
495 && self.y < rect.bottom()
496 && self.right() > rect.x
497 && self.bottom() > rect.y
498 }
499
500 #[inline]
501 fn overlaps_circ(&self, circ: &Circle<T>) -> bool {
502 circ.overlaps_poly(self)
503 }
504
505 #[inline]
506 fn overlaps_poly<P: Polygonal<T>>(&self, poly: &P) -> bool {
507 self.all_normals(|axis| overlaps_on(self, poly, axis))
508 && poly.all_normals(|axis| overlaps_on(self, poly, axis))
509 }
510
511 #[inline]
512 fn extract_from_circ(&self, circ: &Circle<T>) -> Option<Vec2<T>> {
513 circ.extract_from_poly(self).map(|p| -p)
514 }
515
516 #[inline]
517 fn extract_from_poly<P: Polygonal<T>>(&self, poly: &P) -> Option<Vec2<T>> {
518 let mut dist = T::MAX;
519 let mut dir = Vec2::ZERO;
520 (self.all_normals(|axis| extract_on(self, poly, axis, &mut dist, &mut dir))
521 && poly.all_normals(|axis| extract_on(self, poly, axis, &mut dist, &mut dir)))
522 .then(|| dir * dist)
523 }
524
525 #[inline]
526 fn is_convex(&self) -> bool {
527 self.w > T::ZERO && self.h > T::ZERO
528 }
529}
530
531impl<T: Float> Polygonal<T> for Rect<T> {
532 #[inline]
533 fn nearest_vertex(&self, source: Vec2<T>) -> Vec2<T> {
534 self.corners().nearest_vertex(source)
535 }
536
537 #[inline]
538 fn all_edges<F: FnMut(Line<T>) -> bool>(&self, mut cond: F) -> bool {
539 cond(self.right_edge())
540 && cond(self.bottom_edge())
541 && cond(self.left_edge())
542 && cond(self.top_edge())
543 }
544
545 #[inline]
546 fn all_normals<F: FnMut(Vec2<T>) -> bool>(&self, mut cond: F) -> bool {
547 cond(Vec2::RIGHT) && cond(Vec2::DOWN) && cond(Vec2::LEFT) && cond(Vec2::UP)
548 }
549
550 #[inline]
551 fn visit_normals<F: FnMut(Vec2<T>)>(&self, mut plot: F) {
552 plot(Vec2::RIGHT);
553 plot(Vec2::DOWN);
554 plot(Vec2::LEFT);
555 plot(Vec2::UP);
556 }
557}
558
559impl<T: Float> Rect<T> {
560 pub fn fitted(&self, size: Vec2<T>, fractional: bool) -> (Self, T) {
561 let scale = self.size() / size;
562 let mut scale = T::min(scale.x, scale.y);
563 if !fractional && scale > T::ONE {
564 scale = T::floor(scale);
565 }
566 let new_size = size * scale;
567 let pos = self.top_left() + ((self.size() - new_size) * T::HALF).floor();
568 let rect = Rect::pos_size(pos, new_size);
569 (rect, scale)
570 }
571
572 pub fn map_pos(&self, pos: Vec2<T>, target: &Rect<T>) -> Vec2<T> {
573 target.min_pos() + target.size() * ((pos - self.min_pos()) / self.size().abs())
574 }
575}
576
577impl<T: Add<T, Output = T>> Add<Vec2<T>> for Rect<T> {
580 type Output = Rect<T>;
581
582 #[inline]
583 fn add(self, rhs: Vec2<T>) -> Self::Output {
584 rect(self.x + rhs.x, self.y + rhs.y, self.w, self.h)
585 }
586}
587
588impl<T: Copy + Add<T, Output = T>> Add<Vec2<T>> for &Rect<T> {
589 type Output = Rect<T>;
590
591 #[inline]
592 fn add(self, rhs: Vec2<T>) -> Self::Output {
593 rect(self.x + rhs.x, self.y + rhs.y, self.w, self.h)
594 }
595}
596
597impl<T: Copy + Add<T, Output = T>> Add<&Vec2<T>> for Rect<T> {
598 type Output = Rect<T>;
599
600 #[inline]
601 fn add(self, rhs: &Vec2<T>) -> Self::Output {
602 rect(self.x + rhs.x, self.y + rhs.y, self.w, self.h)
603 }
604}
605
606impl<T: Copy + Add<T, Output = T>> Add<&Vec2<T>> for &Rect<T> {
607 type Output = Rect<T>;
608
609 #[inline]
610 fn add(self, rhs: &Vec2<T>) -> Self::Output {
611 rect(self.x + rhs.x, self.y + rhs.y, self.w, self.h)
612 }
613}
614
615impl<T: AddAssign<T>> AddAssign<Vec2<T>> for Rect<T> {
618 #[inline]
619 fn add_assign(&mut self, rhs: Vec2<T>) {
620 self.x += rhs.x;
621 self.y += rhs.y;
622 }
623}
624
625impl<T: Copy + AddAssign<T>> AddAssign<&Vec2<T>> for Rect<T> {
626 #[inline]
627 fn add_assign(&mut self, rhs: &Vec2<T>) {
628 self.x += rhs.x;
629 self.y += rhs.y;
630 }
631}
632
633impl<T: Sub<T, Output = T>> Sub<Vec2<T>> for Rect<T> {
636 type Output = Rect<T>;
637
638 #[inline]
639 fn sub(self, rhs: Vec2<T>) -> Self::Output {
640 rect(self.x - rhs.x, self.y - rhs.y, self.w, self.h)
641 }
642}
643
644impl<T: Copy + Sub<T, Output = T>> Sub<Vec2<T>> for &Rect<T> {
645 type Output = Rect<T>;
646
647 #[inline]
648 fn sub(self, rhs: Vec2<T>) -> Self::Output {
649 rect(self.x - rhs.x, self.y - rhs.y, self.w, self.h)
650 }
651}
652
653impl<T: Copy + Sub<T, Output = T>> Sub<&Vec2<T>> for Rect<T> {
654 type Output = Rect<T>;
655
656 #[inline]
657 fn sub(self, rhs: &Vec2<T>) -> Self::Output {
658 rect(self.x - rhs.x, self.y - rhs.y, self.w, self.h)
659 }
660}
661
662impl<T: Copy + Sub<T, Output = T>> Sub<&Vec2<T>> for &Rect<T> {
663 type Output = Rect<T>;
664
665 #[inline]
666 fn sub(self, rhs: &Vec2<T>) -> Self::Output {
667 rect(self.x - rhs.x, self.y - rhs.y, self.w, self.h)
668 }
669}
670
671impl<T: SubAssign<T>> SubAssign<Vec2<T>> for Rect<T> {
674 #[inline]
675 fn sub_assign(&mut self, rhs: Vec2<T>) {
676 self.x -= rhs.x;
677 self.y -= rhs.y;
678 }
679}
680
681impl<T: Copy + SubAssign<T>> SubAssign<&Vec2<T>> for Rect<T> {
682 #[inline]
683 fn sub_assign(&mut self, rhs: &Vec2<T>) {
684 self.x -= rhs.x;
685 self.y -= rhs.y;
686 }
687}
688
689macro_rules! impl_ops {
692 ($op:ident $op_fn:ident $assign:ident $assign_fn:ident) => {
693 impl<T: Num> std::ops::$op<T> for Rect<T> {
694 type Output = Rect<T>;
695
696 #[inline]
697 fn $op_fn(self, rhs: T) -> Self::Output {
698 rect(
699 self.x.$op_fn(rhs),
700 self.y.$op_fn(rhs),
701 self.w.$op_fn(rhs),
702 self.h.$op_fn(rhs),
703 )
704 }
705 }
706
707 impl<T: Num> std::ops::$op<T> for &Rect<T> {
708 type Output = Rect<T>;
709
710 #[inline]
711 fn $op_fn(self, rhs: T) -> Self::Output {
712 rect(
713 self.x.$op_fn(rhs),
714 self.y.$op_fn(rhs),
715 self.w.$op_fn(rhs),
716 self.h.$op_fn(rhs),
717 )
718 }
719 }
720
721 impl<T: Num> std::ops::$op<Vec2<T>> for Rect<T> {
722 type Output = Rect<T>;
723
724 #[inline]
725 fn $op_fn(self, rhs: Vec2<T>) -> Self::Output {
726 rect(
727 self.x.$op_fn(rhs.x),
728 self.y.$op_fn(rhs.x),
729 self.w.$op_fn(rhs.y),
730 self.h.$op_fn(rhs.y),
731 )
732 }
733 }
734
735 impl<T: Num> std::ops::$op<Vec2<T>> for &Rect<T> {
736 type Output = Rect<T>;
737
738 #[inline]
739 fn $op_fn(self, rhs: Vec2<T>) -> Self::Output {
740 rect(
741 self.x.$op_fn(rhs.x),
742 self.y.$op_fn(rhs.x),
743 self.w.$op_fn(rhs.y),
744 self.h.$op_fn(rhs.y),
745 )
746 }
747 }
748
749 impl<T: Num> std::ops::$assign<T> for Rect<T> {
750 #[inline]
751 fn $assign_fn(&mut self, rhs: T) {
752 self.x.$assign_fn(rhs);
753 self.y.$assign_fn(rhs);
754 self.w.$assign_fn(rhs);
755 self.h.$assign_fn(rhs);
756 }
757 }
758 };
759}
760
761impl_ops!(Mul mul MulAssign mul_assign);
762impl_ops!(Div div DivAssign div_assign);
763impl_ops!(Rem rem RemAssign rem_assign);