From c2da611018267027035724cbaa9e69546573765c Mon Sep 17 00:00:00 2001 From: Jan Haller Date: Thu, 2 Jan 2025 13:12:32 +0100 Subject: [PATCH 1/4] Aabb, Rect2: rename has_point() -> contains_point() --- godot-core/src/builtin/aabb.rs | 14 +++++++++++--- godot-core/src/builtin/rect2.rs | 9 ++++++++- .../rust/src/builtin_tests/geometry/rect2_test.rs | 2 +- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/godot-core/src/builtin/aabb.rs b/godot-core/src/builtin/aabb.rs index 3d7dd4337..fdad7af12 100644 --- a/godot-core/src/builtin/aabb.rs +++ b/godot-core/src/builtin/aabb.rs @@ -128,13 +128,15 @@ impl Aabb { Self { position, size } } - /// Returns `true` if the AABB contains a point. By convention, - /// the right and bottom edges of the AABB are considered exclusive, so points on these edges are not included. + /// Returns `true` if the AABB contains a point (excluding right/bottom edge). + /// + /// By convention, the right and bottom edges of the AABB are considered exclusive, so points on these edges are not included. /// /// # Panics /// If `self.size` is negative. #[inline] - pub fn has_point(self, point: Vector3) -> bool { + #[doc(alias = "has_point")] + pub fn contains_point(self, point: Vector3) -> bool { self.assert_nonnegative(); let point = point - self.position; @@ -145,6 +147,12 @@ impl Aabb { && point.z < self.size.z } + #[inline] + #[deprecated = "Renamed to `contains_point()`, for consistency with `Rect2i`"] + pub fn has_point(self, point: Vector3) -> bool { + self.contains_point(point) + } + /// Returns `true` if the AABB has area, and `false` if the AABB is linear, empty, or has a negative size. See also `Aabb.area()`. #[inline] pub fn has_area(self) -> bool { diff --git a/godot-core/src/builtin/rect2.rs b/godot-core/src/builtin/rect2.rs index 1ab84f68a..cf73734ff 100644 --- a/godot-core/src/builtin/rect2.rs +++ b/godot-core/src/builtin/rect2.rs @@ -181,12 +181,19 @@ impl Rect2 { /// /// Note: This method is not reliable for Rect2 with a negative size. Use `abs` to get a positive sized equivalent rectangle to check for contained points. #[inline] - pub fn has_point(self, point: Vector2) -> bool { + #[doc(alias = "has_point")] + pub fn contains_point(self, point: Vector2) -> bool { let point = point - self.position; point.abs() == point && point.x < self.size.x && point.y < self.size.y } + #[inline] + #[deprecated = "Renamed to `contains_point()`, for consistency with `Rect2i`"] + pub fn has_point(self, point: Vector2) -> bool { + self.contains_point(point) + } + /// Returns the intersection of this Rect2 and `b`. If the rectangles do not intersect, an empty Rect2 is returned. #[inline] pub fn intersection(self, b: Self) -> Option { diff --git a/itest/rust/src/builtin_tests/geometry/rect2_test.rs b/itest/rust/src/builtin_tests/geometry/rect2_test.rs index e704bfd29..d7f11c6db 100644 --- a/itest/rust/src/builtin_tests/geometry/rect2_test.rs +++ b/itest/rust/src/builtin_tests/geometry/rect2_test.rs @@ -56,7 +56,7 @@ fn rect2_inner_equivalence() { for vec in vectors { assert_eq_approx!(rect.expand(vec), inner_rect.expand(vec)); - assert_eq!(rect.has_point(vec), inner_rect.has_point(vec)); + assert_eq!(rect.contains_point(vec), inner_rect.has_point(vec)); } for grow in grow_values { From 54bf0535204310a324c8de1ca237564a5ed6b8ad Mon Sep 17 00:00:00 2001 From: Jan Haller Date: Thu, 2 Jan 2025 13:35:14 +0100 Subject: [PATCH 2/4] Aabb: replace has_area() -> has_surface() --- godot-core/src/builtin/aabb.rs | 13 +++++++++++-- godot-core/src/builtin/rect2.rs | 4 +++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/godot-core/src/builtin/aabb.rs b/godot-core/src/builtin/aabb.rs index fdad7af12..8dae03637 100644 --- a/godot-core/src/builtin/aabb.rs +++ b/godot-core/src/builtin/aabb.rs @@ -153,8 +153,15 @@ impl Aabb { self.contains_point(point) } - /// Returns `true` if the AABB has area, and `false` if the AABB is linear, empty, or has a negative size. See also `Aabb.area()`. + /// Returns if this bounding box has a surface or a length, i.e. at least one component of [`Self::size`] is greater than 0. #[inline] + pub fn has_surface(self) -> bool { + (self.size.x > 0.0) || (self.size.y > 0.0) || (self.size.z > 0.0) + } + + /// Returns true if at least one of the size's components (X, Y, Z) is greater than 0. + #[inline] + #[deprecated = "Replaced with `has_surface()`, which has different semantics"] pub fn has_area(self) -> bool { ((self.size.x > 0.0) as u8 + (self.size.y > 0.0) as u8 + (self.size.z > 0.0) as u8) >= 2 } @@ -226,7 +233,8 @@ impl Aabb { /// Returns the scalar length of the longest axis of the AABB. #[inline] pub fn longest_axis_size(self) -> real { - self.size.x.max(self.size.y.max(self.size.z)) + let size = self.size; + size.x.max(size.y).max(size.z) } /// Returns the normalized shortest axis of the AABB. @@ -253,6 +261,7 @@ impl Aabb { /// Returns the support point in a given direction. This is useful for collision detection algorithms. #[inline] + #[doc(alias = "get_support")] pub fn support(self, dir: Vector3) -> Vector3 { let half_extents = self.size * 0.5; let relative_center_point = self.position + half_extents; diff --git a/godot-core/src/builtin/rect2.rs b/godot-core/src/builtin/rect2.rs index cf73734ff..b29723dd3 100644 --- a/godot-core/src/builtin/rect2.rs +++ b/godot-core/src/builtin/rect2.rs @@ -177,7 +177,9 @@ impl Rect2 { self.size.x > 0.0 && self.size.y > 0.0 } - /// Returns `true` if the Rect2 contains a point. By convention, the right and bottom edges of the Rect2 are considered exclusive, so points on these edges are not included. + /// Returns `true` if the Rect2 contains a point (excluding right/bottom edges). + /// + /// By convention, the right and bottom edges of the Rect2 are considered exclusive, so points on these edges are not included. /// /// Note: This method is not reliable for Rect2 with a negative size. Use `abs` to get a positive sized equivalent rectangle to check for contained points. #[inline] From e2c95c3d5879a56053e7685a6e217fc3b947a2cb Mon Sep 17 00:00:00 2001 From: Jan Haller Date: Wed, 15 Jan 2025 23:09:55 +0100 Subject: [PATCH 3/4] Aabb: add intersect_ray() + lots of extra tests --- godot-core/src/builtin/aabb.rs | 265 ++++++++++++++++++++++++++++++++- 1 file changed, 257 insertions(+), 8 deletions(-) diff --git a/godot-core/src/builtin/aabb.rs b/godot-core/src/builtin/aabb.rs index 8dae03637..208d4f0d0 100644 --- a/godot-core/src/builtin/aabb.rs +++ b/godot-core/src/builtin/aabb.rs @@ -344,22 +344,56 @@ impl Aabb { /// Returns `true` if the given ray intersects with this AABB. Ray length is infinite. /// - /// # Panics + /// Semantically equivalent to `self.intersects_ray(ray_from, ray_dir).is_some()`; might be microscopically faster. + /// + /// # Panics (Debug) /// If `self.size` is negative. #[inline] - pub fn intersects_ray(self, from: Vector3, dir: Vector3) -> bool { + pub fn intersects_ray(self, ray_from: Vector3, ray_dir: Vector3) -> bool { + let (tnear, tfar) = self.compute_ray_tnear_tfar(ray_from, ray_dir); + + tnear <= tfar + } + + /// Returns the point where the given (infinite) ray intersects with this AABB, or `None` if there is no intersection. + /// + /// # Panics (Debug) + /// If `self.size` is negative, or if `ray_dir` is zero. Note that this differs from Godot, which treats rays that degenerate to points as + /// intersecting if inside, and not if outside the AABB. + #[inline] + pub fn intersect_ray(self, ray_from: Vector3, ray_dir: Vector3) -> Option { + let (tnear, tfar) = self.compute_ray_tnear_tfar(ray_from, ray_dir); + + if tnear <= tfar { + // if tnear < 0: the ray starts inside the box -> take other intersection point. + let t = if tnear < 0.0 { tfar } else { tnear }; + Some(ray_from + ray_dir * t) + } else { + None + } + } + + // Credits: https://tavianator.com/2011/ray_box.html + fn compute_ray_tnear_tfar(self, ray_from: Vector3, ray_dir: Vector3) -> (real, real) { self.assert_nonnegative(); + debug_assert!( + ray_dir != Vector3::ZERO, + "ray direction must not be zero; use contains_point() for point checks" + ); - let tmin = (self.position - from) / dir; - let tmax = (self.end() - from) / dir; + // Note: leads to -inf/inf for each component that is 0. This should generally balance out, unless all are zero. + let recip_dir = ray_dir.recip(); + + let tmin = (self.position - ray_from) * recip_dir; + let tmax = (self.end() - ray_from) * recip_dir; let t1 = tmin.coord_min(tmax); let t2 = tmin.coord_max(tmax); let tnear = t1.x.max(t1.y).max(t1.z); - let tfar = t2.y.min(t2.x).min(t2.z); + let tfar = t2.x.min(t2.y).min(t2.z); - tnear <= tfar + (tnear, tfar) } /// Returns `true` if the given ray intersects with this AABB. Segment length is finite. @@ -571,6 +605,7 @@ mod test { }; let from1 = Vector3::new(1.0, 1.0, -1.0); let dir1 = Vector3::new(0.0, 0.0, 1.0); + assert!(aabb1.intersects_ray(from1, dir1)); // Test case 2: Ray misses the AABB @@ -619,15 +654,159 @@ mod test { assert!(aabb6.intersects_ray(from6, dir6)); } + #[test] // Ported from Godot tests. + fn test_intersect_ray_2() { + let aabb = Aabb { + position: Vector3::new(-1.5, 2.0, -2.5), + size: Vector3::new(4.0, 5.0, 6.0), + }; + + assert_eq!( + aabb.intersect_ray(Vector3::new(-100.0, 3.0, 0.0), Vector3::new(1.0, 0.0, 0.0)), + Some(Vector3::new(-1.5, 3.0, 0.0)), + "intersect_ray(), ray points directly at AABB -> Some" + ); + + assert_eq!( + aabb.intersect_ray(Vector3::new(10.0, 10.0, 0.0), Vector3::new(0.0, 1.0, 0.0)), + None, + "intersect_ray(), ray parallel and outside the AABB -> None" + ); + + assert_eq!( + aabb.intersect_ray(Vector3::ONE, Vector3::new(0.0, 1.0, 0.0)), + Some(Vector3::new(1.0, 2.0, 1.0)), + "intersect_ray(), ray originating inside the AABB -> Some" + ); + + assert_eq!( + aabb.intersect_ray(Vector3::new(-10.0, 0.0, 0.0), Vector3::new(-1.0, 0.0, 0.0)), + None, + "intersect_ray(), ray points away from AABB -> None" + ); + + assert_eq!( + aabb.intersect_ray(Vector3::new(0.0, 0.0, 0.0), Vector3::ONE), + Some(Vector3::new(2.0, 2.0, 2.0)), + "intersect_ray(), ray along the AABB diagonal -> Some" + ); + + assert_eq!( + aabb.intersect_ray( + aabb.position + Vector3::splat(0.0001), + Vector3::new(-1.0, 0.0, 0.0) + ), + Some(Vector3::new(-1.5, 2.0001, -2.4999)), + "intersect_ray(), ray starting on the AABB's edge -> Some" + ); + + assert_eq!( + aabb.intersect_ray(Vector3::new(0.0, 0.0, 0.0), Vector3::new(0.0, 1.0, 0.0)), + Some(Vector3::new(0.0, 2.0, 0.0)), + "intersect_ray(): ray has 2 axes parallel to AABB -> Some" + ); + } + + #[test] // Ported from Godot tests. + fn test_intersect_aabb() { + let aabb_big = Aabb { + position: Vector3::new(-1.5, 2.0, -2.5), + size: Vector3::new(4.0, 5.0, 6.0), + }; + + let aabb_small = Aabb { + position: Vector3::new(-1.5, 2.0, -2.5), + size: Vector3::ONE, + }; + assert!( + aabb_big.intersects(aabb_small), + "intersects() with fully contained AABB (touching the edge) should return true." + ); + + let aabb_small = Aabb { + position: Vector3::new(0.5, 1.5, -2.0), + size: Vector3::ONE, + }; + assert!( + aabb_big.intersects(aabb_small), + "intersects() with partially contained AABB (overflowing on Y axis) should return true." + ); + + let aabb_small = Aabb { + position: Vector3::new(10.0, -10.0, -10.0), + size: Vector3::ONE, + }; + assert!( + !aabb_big.intersects(aabb_small), + "intersects() with non-contained AABB should return false." + ); + + let aabb_small = Aabb { + position: Vector3::new(-1.5, 2.0, -2.5), + size: Vector3::ONE, + }; + let inter = aabb_big.intersection(aabb_small); + assert!( + inter.unwrap().approx_eq(&aabb_small), + "intersection() with fully contained AABB should return the smaller AABB." + ); + + let aabb_small = Aabb { + position: Vector3::new(0.5, 1.5, -2.0), + size: Vector3::ONE, + }; + let expected = Aabb { + position: Vector3::new(0.5, 2.0, -2.0), + size: Vector3::new(1.0, 0.5, 1.0), + }; + let inter = aabb_big.intersection(aabb_small); + assert!( + inter.unwrap().approx_eq(&expected), + "intersect() with partially contained AABB (overflowing on Y axis) should match expected." + ); + + let aabb_small = Aabb { + position: Vector3::new(10.0, -10.0, -10.0), + size: Vector3::ONE, + }; + let inter = aabb_big.intersection(aabb_small); + assert!( + inter.is_none(), + "intersect() with non-contained AABB should return None." + ); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn test_intersect_ray_zero_dir_inside() { + let aabb = Aabb { + position: Vector3::new(-1.5, 2.0, -2.5), + size: Vector3::new(4.0, 5.0, 6.0), + }; + + aabb.intersect_ray(Vector3::new(-1.0, 3.0, -2.0), Vector3::ZERO); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn test_intersect_ray_zero_dir_outside() { + let aabb = Aabb { + position: Vector3::new(-1.5, 2.0, -2.5), + size: Vector3::new(4.0, 5.0, 6.0), + }; + + aabb.intersect_ray(Vector3::new(-1000.0, 3.0, -2.0), Vector3::ZERO); + } + #[test] fn test_intersects_plane() { - // Create an AABB let aabb = Aabb { position: Vector3::new(-1.0, -1.0, -1.0), size: Vector3::new(2.0, 2.0, 2.0), }; - // Define planes for testing let plane_inside = Plane { normal: Vector3::new(1.0, 0.0, 0.0), d: 0.0, @@ -655,6 +834,32 @@ mod test { assert!(!aabb.intersects_plane(plane_parallel)); } + #[test] // Ported from Godot tests. + fn test_intersects_plane_2() { + let aabb_big = Aabb { + position: Vector3::new(-1.5, 2.0, -2.5), + size: Vector3::new(4.0, 5.0, 6.0), + }; + + let plane1 = Plane::new(Vector3::new(0.0, 1.0, 0.0), 4.0); + assert!( + aabb_big.intersects_plane(plane1), + "intersects_plane() should return true (plane near top)." + ); + + let plane2 = Plane::new(Vector3::new(0.0, -1.0, 0.0), -4.0); + assert!( + aabb_big.intersects_plane(plane2), + "intersects_plane() should return true (plane near bottom)." + ); + + let plane3 = Plane::new(Vector3::new(0.0, 1.0, 0.0), 200.0); + assert!( + !aabb_big.intersects_plane(plane3), + "intersects_plane() should return false (plane far away)." + ); + } + #[test] fn test_aabb_intersects_segment() { let aabb = Aabb { @@ -672,4 +877,48 @@ mod test { let to = Vector3::new(-1.0, 1.0, 1.0); assert!(!aabb.intersects_segment(from, to)); } + + #[test] // Ported from Godot tests. + fn test_intersects_segment_2() { + let aabb = Aabb { + position: Vector3::new(-1.5, 2.0, -2.5), + size: Vector3::new(4.0, 5.0, 6.0), + }; + + // True cases. + assert!( + aabb.intersects_segment(Vector3::new(1.0, 3.0, 0.0), Vector3::new(0.0, 3.0, 0.0)), + "intersects_segment(), segment fully inside -> true" + ); + assert!( + aabb.intersects_segment(Vector3::new(0.0, 3.0, 0.0), Vector3::new(0.0, -300.0, 0.0)), + "intersects_segment(), segment crossing the box -> true" + ); + assert!( + aabb.intersects_segment( + Vector3::new(-50.0, 3.0, -50.0), + Vector3::new(50.0, 3.0, 50.0) + ), + "intersects_segment(), diagonal crossing the box -> true" + ); + + // False case. + assert!( + !aabb.intersects_segment( + Vector3::new(-50.0, 25.0, -50.0), + Vector3::new(50.0, 25.0, 50.0) + ), + "intersects_segment(), segment above the box -> false" + ); + + // Degenerate segments (points). + assert!( + aabb.intersects_segment(Vector3::new(0.0, 3.0, 0.0), Vector3::new(0.0, 3.0, 0.0)), + "intersects_segment(), segment of length 0 *inside* the box -> true" + ); + assert!( + !aabb.intersects_segment(Vector3::new(0.0, 300.0, 0.0), Vector3::new(0.0, 300.0, 0.0)), + "intersects_segment(), segment of length 0 *outside* the box -> false" + ); + } } From c77ea898f9c9a4aa00f222fdd5c0c2b210a27fc8 Mon Sep 17 00:00:00 2001 From: Jan Haller Date: Wed, 15 Jan 2025 23:24:06 +0100 Subject: [PATCH 4/4] Aabb, Rect2, Rect2i: rename intersection() -> intersect() --- godot-core/src/builtin/aabb.rs | 49 ++++++++++--------- godot-core/src/builtin/rect2.rs | 7 ++- godot-core/src/builtin/rect2i.rs | 21 +++++--- .../src/builtin_tests/geometry/rect2_test.rs | 2 +- .../src/builtin_tests/geometry/rect2i_test.rs | 4 +- 5 files changed, 49 insertions(+), 34 deletions(-) diff --git a/godot-core/src/builtin/aabb.rs b/godot-core/src/builtin/aabb.rs index 208d4f0d0..5289e8c50 100644 --- a/godot-core/src/builtin/aabb.rs +++ b/godot-core/src/builtin/aabb.rs @@ -174,10 +174,10 @@ impl Aabb { /// Returns the intersection between two AABBs. /// - /// # Panics + /// # Panics (Debug) /// If `self.size` is negative. #[inline] - pub fn intersection(self, b: Aabb) -> Option { + pub fn intersect(self, b: Aabb) -> Option { self.assert_nonnegative(); if !self.intersects(b) { @@ -194,6 +194,11 @@ impl Aabb { Some(rect) } + #[deprecated = "Renamed to `intersect()`"] + pub fn intersection(self, b: Aabb) -> Option { + self.intersect(b) + } + /// Returns `true` if this AABB is finite, by calling `@GlobalScope.is_finite` on each component. #[inline] pub fn is_finite(self) -> bool { @@ -434,6 +439,7 @@ impl Aabb { /// /// Most functions will fail to give a correct result if the size is negative. #[inline] + /// TODO(v0.3): make private, change to debug_assert(). pub fn assert_nonnegative(self) { assert!( self.size.x >= 0.0 && self.size.y >= 0.0 && self.size.z >= 0.0, @@ -529,27 +535,27 @@ mod test { size: Vector3::new(1.0, 1.0, 1.0), }; - // Check for intersection including border + // Check for intersection including border. assert!(aabb1.intersects(aabb2)); assert!(aabb2.intersects(aabb1)); - // Check for non-intersection including border + // Check for non-intersection including border. assert!(!aabb1.intersects(aabb3)); assert!(!aabb3.intersects(aabb1)); - // Check for intersection excluding border + // Check for intersection excluding border. assert!(aabb1.intersects_exclude_borders(aabb2)); assert!(aabb2.intersects_exclude_borders(aabb1)); - // Check for non-intersection excluding border + // Check for non-intersection excluding border. assert!(!aabb1.intersects_exclude_borders(aabb3)); assert!(!aabb3.intersects_exclude_borders(aabb1)); - // Check for non-intersection excluding border + // Check for non-intersection excluding border. assert!(!aabb1.intersects_exclude_borders(aabb4)); assert!(!aabb4.intersects_exclude_borders(aabb1)); - // Check for intersection with same AABB including border + // Check for intersection with same AABB including border. assert!(aabb1.intersects(aabb1)); } @@ -576,19 +582,18 @@ mod test { size: Vector3::new(1.0, 1.0, 1.0), }; - // Test cases assert_eq!( - aabb1.intersection(aabb2), + aabb1.intersect(aabb2), Some(Aabb { position: Vector3::new(1.0, 1.0, 1.0), size: Vector3::new(1.0, 1.0, 1.0), }) ); - assert_eq!(aabb1.intersection(aabb3), None); + assert_eq!(aabb1.intersect(aabb3), None); assert_eq!( - aabb1.intersection(aabb4), + aabb1.intersect(aabb4), Some(Aabb { position: Vector3::new(0.0, 0.0, 0.0), size: Vector3::new(0.0, 0.0, 0.0), @@ -598,7 +603,7 @@ mod test { #[test] fn test_intersects_ray() { - // Test case 1: Ray intersects the AABB + // Test case 1: Ray intersects the AABB. let aabb1 = Aabb { position: Vector3::new(0.0, 0.0, 0.0), size: Vector3::new(2.0, 2.0, 2.0), @@ -608,7 +613,7 @@ mod test { assert!(aabb1.intersects_ray(from1, dir1)); - // Test case 2: Ray misses the AABB + // Test case 2: Ray misses the AABB. let aabb2 = Aabb { position: Vector3::new(0.0, 0.0, 0.0), size: Vector3::new(2.0, 2.0, 2.0), @@ -617,7 +622,7 @@ mod test { let dir2 = Vector3::new(0.0, 0.0, 1.0); assert!(!aabb2.intersects_ray(from2, dir2)); - // Test case 3: Ray starts inside the AABB + // Test case 3: Ray starts inside the AABB. let aabb3 = Aabb { position: Vector3::new(0.0, 0.0, 0.0), size: Vector3::new(2.0, 2.0, 2.0), @@ -626,7 +631,7 @@ mod test { let dir3 = Vector3::new(0.0, 0.0, 1.0); assert!(aabb3.intersects_ray(from3, dir3)); - // Test case 4: Ray direction parallel to AABB + // Test case 4: Ray direction parallel to AABB. let aabb4 = Aabb { position: Vector3::new(0.0, 0.0, 0.0), size: Vector3::new(2.0, 2.0, 2.0), @@ -635,7 +640,7 @@ mod test { let dir4 = Vector3::new(1.0, 0.0, 0.0); assert!(aabb4.intersects_ray(from4, dir4)); - // Test case 5: Ray direction diagonal through the AABB + // Test case 5: Ray direction diagonal through the AABB. let aabb5 = Aabb { position: Vector3::new(0.0, 0.0, 0.0), size: Vector3::new(2.0, 2.0, 2.0), @@ -644,7 +649,7 @@ mod test { let dir5 = Vector3::new(1.0, 1.0, 1.0); assert!(aabb5.intersects_ray(from5, dir5)); - // Test case 6: Ray origin on an AABB face + // Test case 6: Ray origin on an AABB face. let aabb6 = Aabb { position: Vector3::new(0.0, 0.0, 0.0), size: Vector3::new(2.0, 2.0, 2.0), @@ -745,10 +750,10 @@ mod test { position: Vector3::new(-1.5, 2.0, -2.5), size: Vector3::ONE, }; - let inter = aabb_big.intersection(aabb_small); + let inter = aabb_big.intersect(aabb_small); assert!( inter.unwrap().approx_eq(&aabb_small), - "intersection() with fully contained AABB should return the smaller AABB." + "intersect() with fully contained AABB should return the smaller AABB." ); let aabb_small = Aabb { @@ -759,7 +764,7 @@ mod test { position: Vector3::new(0.5, 2.0, -2.0), size: Vector3::new(1.0, 0.5, 1.0), }; - let inter = aabb_big.intersection(aabb_small); + let inter = aabb_big.intersect(aabb_small); assert!( inter.unwrap().approx_eq(&expected), "intersect() with partially contained AABB (overflowing on Y axis) should match expected." @@ -769,7 +774,7 @@ mod test { position: Vector3::new(10.0, -10.0, -10.0), size: Vector3::ONE, }; - let inter = aabb_big.intersection(aabb_small); + let inter = aabb_big.intersect(aabb_small); assert!( inter.is_none(), "intersect() with non-contained AABB should return None." diff --git a/godot-core/src/builtin/rect2.rs b/godot-core/src/builtin/rect2.rs index b29723dd3..8bbd06878 100644 --- a/godot-core/src/builtin/rect2.rs +++ b/godot-core/src/builtin/rect2.rs @@ -198,7 +198,7 @@ impl Rect2 { /// Returns the intersection of this Rect2 and `b`. If the rectangles do not intersect, an empty Rect2 is returned. #[inline] - pub fn intersection(self, b: Self) -> Option { + pub fn intersect(self, b: Self) -> Option { if !self.intersects(b) { return None; } @@ -213,6 +213,11 @@ impl Rect2 { Some(rect) } + #[deprecated = "Renamed to `intersect()`"] + pub fn intersection(self, b: Rect2) -> Option { + self.intersect(b) + } + /// Checks whether two rectangles have at least one point in common. /// /// Also returns `true` if the rects only touch each other (share a point/edge). diff --git a/godot-core/src/builtin/rect2i.rs b/godot-core/src/builtin/rect2i.rs index 029195db9..c4e67ff29 100644 --- a/godot-core/src/builtin/rect2i.rs +++ b/godot-core/src/builtin/rect2i.rs @@ -223,7 +223,7 @@ impl Rect2i { /// /// Note that rectangles that only share a border do not intersect. #[inline] - pub fn intersection(self, b: Self) -> Option { + pub fn intersect(self, b: Self) -> Option { self.assert_nonnegative(); b.assert_nonnegative(); @@ -243,11 +243,16 @@ impl Rect2i { Some(Self::from_corners(new_pos, new_end)) } + #[deprecated = "Renamed to `intersect()`"] + pub fn intersection(self, b: Self) -> Option { + self.intersect(b) + } + /// Returns `true` if the `Rect2i` overlaps with `b` (i.e. they have at least one /// point in common) #[inline] pub fn intersects(self, b: Self) -> bool { - self.intersection(b).is_some() + self.intersect(b).is_some() } /// Returns a larger `Rect2i` that contains this `Rect2i` and `b`. @@ -554,19 +559,19 @@ mod test { let d = Rect2i::from_components(8, 8, 2, 3); assert!(a.intersects(b)); - assert_eq!(a.intersection(b), Some(b)); + assert_eq!(a.intersect(b), Some(b)); assert!(a.intersects(c)); - assert_eq!(a.intersection(c), Some(c)); + assert_eq!(a.intersect(c), Some(c)); assert!(a.intersects(d)); - assert_eq!(a.intersection(d), Some(c)); + assert_eq!(a.intersect(d), Some(c)); assert!(!b.intersects(c)); - assert_eq!(b.intersection(c), None); + assert_eq!(b.intersect(c), None); assert!(!b.intersects(d)); - assert_eq!(b.intersection(d), None); + assert_eq!(b.intersect(d), None); assert!(c.intersects(d)); - assert_eq!(c.intersection(d), Some(c)); + assert_eq!(c.intersect(d), Some(c)); } #[test] diff --git a/itest/rust/src/builtin_tests/geometry/rect2_test.rs b/itest/rust/src/builtin_tests/geometry/rect2_test.rs index d7f11c6db..84a81445f 100644 --- a/itest/rust/src/builtin_tests/geometry/rect2_test.rs +++ b/itest/rust/src/builtin_tests/geometry/rect2_test.rs @@ -48,7 +48,7 @@ fn rect2_inner_equivalence() { inner_rect.intersects(other, false), ); assert_eq!( - rect.intersection(other).unwrap_or_default(), + rect.intersect(other).unwrap_or_default(), inner_rect.intersection(other), ); assert_eq_approx!(rect.merge(other), inner_rect.merge(other)); diff --git a/itest/rust/src/builtin_tests/geometry/rect2i_test.rs b/itest/rust/src/builtin_tests/geometry/rect2i_test.rs index 7d14d9b3f..af61747f8 100644 --- a/itest/rust/src/builtin_tests/geometry/rect2i_test.rs +++ b/itest/rust/src/builtin_tests/geometry/rect2i_test.rs @@ -50,8 +50,8 @@ fn rect2i_equiv_unary() { evaluate_mappings("encloses", a.encloses(b), inner_a.encloses(b)); evaluate_mappings("intersects", a.intersects(b), inner_a.intersects(b)); evaluate_mappings( - "intersection", - a.intersection(b).unwrap_or_default(), + "intersect", + a.intersect(b).unwrap_or_default(), inner_a.intersection(b), ); evaluate_mappings("merge", a.merge(b), inner_a.merge(b));