geometry/
rect.rs

1//! Axis-aligned rectangles.
2
3use serde::{Deserialize, Serialize};
4
5use crate::bbox::Bbox;
6use crate::contains::{Containment, Contains};
7use crate::corner::Corner;
8use crate::dims::Dims;
9use crate::dir::Dir;
10use crate::edge::Edge;
11use crate::intersect::Intersect;
12use crate::point::Point;
13use crate::side::{Side, Sides};
14use crate::span::Span;
15use crate::transform::{
16    Transform, TransformMut, TransformRef, Transformation, Translate, TranslateMut, TranslateRef,
17};
18use crate::union::BoundingUnion;
19
20/// An axis-aligned rectangle, specified by lower-left and upper-right corners.
21#[derive(
22    Debug, Default, Copy, Clone, Hash, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord,
23)]
24pub struct Rect {
25    /// The lower-left corner.
26    p0: Point,
27    /// The upper-right corner.
28    p1: Point,
29}
30
31impl Rect {
32    /// Creates a rectangle with corners `(0, 0), (dims.w(), dims.h())`.
33    ///
34    /// # Example
35    ///
36    /// ```
37    /// # use geometry::prelude::*;
38    /// let dims = Dims::new(100, 200);
39    /// let rect = Rect::from_dims(dims);
40    /// assert_eq!(rect.top(), 200);
41    /// assert_eq!(rect.bot(), 0);
42    /// assert_eq!(rect.left(), 0);
43    /// assert_eq!(rect.right(), 100);
44    /// ```
45    pub fn from_dims(dims: Dims) -> Self {
46        Self::new(Point::zero(), Point::new(dims.w(), dims.h()))
47    }
48
49    /// Returns the center point of the rectangle.
50    ///
51    /// Note that the center point will be rounded to integer coordinates.
52    /// The current behavior is to round down, but this is subject to change;
53    /// users should not rely on this behavior.
54    ///
55    /// # Examples
56    ///
57    /// ```
58    /// # use geometry::prelude::*;
59    /// let rect = Rect::from_sides(0, 0, 200, 100);
60    /// assert_eq!(rect.center(), Point::new(100, 50));
61    /// ```
62    ///
63    /// Center points are rounded:
64    /// ```
65    /// # use geometry::prelude::*;
66    /// let rect = Rect::from_sides(0, 0, 55, 45);
67    /// assert_eq!(rect.center(), Point::new(27, 22));
68    /// ```
69    pub const fn center(&self) -> Point {
70        Point::new((self.p0.x + self.p1.x) / 2, (self.p0.y + self.p1.y) / 2)
71    }
72
73    /// Creates a zero-area rectangle containing the given point.
74    ///
75    /// # Example
76    ///
77    /// ```
78    /// # use geometry::prelude::*;
79    /// let rect = Rect::from_point(Point::new(25, 60));
80    /// assert_eq!(rect.top(), 60);
81    /// assert_eq!(rect.bot(), 60);
82    /// assert_eq!(rect.left(), 25);
83    /// assert_eq!(rect.right(), 25);
84    /// ```
85    #[inline]
86    pub const fn from_point(p: Point) -> Self {
87        Self { p0: p, p1: p }
88    }
89
90    /// Creates a rectangle from all 4 sides (left, bottom, right, top).
91    ///
92    /// # Example
93    ///
94    /// ```
95    /// # use geometry::prelude::*;
96    /// let rect = Rect::from_sides(15, 20, 30, 40);
97    /// assert_eq!(rect.left(), 15);
98    /// assert_eq!(rect.bot(), 20);
99    /// assert_eq!(rect.right(), 30);
100    /// assert_eq!(rect.top(), 40);
101    /// ```
102    ///
103    /// # Panics
104    ///
105    /// This method panics if `left > right` or if `bot > top`.
106    ///
107    /// If you want sides to be sorted for you, consider using [`Rect::new`] instead.
108    #[inline]
109    pub fn from_sides(left: i64, bot: i64, right: i64, top: i64) -> Self {
110        assert!(
111            left <= right,
112            "Rect::from_sides requires that left ({}) <= right ({})",
113            left,
114            right
115        );
116        assert!(
117            bot <= top,
118            "Rect::from_sides requires that bot ({}) <= top ({})",
119            bot,
120            top
121        );
122        Self::new(Point::new(left, bot), Point::new(right, top))
123    }
124
125    /// Creates a rectangle from all 4 sides (left, bottom, right, top), without checking
126    /// that `left <= right` and `bot <= top`.
127    ///
128    /// # Safety
129    ///
130    /// The caller must ensure that `left <= right` and that `bot <= top`.
131    #[inline]
132    pub const unsafe fn from_sides_unchecked(left: i64, bot: i64, right: i64, top: i64) -> Self {
133        unsafe { Self::new_unchecked(Point::new(left, bot), Point::new(right, top)) }
134    }
135
136    /// Creates a rectangle from a lower left and upper right corner point,
137    /// but returns `None` if the given sides would make the rectangle empty.
138    ///
139    /// The rectangle is empty if the left edge is beyond the right edge,
140    /// or if the bottom edge is above the top edge.
141    ///
142    /// # Example
143    ///
144    /// ```
145    /// # use geometry::prelude::*;
146    /// let rect = Rect::from_corners_option(Point::new(15, 20), Point::new(30, 40));
147    /// assert_eq!(rect, Some(Rect::from_sides(15, 20, 30, 40)));
148    ///
149    /// let rect = Rect::from_corners_option(Point::new(10, 20), Point::new(0, 40));
150    /// assert_eq!(rect, None);
151    /// ```
152    #[inline]
153    pub fn from_corners_option(ll: Point, ur: Point) -> Option<Self> {
154        if ll.x > ur.x || ll.y > ur.y {
155            None
156        } else {
157            Some(unsafe { Self::new_unchecked(ll, ur) })
158        }
159    }
160
161    /// Creates a rectangle from all 4 sides (left, bottom, right, top),
162    /// but returns `None` if the given sides would make the rectangle empty.
163    ///
164    /// The rectangle is empty if the left edge is beyond the right edge,
165    /// or if the bottom edge is above the top edge.
166    ///
167    /// # Example
168    ///
169    /// ```
170    /// # use geometry::prelude::*;
171    /// let rect = Rect::from_sides_option(15, 20, 30, 40);
172    /// assert_eq!(rect, Some(Rect::from_sides(15, 20, 30, 40)));
173    ///
174    /// let rect = Rect::from_sides_option(10, 20, 0, 40);
175    /// assert_eq!(rect, None);
176    /// ```
177    #[inline]
178    pub fn from_sides_option(left: i64, bot: i64, right: i64, top: i64) -> Option<Self> {
179        if left > right || bot > top {
180            None
181        } else {
182            Some(Self::from_sides(left, bot, right, top))
183        }
184    }
185
186    /// Creates a zero-area empty rectangle containing the given `(x, y)` coordinates.
187    ///
188    /// # Example
189    ///
190    /// ```
191    /// # use geometry::prelude::*;
192    /// let rect = Rect::from_xy(25, 60);
193    /// assert_eq!(rect.top(), 60);
194    /// assert_eq!(rect.bot(), 60);
195    /// assert_eq!(rect.left(), 25);
196    /// assert_eq!(rect.right(), 25);
197    /// ```
198    pub const fn from_xy(x: i64, y: i64) -> Self {
199        let p = Point::new(x, y);
200        Self::from_point(p)
201    }
202
203    /// Creates a new rectangle from the given opposite corner points.
204    ///
205    /// # Examples
206    ///
207    /// Create a rectangle from the lower left and upper right corners:
208    ///
209    /// ```
210    /// # use geometry::prelude::*;
211    /// let rect = Rect::new(Point::new(15, 20), Point::new(30, 40));
212    /// assert_eq!(rect.left(), 15);
213    /// assert_eq!(rect.bot(), 20);
214    /// assert_eq!(rect.right(), 30);
215    /// assert_eq!(rect.top(), 40);
216    /// ```
217    ///
218    /// Create a rectangle from the lower right and upper left corners:
219    ///
220    /// ```
221    /// # use geometry::prelude::*;
222    /// let rect = Rect::new(Point::new(30, 20), Point::new(15, 40));
223    /// assert_eq!(rect.left(), 15);
224    /// assert_eq!(rect.bot(), 20);
225    /// assert_eq!(rect.right(), 30);
226    /// assert_eq!(rect.top(), 40);
227    /// ```
228    #[inline]
229    pub fn new(lower_left: Point, upper_right: Point) -> Self {
230        let p0 = lower_left;
231        let p1 = upper_right;
232        Self {
233            p0: Point::new(p0.x.min(p1.x), p0.y.min(p1.y)),
234            p1: Point::new(p0.x.max(p1.x), p0.y.max(p1.y)),
235        }
236    }
237
238    /// Creates a new rectangle from a lower-left corner and an upper-right corner,
239    /// without checking that coordinates are ordered correctly.
240    ///
241    /// # Safety
242    ///
243    /// The caller must ensure that `p0` is the lower-left corner and that
244    /// `p1` is the upper-right corner. In other words, you must ensure that
245    /// `p0.x <= p1.x` and `p0.y <= p1.y`.
246    ///
247    #[inline]
248    pub const unsafe fn new_unchecked(p0: Point, p1: Point) -> Self {
249        Self { p0, p1 }
250    }
251
252    /// Creates a rectangle from horizontal and vertical [`Span`]s.
253    ///
254    /// # Example
255    ///
256    /// ```
257    /// # use geometry::prelude::*;
258    /// let hspan = Span::new(15, 30);
259    /// let vspan = Span::new(20, 40);
260    /// let rect = Rect::from_spans(hspan, vspan);
261    /// assert_eq!(rect.left(), 15);
262    /// assert_eq!(rect.bot(), 20);
263    /// assert_eq!(rect.right(), 30);
264    /// assert_eq!(rect.top(), 40);
265    /// ```
266    pub const fn from_spans(h: Span, v: Span) -> Self {
267        Self {
268            p0: Point::new(h.start(), v.start()),
269            p1: Point::new(h.stop(), v.stop()),
270        }
271    }
272
273    /// Returns the bottom y-coordinate of the rectangle.
274    ///
275    /// # Example
276    ///
277    /// ```
278    /// # use geometry::prelude::*;
279    /// let rect = Rect::from_sides(10, 20, 30, 40);
280    /// assert_eq!(rect.bot(), 20);
281    /// ```
282    #[inline]
283    pub const fn bot(&self) -> i64 {
284        self.p0.y
285    }
286
287    /// Returns the top y-coordinate of the rectangle.
288    ///
289    /// # Example
290    ///
291    /// ```
292    /// # use geometry::prelude::*;
293    /// let rect = Rect::from_sides(10, 20, 30, 40);
294    /// assert_eq!(rect.top(), 40);
295    /// ```
296    #[inline]
297    pub const fn top(&self) -> i64 {
298        self.p1.y
299    }
300
301    /// Returns the left x-coordinate of the rectangle.
302    ///
303    /// # Example
304    ///
305    /// ```
306    /// # use geometry::prelude::*;
307    /// let rect = Rect::from_sides(10, 20, 30, 40);
308    /// assert_eq!(rect.left(), 10);
309    /// ```
310    #[inline]
311    pub const fn left(&self) -> i64 {
312        self.p0.x
313    }
314
315    /// Returns the right x-coordinate of the rectangle.
316    ///
317    /// # Example
318    ///
319    /// ```
320    /// # use geometry::prelude::*;
321    /// let rect = Rect::from_sides(10, 20, 30, 40);
322    /// assert_eq!(rect.right(), 30);
323    /// ```
324    #[inline]
325    pub const fn right(&self) -> i64 {
326        self.p1.x
327    }
328
329    /// Returns the horizontal [`Span`] of the rectangle.
330    ///
331    /// # Example
332    ///
333    /// ```
334    /// # use geometry::prelude::*;
335    /// let rect = Rect::from_sides(10, 20, 30, 40);
336    /// assert_eq!(rect.hspan(), Span::new(10, 30));
337    /// ```
338    pub const fn hspan(&self) -> Span {
339        unsafe {
340            // SAFETY: A valid Rect has p0.x <= p1.x
341            Span::new_unchecked(self.p0.x, self.p1.x)
342        }
343    }
344
345    /// Returns the vertical span of the rectangle.
346    ///
347    /// # Example
348    ///
349    /// ```
350    /// # use geometry::prelude::*;
351    /// let rect = Rect::from_sides(10, 20, 30, 40);
352    /// assert_eq!(rect.vspan(), Span::new(20, 40));
353    /// ```
354    pub const fn vspan(&self) -> Span {
355        unsafe {
356            // SAFETY: A valid Rect has p0.y <= p1.y
357            Span::new_unchecked(self.p0.y, self.p1.y)
358        }
359    }
360
361    /// Returns a new [`Rect`] with the given `hspan` and the same vertical span.
362    ///
363    /// # Example
364    ///
365    /// ```
366    /// # use geometry::prelude::*;
367    /// let rect = Rect::from_sides(10, 20, 30, 40);
368    /// let new_hspan = Span::new(100, 200);
369    /// let new_rect = rect.with_hspan(new_hspan);
370    /// assert_eq!(new_rect, Rect::from_sides(100, 20, 200, 40));
371    /// ```
372    pub fn with_hspan(self, hspan: Span) -> Self {
373        Rect::new(
374            Point::new(hspan.start(), self.p0.y),
375            Point::new(hspan.stop(), self.p1.y),
376        )
377    }
378
379    /// Returns a [`Rect`] with the given `vspan` and the same horizontal span.
380    ///
381    /// # Example
382    ///
383    /// ```
384    /// # use geometry::prelude::*;
385    /// let rect = Rect::from_sides(10, 20, 30, 40);
386    /// let new_vspan = Span::new(100, 200);
387    /// let new_rect = rect.with_vspan(new_vspan);
388    /// assert_eq!(new_rect, Rect::from_sides(10, 100, 30, 200));
389    /// ```
390    pub fn with_vspan(self, vspan: Span) -> Self {
391        Rect::new(
392            Point::new(self.p0.x, vspan.start()),
393            Point::new(self.p1.x, vspan.stop()),
394        )
395    }
396
397    /// Returns a [`Rect`] with the given `span` in the given `dir`, and the current span in the
398    /// other direction.
399    ///
400    /// # Example
401    ///
402    /// ```
403    /// # use geometry::prelude::*;
404    /// let rect = Rect::from_sides(10, 20, 30, 40);
405    /// let new_vspan = Span::new(100, 200);
406    /// let new_rect = rect.with_span(new_vspan, Dir::Vert);
407    /// assert_eq!(new_rect, Rect::from_sides(10, 100, 30, 200));
408    /// ```
409    pub fn with_span(self, span: Span, dir: Dir) -> Self {
410        match dir {
411            Dir::Vert => self.with_vspan(span),
412            Dir::Horiz => self.with_hspan(span),
413        }
414    }
415
416    /// Returns the horizontal width of the rectangle.
417    ///
418    /// # Example
419    ///
420    /// ```
421    /// # use geometry::prelude::*;
422    /// let rect = Rect::from_sides(10, 20, 30, 50);
423    /// assert_eq!(rect.width(), 20);
424    /// ```
425    #[inline]
426    pub const fn width(&self) -> i64 {
427        self.hspan().length()
428    }
429
430    /// Returns the vertical height of the rectangle.
431    ///
432    /// # Example
433    ///
434    /// ```
435    /// # use geometry::prelude::*;
436    /// let rect = Rect::from_sides(10, 20, 30, 50);
437    /// assert_eq!(rect.height(), 30);
438    /// ```
439    #[inline]
440    pub const fn height(&self) -> i64 {
441        self.vspan().length()
442    }
443
444    /// Returns the area of the rectangle.
445    ///
446    /// # Example
447    ///
448    /// ```
449    /// # use geometry::prelude::*;
450    /// let rect = Rect::from_sides(10, 20, 30, 50);
451    /// assert_eq!(rect.area(), 600);
452    /// ```
453    #[inline]
454    pub const fn area(&self) -> i64 {
455        self.width() * self.height()
456    }
457
458    /// Returns the lowest/leftmost coordinate of the rectangle in the given direction.
459    ///
460    /// For [`Dir::Horiz`], this is the left edge's x-coordinate.
461    /// For [`Dir::Vert`], this is the bottom edge's y-coordinate.
462    ///
463    /// # Example
464    ///
465    /// ```
466    /// # use geometry::prelude::*;
467    /// let rect = Rect::from_sides(10, 20, 30, 50);
468    /// assert_eq!(rect.lower_coord(Dir::Vert), 20);
469    /// assert_eq!(rect.lower_coord(Dir::Horiz), 10);
470    /// ```
471    pub const fn lower_coord(&self, dir: Dir) -> i64 {
472        self.span(dir).start()
473    }
474
475    /// Returns the highest/rightmost coordinate of the rectangle in the given direction.
476    ///
477    /// For [`Dir::Horiz`], this is the right edge's x-coordinate.
478    /// For [`Dir::Vert`], this is the top edge's y-coordinate.
479    ///
480    /// # Example
481    ///
482    /// ```
483    /// # use geometry::prelude::*;
484    /// let rect = Rect::from_sides(10, 20, 30, 50);
485    /// assert_eq!(rect.upper_coord(Dir::Vert), 50);
486    /// assert_eq!(rect.upper_coord(Dir::Horiz), 30);
487    /// ```
488    #[inline]
489    pub const fn upper_coord(&self, dir: Dir) -> i64 {
490        self.span(dir).stop()
491    }
492
493    /// Returns the span of the rectangle in the given direction.
494    ///
495    /// # Example
496    ///
497    /// ```
498    /// # use geometry::prelude::*;
499    /// let rect = Rect::from_sides(10, 20, 30, 50);
500    /// assert_eq!(rect.span(Dir::Vert), Span::new(20, 50));
501    /// assert_eq!(rect.span(Dir::Horiz), Span::new(10, 30));
502    /// ```
503    pub const fn span(&self, dir: Dir) -> Span {
504        match dir {
505            Dir::Horiz => self.hspan(),
506            Dir::Vert => self.vspan(),
507        }
508    }
509
510    /// Returns the edges of two rectangles along the given `dir` in increasing order.
511    ///
512    /// For [`Dir::Horiz`], returns the sorted x-coordinates of all **vertical** edges.
513    /// For [`Dir::Vert`], returns the sorted y-coordinates of all **horizontal** edges.
514    fn sorted_coords(&self, other: Self, dir: Dir) -> [i64; 4] {
515        let mut edges = [
516            self.lower_coord(dir),
517            self.upper_coord(dir),
518            other.lower_coord(dir),
519            other.upper_coord(dir),
520        ];
521        edges.sort();
522        edges
523    }
524
525    /// Returns the span between the inner two edges of two rectangles along the given direction.
526    ///
527    /// # Example
528    ///
529    /// ```
530    /// # use geometry::prelude::*;
531    /// let r1 = Rect::from_sides(10, 25, 30, 50);
532    /// let r2 = Rect::from_sides(20, 15, 70, 35);
533    /// assert_eq!(r1.inner_span(r2, Dir::Horiz), Span::new(20, 30));
534    /// assert_eq!(r1.inner_span(r2, Dir::Vert), Span::new(25, 35));
535    /// ```
536    ///
537    /// The "order" of `r1` and `r2` does not matter:
538    ///
539    /// ```
540    /// # use geometry::prelude::*;
541    /// let r1 = Rect::from_sides(10, 25, 30, 50);
542    /// let r2 = Rect::from_sides(20, 15, 70, 35);
543    /// assert_eq!(r2.inner_span(r1, Dir::Horiz), Span::new(20, 30));
544    /// assert_eq!(r2.inner_span(r1, Dir::Vert), Span::new(25, 35));
545    /// ```
546    #[inline]
547    pub fn inner_span(&self, other: Self, dir: Dir) -> Span {
548        let edges = self.sorted_coords(other, dir);
549        unsafe {
550            // SAFETY: sorted_coords returns edges in sorted order,
551            // so edges[1] <= edges[2].
552            Span::new_unchecked(edges[1], edges[2])
553        }
554    }
555
556    /// Returns the span between the outer two edges of two rectangles along the given direction.
557    ///
558    /// # Example
559    ///
560    /// ```
561    /// # use geometry::prelude::*;
562    /// let r1 = Rect::from_sides(10, 25, 30, 50);
563    /// let r2 = Rect::from_sides(20, 15, 70, 35);
564    /// assert_eq!(r1.outer_span(r2, Dir::Horiz), Span::new(10, 70));
565    /// assert_eq!(r1.outer_span(r2, Dir::Vert), Span::new(15, 50));
566    /// ```
567    ///
568    /// The "order" of `r1` and `r2` does not matter:
569    ///
570    /// ```
571    /// # use geometry::prelude::*;
572    /// let r1 = Rect::from_sides(10, 25, 30, 50);
573    /// let r2 = Rect::from_sides(20, 15, 70, 35);
574    /// assert_eq!(r2.outer_span(r1, Dir::Horiz), Span::new(10, 70));
575    /// assert_eq!(r2.outer_span(r1, Dir::Vert), Span::new(15, 50));
576    /// ```
577    #[inline]
578    pub fn outer_span(&self, other: Self, dir: Dir) -> Span {
579        let edges = self.sorted_coords(other, dir);
580        unsafe {
581            // SAFETY: sorted_coords returns edges in sorted order,
582            // so edges[0] <= edges[3].
583            Span::new_unchecked(edges[0], edges[3])
584        }
585    }
586
587    /// Returns the edge of a rectangle closest to the coordinate `x` along a given direction.
588    ///
589    /// # Example
590    ///
591    /// ```
592    /// # use geometry::prelude::*;
593    /// let rect = Rect::from_sides(10, 25, 30, 50);
594    /// assert_eq!(rect.edge_closer_to(14, Dir::Horiz), 10);
595    /// assert_eq!(rect.edge_closer_to(22, Dir::Horiz), 30);
596    /// assert_eq!(rect.edge_closer_to(23, Dir::Vert), 25);
597    /// assert_eq!(rect.edge_closer_to(37, Dir::Vert), 25);
598    /// assert_eq!(rect.edge_closer_to(38, Dir::Vert), 50);
599    /// assert_eq!(rect.edge_closer_to(59, Dir::Vert), 50);
600    /// ```
601    pub fn edge_closer_to(&self, x: i64, dir: Dir) -> i64 {
602        let (x0, x1) = self.span(dir).into();
603        if (x - x0).abs() <= (x - x1).abs() {
604            x0
605        } else {
606            x1
607        }
608    }
609
610    /// Returns the edge of a rectangle farthest from the coordinate `x` along a given direction.
611    ///
612    /// # Example
613    ///
614    /// ```
615    /// # use geometry::prelude::*;
616    /// let rect = Rect::from_sides(10, 25, 30, 50);
617    /// assert_eq!(rect.edge_farther_from(14, Dir::Horiz), 30);
618    /// assert_eq!(rect.edge_farther_from(22, Dir::Horiz), 10);
619    /// assert_eq!(rect.edge_farther_from(23, Dir::Vert), 50);
620    /// assert_eq!(rect.edge_farther_from(37, Dir::Vert), 50);
621    /// assert_eq!(rect.edge_farther_from(38, Dir::Vert), 25);
622    /// assert_eq!(rect.edge_farther_from(59, Dir::Vert), 25);
623    /// ```
624    pub fn edge_farther_from(&self, x: i64, dir: Dir) -> i64 {
625        let (x0, x1) = self.span(dir).into();
626        if (x - x0).abs() <= (x - x1).abs() {
627            x1
628        } else {
629            x0
630        }
631    }
632
633    /// Creates a rectangle from two [`Span`]s, where the first is parallel to `dir`,
634    /// and the second is perpendicular.
635    ///
636    /// # Example
637    ///
638    /// ```
639    /// # use geometry::prelude::*;
640    /// let span1 = Span::new(10, 30);
641    /// let span2 = Span::new(25, 50);
642    /// let rect = Rect::from_dir_spans(Dir::Horiz, span1, span2);
643    /// assert_eq!(rect, Rect::from_sides(10, 25, 30, 50));
644    /// let rect = Rect::from_dir_spans(Dir::Vert, span1, span2);
645    /// assert_eq!(rect, Rect::from_sides(25, 10, 50, 30));
646    /// ```
647    #[inline]
648    pub fn from_dir_spans(dir: Dir, parallel_span: Span, perp_span: Span) -> Self {
649        match dir {
650            Dir::Vert => Self::from_spans(perp_span, parallel_span),
651            Dir::Horiz => Self::from_spans(parallel_span, perp_span),
652        }
653    }
654
655    /// Returns the length of this rectangle in the given direction.
656    ///
657    /// # Example
658    ///
659    /// ```
660    /// # use geometry::prelude::*;
661    /// let rect = Rect::from_sides(0, 0, 200, 100);
662    /// assert_eq!(rect.length(Dir::Horiz), 200);
663    /// assert_eq!(rect.length(Dir::Vert), 100);
664    /// ```
665    ///
666    pub const fn length(&self, dir: Dir) -> i64 {
667        self.span(dir).length()
668    }
669
670    /// Returns the direction in which the rectangle is longer, choosing [`Dir::Horiz`] if the sides
671    /// are equal.
672    ///
673    /// # Example
674    ///
675    /// ```
676    /// # use geometry::prelude::*;
677    /// let rect = Rect::from_sides(0, 0, 100, 200);
678    /// assert_eq!(rect.longer_dir(), Dir::Vert);
679    /// let rect = Rect::from_sides(0, 0, 200, 100);
680    /// assert_eq!(rect.longer_dir(), Dir::Horiz);
681    /// let rect = Rect::from_sides(0, 0, 100, 100);
682    /// assert_eq!(rect.longer_dir(), Dir::Horiz);
683    /// ```
684    #[inline]
685    pub const fn longer_dir(&self) -> Dir {
686        if self.height() > self.width() {
687            Dir::Vert
688        } else {
689            Dir::Horiz
690        }
691    }
692
693    /// Returns the direction in which the rectangle is longer, returning [`None`] if the sides
694    /// are equal.
695    ///
696    /// # Example
697    ///
698    /// ```
699    /// # use geometry::prelude::*;
700    /// let rect = Rect::from_sides(0, 0, 100, 200);
701    /// assert_eq!(rect.longer_dir_strict(), Some(Dir::Vert));
702    /// let rect = Rect::from_sides(0, 0, 200, 100);
703    /// assert_eq!(rect.longer_dir_strict(), Some(Dir::Horiz));
704    /// let rect = Rect::from_sides(0, 0, 100, 100);
705    /// assert_eq!(rect.longer_dir_strict(), None);
706    /// ```
707    #[inline]
708    pub fn longer_dir_strict(&self) -> Option<Dir> {
709        use std::cmp::Ordering;
710        match self.height().cmp(&self.width()) {
711            Ordering::Less => Some(Dir::Horiz),
712            Ordering::Equal => None,
713            Ordering::Greater => Some(Dir::Vert),
714        }
715    }
716
717    /// Returns the direction in which the rectangle is shorter, choosing [`Dir::Vert`] if the sides
718    /// are equal.
719    ///
720    /// This always returns the opposite of [`Rect::longer_dir`].
721    ///
722    /// # Example
723    ///
724    /// ```
725    /// # use geometry::prelude::*;
726    /// let rect = Rect::from_sides(0, 0, 100, 200);
727    /// assert_eq!(rect.shorter_dir(), Dir::Horiz);
728    /// let rect = Rect::from_sides(0, 0, 200, 100);
729    /// assert_eq!(rect.shorter_dir(), Dir::Vert);
730    /// let rect = Rect::from_sides(0, 0, 100, 100);
731    /// assert_eq!(rect.shorter_dir(), Dir::Vert);
732    /// ```
733    #[inline]
734    pub const fn shorter_dir(&self) -> Dir {
735        self.longer_dir().other()
736    }
737
738    /// Returns the direction in which the rectangle is shorter, choosing [`None`] if the sides
739    /// are equal.
740    ///
741    /// This always returns the opposite of [`Rect::longer_dir_strict`].
742    ///
743    /// # Example
744    ///
745    /// ```
746    /// # use geometry::prelude::*;
747    /// let rect = Rect::from_sides(0, 0, 100, 200);
748    /// assert_eq!(rect.shorter_dir_strict(), Some(Dir::Horiz));
749    /// let rect = Rect::from_sides(0, 0, 200, 100);
750    /// assert_eq!(rect.shorter_dir_strict(), Some(Dir::Vert));
751    /// let rect = Rect::from_sides(0, 0, 100, 100);
752    /// assert_eq!(rect.shorter_dir_strict(), None);
753    /// ```
754    #[inline]
755    pub fn shorter_dir_strict(&self) -> Option<Dir> {
756        self.longer_dir_strict().as_ref().map(Dir::other)
757    }
758
759    /// Computes the rectangular union of this `Rect` with another `Rect`.
760    ///
761    /// # Example
762    ///
763    /// ```
764    /// # use geometry::prelude::*;
765    /// let r1 = Rect::from_sides(0, 0, 100, 200);
766    /// let r2 = Rect::from_sides(-50, 20, 120, 160);
767    /// assert_eq!(r1.union(r2), Rect::from_sides(-50, 0, 120, 200));
768    /// ```
769    pub fn union(self, other: Self) -> Self {
770        Rect::new(
771            Point::new(self.p0.x.min(other.p0.x), self.p0.y.min(other.p0.y)),
772            Point::new(self.p1.x.max(other.p1.x), self.p1.y.max(other.p1.y)),
773        )
774    }
775
776    /// Calculates the rectangular union of all rectangles provided.
777    ///
778    /// # Example
779    ///
780    /// ```
781    /// # use geometry::prelude::*;
782    /// let rects = vec![
783    ///     Rect::from_sides(10, 20, 30, 40),
784    ///     Rect::from_sides(-10, 25, 20, 35),
785    ///     Rect::from_sides(15, 20, 25, 60),
786    /// ];
787    /// assert_eq!(Rect::union_all(rects.into_iter()), Rect::from_sides(-10, 20, 30, 60));
788    /// ```
789    ///
790    /// # Panics
791    ///
792    /// This function panics if the provided iterator has no elements.
793    /// If your iterator may be empty, consider using [`Rect::union_all_option`].
794    pub fn union_all<T>(rects: impl Iterator<Item = T>) -> Self
795    where
796        T: Into<Self>,
797    {
798        rects
799            .fold(None, |acc: Option<Rect>, r| match acc {
800                Some(acc) => Some(acc.union(r.into())),
801                None => Some(r.into()),
802            })
803            .unwrap()
804    }
805
806    /// Calculates the rectangular union of all `Option<Rect>`s provided.
807    ///
808    /// All `None` elements in the iterator are ignored.
809    /// If the iterator has no `Some(_)` elements, this function returns [`None`].
810    ///
811    /// # Example
812    ///
813    /// ```
814    /// # use geometry::prelude::*;
815    /// let rects = vec![
816    ///     Some(Rect::from_sides(10, 20, 30, 40)),
817    ///     Some(Rect::from_sides(-10, 25, 20, 35)),
818    ///     None,
819    ///     Some(Rect::from_sides(15, 20, 25, 60)),
820    /// ];
821    /// assert_eq!(Rect::union_all_option(rects.into_iter()), Some(Rect::from_sides(-10, 20, 30, 60)));
822    /// ```
823    pub fn union_all_option<T>(rects: impl Iterator<Item = T>) -> Option<Self>
824    where
825        T: Into<Option<Self>>,
826    {
827        rects
828            .filter_map(|r| r.into())
829            .fold(None, |acc, r| match acc {
830                Some(acc) => Some(acc.union(r)),
831                None => Some(r),
832            })
833    }
834
835    /// Computes the rectangular intersection of this `Rect` with another `Rect`.
836    ///
837    /// Returns `None` if the intersection is empty.
838    ///
839    /// # Example
840    ///
841    /// ```
842    /// # use geometry::prelude::*;
843    /// let r1 = Rect::from_sides(0, 0, 100, 200);
844    /// let r2 = Rect::from_sides(-50, 20, 120, 160);
845    /// assert_eq!(r1.intersection(r2), Some(Rect::from_sides(0, 20, 100, 160)));
846    ///
847    /// let r1 = Rect::from_sides(0, 0, 100, 200);
848    /// let r2 = Rect::from_sides(120, -60, 240, 800);
849    /// assert_eq!(r1.intersection(r2), None);
850    /// ```
851    pub fn intersection(self, other: Self) -> Option<Self> {
852        let pmin = Point::new(self.p0.x.max(other.p0.x), self.p0.y.max(other.p0.y));
853        let pmax = Point::new(self.p1.x.min(other.p1.x), self.p1.y.min(other.p1.y));
854
855        // Check for empty intersection, and return None
856        if pmin.x > pmax.x || pmin.y > pmax.y {
857            return None;
858        }
859
860        // Otherwise, return the intersection
861        Some(Rect::new(pmin, pmax))
862    }
863
864    /// Expands the rectangle by `amount` on all sides.
865    ///
866    /// # Example
867    ///
868    /// ```
869    /// # use geometry::prelude::*;
870    /// let rect = Rect::from_sides(0, 0, 100, 200);
871    /// assert_eq!(rect.expand_all(20), Rect::from_sides(-20, -20, 120, 220));
872    /// ```
873    #[inline]
874    pub fn expand_all(&self, amount: i64) -> Self {
875        Self::new(
876            Point::new(self.p0.x - amount, self.p0.y - amount),
877            Point::new(self.p1.x + amount, self.p1.y + amount),
878        )
879    }
880
881    /// Expands the rectangle by `amount` on both sides associated with the direction `dir`.
882    ///
883    /// # Example
884    ///
885    /// ```
886    /// # use geometry::prelude::*;
887    /// let rect = Rect::from_sides(0, 0, 100, 200);
888    /// assert_eq!(rect.expand_dir(Dir::Horiz, 20), Rect::from_sides(-20, 0, 120, 200));
889    /// assert_eq!(rect.expand_dir(Dir::Vert, 20), Rect::from_sides(0, -20, 100, 220));
890    /// ```
891    #[inline]
892    pub fn expand_dir(&self, dir: Dir, amount: i64) -> Self {
893        match dir {
894            Dir::Horiz => Self::new(
895                Point::new(self.p0.x - amount, self.p0.y),
896                Point::new(self.p1.x + amount, self.p1.y),
897            ),
898            Dir::Vert => Self::new(
899                Point::new(self.p0.x, self.p0.y - amount),
900                Point::new(self.p1.x, self.p1.y + amount),
901            ),
902        }
903    }
904
905    /// Expands the rectangle by `amount` on the given side.
906    ///
907    /// # Example
908    ///
909    /// ```
910    /// # use geometry::prelude::*;
911    /// let rect = Rect::from_sides(0, 0, 100, 200);
912    /// assert_eq!(rect.expand_side(Side::Top, 20), Rect::from_sides(0, 0, 100, 220));
913    /// assert_eq!(rect.expand_side(Side::Bot, 20), Rect::from_sides(0, -20, 100, 200));
914    /// assert_eq!(rect.expand_side(Side::Left, 20), Rect::from_sides(-20, 0, 100, 200));
915    /// assert_eq!(rect.expand_side(Side::Right, 20), Rect::from_sides(0, 0, 120, 200));
916    /// ```
917    #[inline]
918    pub fn expand_side(&self, side: Side, amount: i64) -> Self {
919        match side {
920            Side::Top => Self::new(
921                Point::new(self.p0.x, self.p0.y),
922                Point::new(self.p1.x, self.p1.y + amount),
923            ),
924            Side::Bot => Self::new(
925                Point::new(self.p0.x, self.p0.y - amount),
926                Point::new(self.p1.x, self.p1.y),
927            ),
928            Side::Right => Self::new(
929                Point::new(self.p0.x, self.p0.y),
930                Point::new(self.p1.x + amount, self.p1.y),
931            ),
932            Side::Left => Self::new(
933                Point::new(self.p0.x - amount, self.p0.y),
934                Point::new(self.p1.x, self.p1.y),
935            ),
936        }
937    }
938
939    /// Expands the rectangle by `amount` at the given corner.
940    ///
941    /// # Example
942    ///
943    /// ```
944    /// # use geometry::prelude::*;
945    /// let rect = Rect::from_sides(0, 0, 100, 200);
946    /// assert_eq!(rect.expand_corner(Corner::LowerLeft, 20), Rect::from_sides(-20, -20, 100, 200));
947    /// assert_eq!(rect.expand_corner(Corner::LowerRight, 20), Rect::from_sides(0, -20, 120, 200));
948    /// assert_eq!(rect.expand_corner(Corner::UpperLeft, 20), Rect::from_sides(-20, 0, 100, 220));
949    /// assert_eq!(rect.expand_corner(Corner::UpperRight, 20), Rect::from_sides(0, 0, 120, 220));
950    /// ```
951    #[inline]
952    pub fn expand_corner(self, corner: Corner, amount: i64) -> Self {
953        match corner {
954            Corner::LowerLeft => {
955                Self::from_sides(self.p0.x - amount, self.p0.y - amount, self.p1.x, self.p1.y)
956            }
957            Corner::LowerRight => {
958                Self::from_sides(self.p0.x, self.p0.y - amount, self.p1.x + amount, self.p1.y)
959            }
960            Corner::UpperLeft => {
961                Self::from_sides(self.p0.x - amount, self.p0.y, self.p1.x, self.p1.y + amount)
962            }
963            Corner::UpperRight => {
964                Self::from_sides(self.p0.x, self.p0.y, self.p1.x + amount, self.p1.y + amount)
965            }
966        }
967    }
968
969    /// Expands the rectangle by some (possibly different) amount on each side.
970    ///
971    /// # Example
972    ///
973    /// ```
974    /// # use geometry::prelude::*;
975    /// let rect = Rect::from_sides(0, 0, 100, 200);
976    /// let sides = Sides::new(10, 20, 30, 40);
977    /// assert_eq!(rect.expand_sides(sides), Rect::from_sides(-10, -20, 130, 240));
978    /// ```
979    pub fn expand_sides(&self, sides: Sides<i64>) -> Self {
980        Self::from_sides(
981            self.p0.x - sides[Side::Left],
982            self.p0.y - sides[Side::Bot],
983            self.p1.x + sides[Side::Right],
984            self.p1.y + sides[Side::Top],
985        )
986    }
987
988    /// Shrinks the rectangle by `amount` on all sides.
989    ///
990    /// Returns [`None`] if shrinking would make the rectangle invalid.
991    ///
992    /// # Example
993    ///
994    /// ```
995    /// # use geometry::prelude::*;
996    /// let rect = Rect::from_sides(0, 0, 100, 200);
997    /// assert_eq!(rect.shrink_all(20), Some(Rect::from_sides(20, 20, 80, 180)));
998    /// assert_eq!(rect.shrink_all(105), None);
999    /// ```
1000    #[inline]
1001    pub fn shrink_all(&self, amount: i64) -> Option<Self> {
1002        Self::from_sides_option(
1003            self.p0.x + amount,
1004            self.p0.y + amount,
1005            self.p1.x - amount,
1006            self.p1.y - amount,
1007        )
1008    }
1009
1010    /// Shrinks the rectangle by `amount` on both sides associated with the direction `dir`.
1011    ///
1012    /// Returns [`None`] if shrinking would make the rectangle invalid.
1013    ///
1014    /// # Example
1015    ///
1016    /// ```
1017    /// # use geometry::prelude::*;
1018    /// let rect = Rect::from_sides(0, 0, 100, 200);
1019    /// assert_eq!(rect.shrink_dir(Dir::Horiz, 20), Some(Rect::from_sides(20, 0, 80, 200)));
1020    /// assert_eq!(rect.shrink_dir(Dir::Vert, 20), Some(Rect::from_sides(0, 20, 100, 180)));
1021    /// assert_eq!(rect.shrink_dir(Dir::Vert, 120), None);
1022    /// ```
1023    #[inline]
1024    pub fn shrink_dir(&self, dir: Dir, amount: i64) -> Option<Self> {
1025        match dir {
1026            Dir::Horiz => Self::from_sides_option(
1027                self.p0.x + amount,
1028                self.p0.y,
1029                self.p1.x - amount,
1030                self.p1.y,
1031            ),
1032            Dir::Vert => Self::from_sides_option(
1033                self.p0.x,
1034                self.p0.y + amount,
1035                self.p1.x,
1036                self.p1.y - amount,
1037            ),
1038        }
1039    }
1040
1041    /// Shrinks the rectangle by `amount` on the given side.
1042    ///
1043    /// Returns [`None`] if shrinking would make the rectangle invalid.
1044    ///
1045    /// # Example
1046    ///
1047    /// ```
1048    /// # use geometry::prelude::*;
1049    /// let rect = Rect::from_sides(0, 0, 100, 200);
1050    /// assert_eq!(rect.shrink_side(Side::Top, 20), Some(Rect::from_sides(0, 0, 100, 180)));
1051    /// assert_eq!(rect.shrink_side(Side::Bot, 20), Some(Rect::from_sides(0, 20, 100, 200)));
1052    /// assert_eq!(rect.shrink_side(Side::Left, 20), Some(Rect::from_sides(20, 0, 100, 200)));
1053    /// assert_eq!(rect.shrink_side(Side::Right, 20), Some(Rect::from_sides(0, 0, 80, 200)));
1054    /// assert_eq!(rect.shrink_side(Side::Right, 210), None);
1055    /// ```
1056    #[inline]
1057    pub fn shrink_side(&self, side: Side, amount: i64) -> Option<Self> {
1058        match side {
1059            Side::Top => {
1060                Self::from_sides_option(self.p0.x, self.p0.y, self.p1.x, self.p1.y - amount)
1061            }
1062            Side::Bot => {
1063                Self::from_sides_option(self.p0.x, self.p0.y + amount, self.p1.x, self.p1.y)
1064            }
1065            Side::Right => {
1066                Self::from_sides_option(self.p0.x, self.p0.y, self.p1.x - amount, self.p1.y)
1067            }
1068            Side::Left => {
1069                Self::from_sides_option(self.p0.x + amount, self.p0.y, self.p1.x, self.p1.y)
1070            }
1071        }
1072    }
1073
1074    /// Shrinks the rectangle by some (possibly different) amount on each side.
1075    ///
1076    /// Returns [`None`] if shrinking would make the rectangle invalid.
1077    ///
1078    /// # Example
1079    ///
1080    /// ```
1081    /// # use geometry::prelude::*;
1082    /// let rect = Rect::from_sides(0, 0, 100, 200);
1083    /// let sides = Sides::new(10, 20, 30, 40);
1084    /// assert_eq!(rect.shrink_sides(sides), Some(Rect::from_sides(10, 20, 70, 160)));
1085    /// ```
1086    pub fn shrink_sides(&self, sides: Sides<i64>) -> Option<Self> {
1087        Self::from_sides_option(
1088            self.p0.x + sides[Side::Left],
1089            self.p0.y + sides[Side::Bot],
1090            self.p1.x - sides[Side::Right],
1091            self.p1.y - sides[Side::Top],
1092        )
1093    }
1094
1095    /// Shrinks the rectangle by `amount` at the given corner.
1096    ///
1097    /// Returns [`None`] if shrinking would make the rectangle invalid.
1098    ///
1099    /// # Example
1100    ///
1101    /// ```
1102    /// # use geometry::prelude::*;
1103    /// let rect = Rect::from_sides(0, 0, 100, 200);
1104    /// assert_eq!(rect.shrink_corner(Corner::LowerLeft, 20), Some(Rect::from_sides(20, 20, 100, 200)));
1105    /// assert_eq!(rect.shrink_corner(Corner::LowerRight, 20), Some(Rect::from_sides(0, 20, 80, 200)));
1106    /// assert_eq!(rect.shrink_corner(Corner::UpperLeft, 20), Some(Rect::from_sides(20, 0, 100, 180)));
1107    /// assert_eq!(rect.shrink_corner(Corner::UpperRight, 20), Some(Rect::from_sides(0, 0, 80, 180)));
1108    /// assert_eq!(rect.shrink_corner(Corner::UpperRight, 110), None);
1109    /// ```
1110    #[inline]
1111    pub fn shrink_corner(self, corner: Corner, amount: i64) -> Option<Self> {
1112        match corner {
1113            Corner::LowerLeft => Self::from_sides_option(
1114                self.p0.x + amount,
1115                self.p0.y + amount,
1116                self.p1.x,
1117                self.p1.y,
1118            ),
1119            Corner::LowerRight => Self::from_sides_option(
1120                self.p0.x,
1121                self.p0.y + amount,
1122                self.p1.x - amount,
1123                self.p1.y,
1124            ),
1125            Corner::UpperLeft => Self::from_sides_option(
1126                self.p0.x + amount,
1127                self.p0.y,
1128                self.p1.x,
1129                self.p1.y - amount,
1130            ),
1131            Corner::UpperRight => Self::from_sides_option(
1132                self.p0.x,
1133                self.p0.y,
1134                self.p1.x - amount,
1135                self.p1.y - amount,
1136            ),
1137        }
1138    }
1139
1140    /// Returns the dimensions of the rectangle.
1141    ///
1142    /// # Example
1143    ///
1144    /// ```
1145    /// # use geometry::prelude::*;
1146    /// let rect = Rect::from_sides(20, 20, 100, 200);
1147    /// assert_eq!(rect.dims(), Dims::new(80, 180));
1148    /// ```
1149    #[inline]
1150    pub fn dims(&self) -> Dims {
1151        Dims::new(self.width(), self.height())
1152    }
1153
1154    /// The lower left corner of the rectangle.
1155    ///
1156    /// # Example
1157    ///
1158    /// ```
1159    /// # use geometry::prelude::*;
1160    /// let rect = Rect::from_sides(20, 20, 100, 200);
1161    /// assert_eq!(rect.lower_left(), Point::new(20, 20));
1162    /// ```
1163    #[inline]
1164    pub fn lower_left(&self) -> Point {
1165        self.corner(Corner::LowerLeft)
1166    }
1167
1168    /// The lower right corner of the rectangle.
1169    ///
1170    /// # Example
1171    ///
1172    /// ```
1173    /// # use geometry::prelude::*;
1174    /// let rect = Rect::from_sides(20, 20, 100, 200);
1175    /// assert_eq!(rect.lower_right(), Point::new(100, 20));
1176    /// ```
1177    #[inline]
1178    pub fn lower_right(&self) -> Point {
1179        self.corner(Corner::LowerRight)
1180    }
1181
1182    /// The upper left corner of the rectangle.
1183    ///
1184    /// # Example
1185    ///
1186    /// ```
1187    /// # use geometry::prelude::*;
1188    /// let rect = Rect::from_sides(20, 20, 100, 200);
1189    /// assert_eq!(rect.upper_left(), Point::new(20, 200));
1190    /// ```
1191    #[inline]
1192    pub fn upper_left(&self) -> Point {
1193        self.corner(Corner::UpperLeft)
1194    }
1195
1196    /// The upper right corner of the rectangle.
1197    ///
1198    /// # Example
1199    ///
1200    /// ```
1201    /// # use geometry::prelude::*;
1202    /// let rect = Rect::from_sides(20, 20, 100, 200);
1203    /// assert_eq!(rect.upper_right(), Point::new(100, 200));
1204    /// ```
1205    #[inline]
1206    pub fn upper_right(&self) -> Point {
1207        self.corner(Corner::UpperRight)
1208    }
1209
1210    /// Returns the desired corner of the rectangle.
1211    ///
1212    /// # Example
1213    ///
1214    /// ```
1215    /// # use geometry::prelude::*;
1216    /// let rect = Rect::from_sides(20, 20, 100, 200);
1217    /// assert_eq!(rect.corner(Corner::LowerLeft), Point::new(20, 20));
1218    /// assert_eq!(rect.corner(Corner::LowerRight), Point::new(100, 20));
1219    /// assert_eq!(rect.corner(Corner::UpperLeft), Point::new(20, 200));
1220    /// assert_eq!(rect.corner(Corner::UpperRight), Point::new(100, 200));
1221    /// ```
1222    pub fn corner(&self, corner: Corner) -> Point {
1223        match corner {
1224            Corner::LowerLeft => self.p0,
1225            Corner::LowerRight => Point::new(self.p1.x, self.p0.y),
1226            Corner::UpperLeft => Point::new(self.p0.x, self.p1.y),
1227            Corner::UpperRight => self.p1,
1228        }
1229    }
1230
1231    /// Returns the desired side of the rectangle.
1232    ///
1233    /// # Example
1234    ///
1235    /// ```
1236    /// # use geometry::prelude::*;
1237    /// let rect = Rect::from_sides(20, 20, 100, 200);
1238    /// assert_eq!(rect.side(Side::Bot), 20);
1239    /// assert_eq!(rect.side(Side::Left), 20);
1240    /// assert_eq!(rect.side(Side::Top), 200);
1241    /// assert_eq!(rect.side(Side::Right), 100);
1242    /// ```
1243    #[inline]
1244    pub fn side(&self, side: Side) -> i64 {
1245        match side {
1246            Side::Top => self.top(),
1247            Side::Bot => self.bot(),
1248            Side::Right => self.right(),
1249            Side::Left => self.left(),
1250        }
1251    }
1252
1253    /// Returns the desired edge of the rectangle.
1254    ///
1255    /// # Example
1256    ///
1257    /// ```
1258    /// # use geometry::prelude::*;
1259    /// let rect = Rect::from_sides(20, 20, 100, 200);
1260    /// assert_eq!(rect.edge(Side::Bot), Edge::new(Side::Bot, 20, Span::new(20, 100)));
1261    /// assert_eq!(rect.edge(Side::Top), Edge::new(Side::Top, 200, Span::new(20, 100)));
1262    /// assert_eq!(rect.edge(Side::Left), Edge::new(Side::Left, 20, Span::new(20, 200)));
1263    /// assert_eq!(rect.edge(Side::Right), Edge::new(Side::Right, 100, Span::new(20, 200)));
1264    /// ```
1265    #[inline]
1266    pub fn edge(&self, side: Side) -> Edge {
1267        Edge::new(side, self.side(side), self.span(side.edge_dir()))
1268    }
1269
1270    /// Snaps the corners of this rectangle to the given grid.
1271    ///
1272    /// Note that the rectangle may have zero area after snapping.
1273    ///
1274    /// # Example
1275    ///
1276    /// ```
1277    /// # use geometry::prelude::*;
1278    /// let rect = Rect::from_sides(17, 23, 101, 204);
1279    /// assert_eq!(rect.snap_to_grid(5), Rect::from_sides(15, 25, 100, 205));
1280    ///
1281    /// let rect = Rect::from_sides(16, 17, 101, 104);
1282    /// assert_eq!(rect.snap_to_grid(5), Rect::from_sides(15, 15, 100, 105));
1283    ///
1284    /// let rect = Rect::from_sides(16, 17, 17, 18);
1285    /// assert_eq!(rect.snap_to_grid(5), Rect::from_sides(15, 15, 15, 20));
1286    /// ```
1287    #[inline]
1288    pub fn snap_to_grid(&self, grid: i64) -> Self {
1289        Self::new(self.p0.snap_to_grid(grid), self.p1.snap_to_grid(grid))
1290    }
1291
1292    /// Based on `clip`, cuts a hole in this rectangle and returns the four surrounding pieces.
1293    ///
1294    /// Assumes that `clip` is entirely contained by this rectangle.
1295    ///
1296    /// # Example
1297    ///
1298    /// ```
1299    /// # use geometry::prelude::*;
1300    /// let rect = Rect::from_sides(0, 0, 100, 100);
1301    /// let clip = Rect::from_sides(20, 20, 80, 80);
1302    /// assert_eq!(rect.cutout(clip), [
1303    ///     Rect::from_sides(0, 80, 100, 100),
1304    ///     Rect::from_sides(0, 0, 100, 20),
1305    ///     Rect::from_sides(0, 0, 20, 100),
1306    ///     Rect::from_sides(80, 0, 100, 100),
1307    /// ]);
1308    pub fn cutout(&self, clip: Rect) -> [Rect; 4] {
1309        let src = *self;
1310        let t_span = Span::new(clip.top(), src.top());
1311        let b_span = Span::new(src.bot(), clip.bot());
1312        let l_span = Span::new(src.left(), clip.left());
1313        let r_span = Span::new(clip.right(), src.right());
1314
1315        [
1316            Rect::from_spans(src.hspan(), t_span),
1317            Rect::from_spans(src.hspan(), b_span),
1318            Rect::from_spans(l_span, src.vspan()),
1319            Rect::from_spans(r_span, src.vspan()),
1320        ]
1321    }
1322
1323    /// Returns whether the rectangle's center has integer coordinates.
1324    ///
1325    /// # Example
1326    ///
1327    /// ```
1328    /// # use geometry::prelude::*;
1329    /// let rect = Rect::from_sides(0, 0, 100, 100);
1330    /// assert!(rect.has_integer_center());
1331    ///
1332    /// let rect = Rect::from_sides(0, 0, 99, 100);
1333    /// assert!(!rect.has_integer_center());
1334    /// ```
1335    pub fn has_integer_center(&self) -> bool {
1336        self.vspan().has_integer_center() && self.hspan().has_integer_center()
1337    }
1338}
1339
1340impl Bbox for Rect {
1341    fn bbox(&self) -> Option<Rect> {
1342        Some(*self)
1343    }
1344}
1345
1346impl Intersect<Rect> for Rect {
1347    type Output = Self;
1348
1349    fn intersect(&self, bounds: &Rect) -> Option<Self::Output> {
1350        self.intersection(*bounds)
1351    }
1352}
1353
1354impl TranslateRef for Rect {
1355    #[inline]
1356    fn translate_ref(&self, p: Point) -> Self {
1357        self.translate(p)
1358    }
1359}
1360
1361impl TranslateMut for Rect {
1362    fn translate_mut(&mut self, p: Point) {
1363        self.p0.translate_mut(p);
1364        self.p1.translate_mut(p);
1365    }
1366}
1367
1368impl TransformRef for Rect {
1369    #[inline]
1370    fn transform_ref(&self, trans: Transformation) -> Self {
1371        self.transform(trans)
1372    }
1373}
1374
1375impl TransformMut for Rect {
1376    fn transform_mut(&mut self, trans: Transformation) {
1377        let (mut p0, mut p1) = (self.p0, self.p1);
1378        p0.transform_mut(trans);
1379        p1.transform_mut(trans);
1380
1381        self.p0 = Point::new(std::cmp::min(p0.x, p1.x), std::cmp::min(p0.y, p1.y));
1382        self.p1 = Point::new(std::cmp::max(p0.x, p1.x), std::cmp::max(p0.y, p1.y));
1383    }
1384}
1385
1386impl BoundingUnion<Rect> for Rect {
1387    type Output = Rect;
1388    fn bounding_union(&self, other: &Rect) -> Self::Output {
1389        self.union(*other)
1390    }
1391}
1392
1393impl From<Dims> for Rect {
1394    /// Converts the [`Dims`] to a [`Rect`] as described in [`Rect::from_dims`].
1395    #[inline]
1396    fn from(value: Dims) -> Self {
1397        Self::from_dims(value)
1398    }
1399}
1400
1401impl Contains<Point> for Rect {
1402    fn contains(&self, other: &Point) -> Containment {
1403        if other.x >= self.p0.x
1404            && other.x <= self.p1.x
1405            && other.y >= self.p0.y
1406            && other.y <= self.p1.y
1407        {
1408            Containment::Full
1409        } else {
1410            Containment::None
1411        }
1412    }
1413}
1414
1415#[cfg(test)]
1416mod tests {
1417    use crate::prelude::*;
1418
1419    #[test]
1420    fn sorted_coords_works() {
1421        let r1 = Rect::from_sides(10, 25, 30, 50);
1422        let r2 = Rect::from_sides(20, 15, 70, 35);
1423        assert_eq!(r1.sorted_coords(r2, Dir::Horiz), [10, 20, 30, 70]);
1424        assert_eq!(r1.sorted_coords(r2, Dir::Vert), [15, 25, 35, 50]);
1425        assert_eq!(r2.sorted_coords(r1, Dir::Horiz), [10, 20, 30, 70]);
1426        assert_eq!(r2.sorted_coords(r1, Dir::Vert), [15, 25, 35, 50]);
1427    }
1428}