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 <jondolf.dev@gmail.com>
Co-authored-by: James Liu <contact@jamessliu.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
This commit is contained in:
TheBigCheese 2024-09-30 19:44:49 +01:00 committed by GitHub
parent c5742ff43e
commit 01dce4742f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 35 additions and 2 deletions

View file

@ -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);

View file

@ -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);