From 01dce4742f77a572a1ef21ce8f64ce3b6d2328a8 Mon Sep 17 00:00:00 2001 From: TheBigCheese <32036861+13ros27@users.noreply.github.com> Date: Mon, 30 Sep 2024 19:44:49 +0100 Subject: [PATCH] Add `to_inner_rectangle`, `area` and `perimeter` methods to `Capsule2d` (#15388) # Objective Unlike `Capsule3d` which has the `.to_cylinder` method, `Capsule2d` doesn't have an equivalent `.to_inner_rectangle` method and as shown by #15191 this is surprisingly easy to get wrong ## Solution Implemented a `Capsule2d::to_inner_rectangle` method as it is implemented in the fixed `Capsule2d` shape sampling, and as I was adding tests I noticed `Capsule2d` didn't implement `Measure2d` so I did this as well. ## Changelog ### Added - `Capsule2d::to_inner_rectangle`, `Capsule2d::area` and `Capsule2d::perimeter` --------- Co-authored-by: Joona Aalto Co-authored-by: James Liu Co-authored-by: Alice Cecile --- crates/bevy_math/src/primitives/dim2.rs | 34 +++++++++++++++++++ .../bevy_math/src/sampling/shape_sampling.rs | 3 +- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/crates/bevy_math/src/primitives/dim2.rs b/crates/bevy_math/src/primitives/dim2.rs index 6e44d8bc04..597fe8e891 100644 --- a/crates/bevy_math/src/primitives/dim2.rs +++ b/crates/bevy_math/src/primitives/dim2.rs @@ -1817,6 +1817,28 @@ impl Capsule2d { half_length: length / 2.0, } } + + /// Get the part connecting the semicircular ends of the capsule as a [`Rectangle`] + #[inline] + pub fn to_inner_rectangle(&self) -> Rectangle { + Rectangle::new(self.radius * 2.0, self.half_length * 2.0) + } +} + +impl Measured2d for Capsule2d { + /// Get the area of the capsule + #[inline] + fn area(&self) -> f32 { + // pi*r^2 + (2r)*l + PI * self.radius.squared() + self.to_inner_rectangle().area() + } + + /// Get the perimeter of the capsule + #[inline] + fn perimeter(&self) -> f32 { + // 2pi*r + 2l + 2.0 * PI * self.radius + 4.0 * self.half_length + } } #[cfg(test)] @@ -1892,6 +1914,18 @@ mod tests { assert_eq!(circle.perimeter(), 18.849556, "incorrect perimeter"); } + #[test] + fn capsule_math() { + let capsule = Capsule2d::new(2.0, 9.0); + assert_eq!( + capsule.to_inner_rectangle(), + Rectangle::new(4.0, 9.0), + "rectangle wasn't created correctly from a capsule" + ); + assert_eq!(capsule.area(), 48.566371, "incorrect area"); + assert_eq!(capsule.perimeter(), 30.566371, "incorrect perimeter"); + } + #[test] fn annulus_math() { let annulus = Annulus::new(2.5, 3.5); diff --git a/crates/bevy_math/src/sampling/shape_sampling.rs b/crates/bevy_math/src/sampling/shape_sampling.rs index 7e8c672a6b..e1fb0aef7d 100644 --- a/crates/bevy_math/src/sampling/shape_sampling.rs +++ b/crates/bevy_math/src/sampling/shape_sampling.rs @@ -450,8 +450,7 @@ impl ShapeSample for Capsule2d { if capsule_area > 0.0 { // Check if the random point should be inside the rectangle if rng.gen_bool((rectangle_area / capsule_area) as f64) { - let rectangle = Rectangle::new(self.radius * 2.0, self.half_length * 2.0); - rectangle.sample_interior(rng) + self.to_inner_rectangle().sample_interior(rng) } else { let circle = Circle::new(self.radius); let point = circle.sample_interior(rng);