Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
title: Bounded2d and Bounded3d signature change
pull_requests: [23623]
---

The signature of `Bounded2d` and `Bounded3d` has changed. All methods now
accept `Isometry2d` and `Isometry3d` objects, rather than `impl Into<IsometryXd>`
type argument.

The new signatures allow `Bounded2d` and `Bounded3d` to be dyn-compatible.

When calling `Bounded2d::aabb_2d`, `Bounded2d::bounding_circle`,
`Bounded3d::aabb_3d`, and `Bounded3d::bounding_sphere`, you may need to call
`into()` on the object sent to the function. e.g.,

```diff
- let aabb2d = self.aabb_2d(Rot2::radians(angle));
+ let aabb2d = self.aabb_2d(Rot2::radians(angle).into());
```

When implementing these traits for an object, you will need to update the signature.
You may also be able to remove `let isometry = isometry.into();` lines.
4 changes: 2 additions & 2 deletions crates/bevy_math/src/bounding/bounded2d/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ fn point_cloud_2d_center(points: &[Vec2]) -> Vec2 {
/// A trait with methods that return 2D bounding volumes for a shape.
pub trait Bounded2d {
/// Get an axis-aligned bounding box for the shape translated and rotated by the given isometry.
fn aabb_2d(&self, isometry: impl Into<Isometry2d>) -> Aabb2d;
fn aabb_2d(&self, isometry: Isometry2d) -> Aabb2d;
/// Get a bounding circle for the shape translated and rotated by the given isometry.
fn bounding_circle(&self, isometry: impl Into<Isometry2d>) -> BoundingCircle;
fn bounding_circle(&self, isometry: Isometry2d) -> BoundingCircle;
}

/// A 2D axis-aligned bounding box, or bounding rectangle
Expand Down
108 changes: 36 additions & 72 deletions crates/bevy_math/src/bounding/bounded2d/primitive_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,11 @@ use arrayvec::ArrayVec;
use super::{Aabb2d, Bounded2d, BoundingCircle};

impl Bounded2d for Circle {
fn aabb_2d(&self, isometry: impl Into<Isometry2d>) -> Aabb2d {
let isometry = isometry.into();
fn aabb_2d(&self, isometry: Isometry2d) -> Aabb2d {
Aabb2d::new(isometry.translation, Vec2::splat(self.radius))
}

fn bounding_circle(&self, isometry: impl Into<Isometry2d>) -> BoundingCircle {
let isometry = isometry.into();
fn bounding_circle(&self, isometry: Isometry2d) -> BoundingCircle {
BoundingCircle::new(isometry.translation, self.radius)
}
}
Expand Down Expand Up @@ -65,23 +63,19 @@ fn arc_bounding_points(arc: Arc2d, rotation: impl Into<Rot2>) -> ArrayVec<Vec2,
}

impl Bounded2d for Arc2d {
fn aabb_2d(&self, isometry: impl Into<Isometry2d>) -> Aabb2d {
fn aabb_2d(&self, isometry: Isometry2d) -> Aabb2d {
// If our arc covers more than a circle, just return the bounding box of the circle.
if self.half_angle >= PI {
return Circle::new(self.radius).aabb_2d(isometry);
}

let isometry = isometry.into();

Aabb2d::from_point_cloud(
Isometry2d::from_translation(isometry.translation),
&arc_bounding_points(*self, isometry.rotation),
)
}

fn bounding_circle(&self, isometry: impl Into<Isometry2d>) -> BoundingCircle {
let isometry = isometry.into();

fn bounding_circle(&self, isometry: Isometry2d) -> BoundingCircle {
// There are two possibilities for the bounding circle.
if self.is_major() {
// If the arc is major, then the widest distance between two points is a diameter of the arc's circle;
Expand All @@ -97,9 +91,7 @@ impl Bounded2d for Arc2d {
}

impl Bounded2d for CircularSector {
fn aabb_2d(&self, isometry: impl Into<Isometry2d>) -> Aabb2d {
let isometry = isometry.into();

fn aabb_2d(&self, isometry: Isometry2d) -> Aabb2d {
// If our sector covers more than a circle, just return the bounding box of the circle.
if self.half_angle() >= PI {
return Circle::new(self.radius()).aabb_2d(isometry);
Expand All @@ -112,10 +104,8 @@ impl Bounded2d for CircularSector {
Aabb2d::from_point_cloud(Isometry2d::from_translation(isometry.translation), &bounds)
}

fn bounding_circle(&self, isometry: impl Into<Isometry2d>) -> BoundingCircle {
fn bounding_circle(&self, isometry: Isometry2d) -> BoundingCircle {
if self.arc.is_major() {
let isometry = isometry.into();

// If the arc is major, that is, greater than a semicircle,
// then bounding circle is just the circle defining the sector.
BoundingCircle::new(isometry.translation, self.arc.radius)
Expand All @@ -136,19 +126,17 @@ impl Bounded2d for CircularSector {
}

impl Bounded2d for CircularSegment {
fn aabb_2d(&self, isometry: impl Into<Isometry2d>) -> Aabb2d {
fn aabb_2d(&self, isometry: Isometry2d) -> Aabb2d {
self.arc.aabb_2d(isometry)
}

fn bounding_circle(&self, isometry: impl Into<Isometry2d>) -> BoundingCircle {
fn bounding_circle(&self, isometry: Isometry2d) -> BoundingCircle {
self.arc.bounding_circle(isometry)
}
}

impl Bounded2d for Ellipse {
fn aabb_2d(&self, isometry: impl Into<Isometry2d>) -> Aabb2d {
let isometry = isometry.into();

fn aabb_2d(&self, isometry: Isometry2d) -> Aabb2d {
// V = (hh * cos(beta), hh * sin(beta))
// #####*#####
// ### | ###
Expand Down Expand Up @@ -177,28 +165,23 @@ impl Bounded2d for Ellipse {
Aabb2d::new(isometry.translation, half_size)
}

fn bounding_circle(&self, isometry: impl Into<Isometry2d>) -> BoundingCircle {
let isometry = isometry.into();
fn bounding_circle(&self, isometry: Isometry2d) -> BoundingCircle {
BoundingCircle::new(isometry.translation, self.semi_major())
}
}

impl Bounded2d for Annulus {
fn aabb_2d(&self, isometry: impl Into<Isometry2d>) -> Aabb2d {
let isometry = isometry.into();
fn aabb_2d(&self, isometry: Isometry2d) -> Aabb2d {
Aabb2d::new(isometry.translation, Vec2::splat(self.outer_circle.radius))
}

fn bounding_circle(&self, isometry: impl Into<Isometry2d>) -> BoundingCircle {
let isometry = isometry.into();
fn bounding_circle(&self, isometry: Isometry2d) -> BoundingCircle {
BoundingCircle::new(isometry.translation, self.outer_circle.radius)
}
}

impl Bounded2d for Rhombus {
fn aabb_2d(&self, isometry: impl Into<Isometry2d>) -> Aabb2d {
let isometry = isometry.into();

fn aabb_2d(&self, isometry: Isometry2d) -> Aabb2d {
let [rotated_x_half_diagonal, rotated_y_half_diagonal] = [
isometry.rotation * Vec2::new(self.half_diagonals.x, 0.0),
isometry.rotation * Vec2::new(0.0, self.half_diagonals.y),
Expand All @@ -213,16 +196,13 @@ impl Bounded2d for Rhombus {
}
}

fn bounding_circle(&self, isometry: impl Into<Isometry2d>) -> BoundingCircle {
let isometry = isometry.into();
fn bounding_circle(&self, isometry: Isometry2d) -> BoundingCircle {
BoundingCircle::new(isometry.translation, self.circumradius())
}
}

impl Bounded2d for Plane2d {
fn aabb_2d(&self, isometry: impl Into<Isometry2d>) -> Aabb2d {
let isometry = isometry.into();

fn aabb_2d(&self, isometry: Isometry2d) -> Aabb2d {
let normal = isometry.rotation * *self.normal;
let facing_x = normal == Vec2::X || normal == Vec2::NEG_X;
let facing_y = normal == Vec2::Y || normal == Vec2::NEG_Y;
Expand All @@ -236,16 +216,13 @@ impl Bounded2d for Plane2d {
Aabb2d::new(isometry.translation, half_size)
}

fn bounding_circle(&self, isometry: impl Into<Isometry2d>) -> BoundingCircle {
let isometry = isometry.into();
fn bounding_circle(&self, isometry: Isometry2d) -> BoundingCircle {
BoundingCircle::new(isometry.translation, f32::MAX / 2.0)
}
}

impl Bounded2d for Line2d {
fn aabb_2d(&self, isometry: impl Into<Isometry2d>) -> Aabb2d {
let isometry = isometry.into();

fn aabb_2d(&self, isometry: Isometry2d) -> Aabb2d {
let direction = isometry.rotation * *self.direction;

// Dividing `f32::MAX` by 2.0 is helpful so that we can do operations
Expand All @@ -258,19 +235,17 @@ impl Bounded2d for Line2d {
Aabb2d::new(isometry.translation, half_size)
}

fn bounding_circle(&self, isometry: impl Into<Isometry2d>) -> BoundingCircle {
let isometry = isometry.into();
fn bounding_circle(&self, isometry: Isometry2d) -> BoundingCircle {
BoundingCircle::new(isometry.translation, f32::MAX / 2.0)
}
}

impl Bounded2d for Segment2d {
fn aabb_2d(&self, isometry: impl Into<Isometry2d>) -> Aabb2d {
fn aabb_2d(&self, isometry: Isometry2d) -> Aabb2d {
Aabb2d::from_point_cloud(isometry, &[self.point1(), self.point2()])
}

fn bounding_circle(&self, isometry: impl Into<Isometry2d>) -> BoundingCircle {
let isometry: Isometry2d = isometry.into();
fn bounding_circle(&self, isometry: Isometry2d) -> BoundingCircle {
let local_center = self.center();
let radius = local_center.distance(self.point1());
let local_circle = BoundingCircle::new(local_center, radius);
Expand All @@ -280,18 +255,17 @@ impl Bounded2d for Segment2d {

#[cfg(feature = "alloc")]
impl Bounded2d for Polyline2d {
fn aabb_2d(&self, isometry: impl Into<Isometry2d>) -> Aabb2d {
fn aabb_2d(&self, isometry: Isometry2d) -> Aabb2d {
Aabb2d::from_point_cloud(isometry, &self.vertices)
}

fn bounding_circle(&self, isometry: impl Into<Isometry2d>) -> BoundingCircle {
fn bounding_circle(&self, isometry: Isometry2d) -> BoundingCircle {
BoundingCircle::from_point_cloud(isometry, &self.vertices)
}
}

impl Bounded2d for Triangle2d {
fn aabb_2d(&self, isometry: impl Into<Isometry2d>) -> Aabb2d {
let isometry = isometry.into();
fn aabb_2d(&self, isometry: Isometry2d) -> Aabb2d {
let [a, b, c] = self.vertices.map(|vtx| isometry.rotation * vtx);

let min = Vec2::new(a.x.min(b.x).min(c.x), a.y.min(b.y).min(c.y));
Expand All @@ -303,8 +277,7 @@ impl Bounded2d for Triangle2d {
}
}

fn bounding_circle(&self, isometry: impl Into<Isometry2d>) -> BoundingCircle {
let isometry = isometry.into();
fn bounding_circle(&self, isometry: Isometry2d) -> BoundingCircle {
let [a, b, c] = self.vertices;

// The points of the segment opposite to the obtuse or right angle if one exists
Expand Down Expand Up @@ -335,9 +308,7 @@ impl Bounded2d for Triangle2d {
}

impl Bounded2d for Rectangle {
fn aabb_2d(&self, isometry: impl Into<Isometry2d>) -> Aabb2d {
let isometry = isometry.into();

fn aabb_2d(&self, isometry: Isometry2d) -> Aabb2d {
// Compute the AABB of the rotated rectangle by transforming the half-extents
// by an absolute rotation matrix.
let (sin, cos) = isometry.rotation.sin_cos();
Expand All @@ -348,39 +319,36 @@ impl Bounded2d for Rectangle {
Aabb2d::new(isometry.translation, half_size)
}

fn bounding_circle(&self, isometry: impl Into<Isometry2d>) -> BoundingCircle {
let isometry = isometry.into();
fn bounding_circle(&self, isometry: Isometry2d) -> BoundingCircle {
let radius = self.half_size.length();
BoundingCircle::new(isometry.translation, radius)
}
}

#[cfg(feature = "alloc")]
impl Bounded2d for Polygon {
fn aabb_2d(&self, isometry: impl Into<Isometry2d>) -> Aabb2d {
fn aabb_2d(&self, isometry: Isometry2d) -> Aabb2d {
Aabb2d::from_point_cloud(isometry, &self.vertices)
}

fn bounding_circle(&self, isometry: impl Into<Isometry2d>) -> BoundingCircle {
fn bounding_circle(&self, isometry: Isometry2d) -> BoundingCircle {
BoundingCircle::from_point_cloud(isometry, &self.vertices)
}
}

#[cfg(feature = "alloc")]
impl Bounded2d for ConvexPolygon {
fn aabb_2d(&self, isometry: impl Into<Isometry2d>) -> Aabb2d {
fn aabb_2d(&self, isometry: Isometry2d) -> Aabb2d {
Aabb2d::from_point_cloud(isometry, self.vertices())
}

fn bounding_circle(&self, isometry: impl Into<Isometry2d>) -> BoundingCircle {
fn bounding_circle(&self, isometry: Isometry2d) -> BoundingCircle {
BoundingCircle::from_point_cloud(isometry, self.vertices())
}
}

impl Bounded2d for RegularPolygon {
fn aabb_2d(&self, isometry: impl Into<Isometry2d>) -> Aabb2d {
let isometry = isometry.into();

fn aabb_2d(&self, isometry: Isometry2d) -> Aabb2d {
let mut min = Vec2::ZERO;
let mut max = Vec2::ZERO;

Expand All @@ -395,16 +363,13 @@ impl Bounded2d for RegularPolygon {
}
}

fn bounding_circle(&self, isometry: impl Into<Isometry2d>) -> BoundingCircle {
let isometry = isometry.into();
fn bounding_circle(&self, isometry: Isometry2d) -> BoundingCircle {
BoundingCircle::new(isometry.translation, self.circumcircle.radius)
}
}

impl Bounded2d for Capsule2d {
fn aabb_2d(&self, isometry: impl Into<Isometry2d>) -> Aabb2d {
let isometry = isometry.into();

fn aabb_2d(&self, isometry: Isometry2d) -> Aabb2d {
// Get the line segment between the semicircles of the rotated capsule
let segment = Segment2d::from_direction_and_length(
isometry.rotation * Dir2::Y,
Expand All @@ -422,18 +387,17 @@ impl Bounded2d for Capsule2d {
}
}

fn bounding_circle(&self, isometry: impl Into<Isometry2d>) -> BoundingCircle {
let isometry = isometry.into();
fn bounding_circle(&self, isometry: Isometry2d) -> BoundingCircle {
BoundingCircle::new(isometry.translation, self.radius + self.half_length)
}
}

impl<P: Bounded2d + Primitive2d> Bounded2d for Ring<P> {
fn aabb_2d(&self, isometry: impl Into<Isometry2d>) -> Aabb2d {
fn aabb_2d(&self, isometry: Isometry2d) -> Aabb2d {
self.outer_shape.aabb_2d(isometry)
}

fn bounding_circle(&self, isometry: impl Into<Isometry2d>) -> BoundingCircle {
fn bounding_circle(&self, isometry: Isometry2d) -> BoundingCircle {
self.outer_shape.bounding_circle(isometry)
}
}
Expand Down
Loading