From 26f1a339015e837eda71a809f6a3af276164e608 Mon Sep 17 00:00:00 2001 From: Nils Date: Sun, 26 May 2024 00:01:35 +0200 Subject: [PATCH 1/5] add the `Rect::intersect` method --- src/rect.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/rect.rs b/src/rect.rs index 397b9785..40393262 100644 --- a/src/rect.rs +++ b/src/rect.rs @@ -222,6 +222,11 @@ impl Rect { /// /// The result is zero-area if either input has negative width or /// height. The result always has non-negative width and height. + /// + /// If you want to determine whether two rectangles intersect, use the + /// [`intersects`] method instead. + /// + /// [`intersects`]: Rect::intersects #[inline] pub fn intersect(&self, other: Rect) -> Rect { let x0 = self.x0.max(other.x0); @@ -231,6 +236,29 @@ impl Rect { Rect::new(x0, y0, x1.max(x0), y1.max(y0)) } + /// Determines whether the this rectangle intersects with another in any way. + /// + /// Returns `true` if the rectangles intersect, `false` otherwise. + /// + /// If you want to compute the *intersection* of two rectangles, use the + /// [`intersect`] method instead. + /// + /// [`intersect`]: Rect::intersect + /// + /// # Examples + /// + /// ``` + /// use kurbo::Rect; + /// + /// let rect1 = Rect::new(0.0, 0.0, 10.0, 10.0); + /// let rect2 = Rect::new(5.0, 5.0, 15.0, 15.0); + /// assert!(rect1.intersects(rect2)); + /// ``` + #[inline] + pub fn intersects(&self, other: Rect) -> bool { + self.x0 < other.x1 && self.x1 > other.x0 && self.y0 < other.y1 && self.y1 > other.y0 + } + /// Expand a rectangle by a constant amount in both directions. /// /// The logic simply applies the amount in each direction. If rectangle From 38d9f8ae731e6dca94e3cb5a2aa07a48756bd804 Mon Sep 17 00:00:00 2001 From: Nils Date: Sun, 26 May 2024 00:15:55 +0200 Subject: [PATCH 2/5] add the `Rect::contains_rect` method --- src/rect.rs | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/src/rect.rs b/src/rect.rs index 40393262..5ea7ed7e 100644 --- a/src/rect.rs +++ b/src/rect.rs @@ -243,7 +243,7 @@ impl Rect { /// If you want to compute the *intersection* of two rectangles, use the /// [`intersect`] method instead. /// - /// [`intersect`]: Rect::intersect + /// [`intersect`]: Rect::intersects /// /// # Examples /// @@ -259,6 +259,34 @@ impl Rect { self.x0 < other.x1 && self.x1 > other.x0 && self.y0 < other.y1 && self.y1 > other.y0 } + /// Returns whether this rectangle contains another rectangle. + /// + /// A rectangle is considered to contain another rectangle if the other + /// rectangle is fully enclosed within the bounds of this rectangle. + /// + /// # Examples + /// + /// ``` + /// use kurbo::Rect; + /// + /// let rect1 = Rect::new(0.0, 0.0, 10.0, 10.0); + /// let rect2 = Rect::new(2.0, 2.0, 4.0, 4.0); + /// assert!(rect1.contains_rect(rect2)); + /// ``` + /// + /// Two equal rectangles are considered to contain each other. + /// + /// ``` + /// use kurbo::Rect; + /// + /// let rect = Rect::new(0.0, 0.0, 10.0, 10.0); + /// assert!(rect.contains_rect(rect)); + /// ``` + #[inline] + pub fn contains_rect(&self, other: Rect) -> bool { + self.x0 <= other.x0 && self.y0 <= other.y0 && self.x1 >= other.x1 && self.y1 >= other.y1 + } + /// Expand a rectangle by a constant amount in both directions. /// /// The logic simply applies the amount in each direction. If rectangle @@ -796,4 +824,54 @@ mod tests { let test = Rect::new(0.0, 0.0, 1.0, 1.0); assert!((test.aspect_ratio() - 1.0).abs() < 1e-6); } + + #[test] + fn contained_rect_intersects() { + let outer = Rect::new(0.0, 0.0, 10.0, 10.0); + let inner = Rect::new(2.0, 2.0, 4.0, 4.0); + assert!(outer.intersects(inner)); + } + + #[test] + fn overlapping_rect_intersects() { + let a = Rect::new(0.0, 0.0, 10.0, 10.0); + let b = Rect::new(5.0, 5.0, 15.0, 15.0); + assert!(a.intersects(b)); + } + + #[test] + fn disjoint_rect_intersects() { + let a = Rect::new(0.0, 0.0, 10.0, 10.0); + let b = Rect::new(11.0, 11.0, 15.0, 15.0); + assert!(!a.intersects(b)); + } + + // Test the two other directions in case there is a bug that only appears in one direction. + #[test] + fn disjoint_rect_intersects_negative() { + let a = Rect::new(0.0, 0.0, 10.0, 10.0); + let b = Rect::new(-10.0, -10.0, -5.0, -5.0); + assert!(!a.intersects(b)); + } + + #[test] + fn contained_rectangle_contains() { + let outer = Rect::new(0.0, 0.0, 10.0, 10.0); + let inner = Rect::new(2.0, 2.0, 4.0, 4.0); + assert!(outer.contains_rect(inner)); + } + + #[test] + fn overlapping_rectangle_contains() { + let outer = Rect::new(0.0, 0.0, 10.0, 10.0); + let inner = Rect::new(5.0, 5.0, 15.0, 15.0); + assert!(!outer.contains_rect(inner)); + } + + #[test] + fn disjoint_rectangle_contains() { + let outer = Rect::new(0.0, 0.0, 10.0, 10.0); + let inner = Rect::new(11.0, 11.0, 15.0, 15.0); + assert!(!outer.contains_rect(inner)); + } } From 66f93ab596b599c28dbbd934d7238a75c911864f Mon Sep 17 00:00:00 2001 From: Nils Date: Sun, 26 May 2024 00:17:39 +0200 Subject: [PATCH 3/5] renamed `Rect::intersects` into `Rect::overlaps` --- src/rect.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/rect.rs b/src/rect.rs index 5ea7ed7e..94bfbd9d 100644 --- a/src/rect.rs +++ b/src/rect.rs @@ -224,9 +224,9 @@ impl Rect { /// height. The result always has non-negative width and height. /// /// If you want to determine whether two rectangles intersect, use the - /// [`intersects`] method instead. + /// [`overlaps`] method instead. /// - /// [`intersects`]: Rect::intersects + /// [`overlaps`]: Rect::overlaps #[inline] pub fn intersect(&self, other: Rect) -> Rect { let x0 = self.x0.max(other.x0); @@ -252,10 +252,10 @@ impl Rect { /// /// let rect1 = Rect::new(0.0, 0.0, 10.0, 10.0); /// let rect2 = Rect::new(5.0, 5.0, 15.0, 15.0); - /// assert!(rect1.intersects(rect2)); + /// assert!(rect1.overlaps(rect2)); /// ``` #[inline] - pub fn intersects(&self, other: Rect) -> bool { + pub fn overlaps(&self, other: Rect) -> bool { self.x0 < other.x1 && self.x1 > other.x0 && self.y0 < other.y1 && self.y1 > other.y0 } @@ -826,32 +826,32 @@ mod tests { } #[test] - fn contained_rect_intersects() { + fn contained_rect_overlaps() { let outer = Rect::new(0.0, 0.0, 10.0, 10.0); let inner = Rect::new(2.0, 2.0, 4.0, 4.0); - assert!(outer.intersects(inner)); + assert!(outer.overlaps(inner)); } #[test] - fn overlapping_rect_intersects() { + fn overlapping_rect_overlaps() { let a = Rect::new(0.0, 0.0, 10.0, 10.0); let b = Rect::new(5.0, 5.0, 15.0, 15.0); - assert!(a.intersects(b)); + assert!(a.overlaps(b)); } #[test] - fn disjoint_rect_intersects() { + fn disjoint_rect_overlaps() { let a = Rect::new(0.0, 0.0, 10.0, 10.0); let b = Rect::new(11.0, 11.0, 15.0, 15.0); - assert!(!a.intersects(b)); + assert!(!a.overlaps(b)); } // Test the two other directions in case there is a bug that only appears in one direction. #[test] - fn disjoint_rect_intersects_negative() { + fn disjoint_rect_overlaps_negative() { let a = Rect::new(0.0, 0.0, 10.0, 10.0); let b = Rect::new(-10.0, -10.0, -5.0, -5.0); - assert!(!a.intersects(b)); + assert!(!a.overlaps(b)); } #[test] From 4e85e6db5c16f7900b1b48c5b7b0515f46e63afc Mon Sep 17 00:00:00 2001 From: Nils Date: Sat, 15 Jun 2024 15:35:47 +0200 Subject: [PATCH 4/5] indicate that sharing and edge means overlap + add a test for that --- src/rect.rs | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/rect.rs b/src/rect.rs index 94bfbd9d..eeeb4aa3 100644 --- a/src/rect.rs +++ b/src/rect.rs @@ -236,14 +236,17 @@ impl Rect { Rect::new(x0, y0, x1.max(x0), y1.max(y0)) } - /// Determines whether the this rectangle intersects with another in any way. + /// Determines whether this rectangle overlaps with another in any way. /// - /// Returns `true` if the rectangles intersect, `false` otherwise. + /// Note that the edge of the rectangle is considered to be part of itself, meaning + /// that two rectangles that share an edge are considered to overlap. + /// + /// Returns `true` if the rectangles overlap, `false` otherwise. /// /// If you want to compute the *intersection* of two rectangles, use the /// [`intersect`] method instead. /// - /// [`intersect`]: Rect::intersects + /// [`intersect`]: Rect::intersect /// /// # Examples /// @@ -253,10 +256,14 @@ impl Rect { /// let rect1 = Rect::new(0.0, 0.0, 10.0, 10.0); /// let rect2 = Rect::new(5.0, 5.0, 15.0, 15.0); /// assert!(rect1.overlaps(rect2)); + /// + /// let rect1 = Rect::new(0.0, 0.0, 10.0, 10.0); + /// let rect2 = Rect::new(10.0, 0.0, 20.0, 10.0); + /// assert!(rect1.overlaps(rect2)); /// ``` #[inline] pub fn overlaps(&self, other: Rect) -> bool { - self.x0 < other.x1 && self.x1 > other.x0 && self.y0 < other.y1 && self.y1 > other.y0 + self.x0 <= other.x1 && self.x1 >= other.x0 && self.y0 <= other.y1 && self.y1 >= other.y0 } /// Returns whether this rectangle contains another rectangle. @@ -846,6 +853,13 @@ mod tests { assert!(!a.overlaps(b)); } + #[test] + fn sharing_edge_overlaps() { + let a = Rect::new(0.0, 0.0, 10.0, 10.0); + let b = Rect::new(10.0, 0.0, 20.0, 10.0); + assert!(a.overlaps(b)); + } + // Test the two other directions in case there is a bug that only appears in one direction. #[test] fn disjoint_rect_overlaps_negative() { From 4b96c3c5a751ae87baa0956eba81dad4c98e09fa Mon Sep 17 00:00:00 2001 From: Nils Date: Fri, 2 Aug 2024 20:17:41 +0200 Subject: [PATCH 5/5] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f2e1e929..b344df0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ This release has an [MSRV][] of 1.65. ### Added - Add `From (f32, f32)` for `Point`. ([#339] by [@rsheeter]) +- Add `Rect::overlaps` and `Rect::contains_rect`. ([#347] by [@nils-mathieu]) ### Changed @@ -35,6 +36,7 @@ This release has an [MSRV][] of 1.65. Note: A changelog was not kept for or before this release +[@nils-mathieu]: https://github.com/nils-mathieu [@platlas]: https://github.com/platlas [@raphlinus]: https://github.com/raphlinus [@rsheeter]: https://github.com/rsheeter @@ -45,6 +47,7 @@ Note: A changelog was not kept for or before this release [#339]: https://github.com/linebender/kurbo/pull/339 [#340]: https://github.com/linebender/kurbo/pull/340 [#343]: https://github.com/linebender/kurbo/pull/343 +[#347]: https://github.com/linebender/kurbo/pull/347 [#354]: https://github.com/linebender/kurbo/pull/354 [Unreleased]: https://github.com/linebender/kurbo/compare/v0.11.0...HEAD