From 92cda8b0bbc6cbc4223c728b37bde363465aa9ba Mon Sep 17 00:00:00 2001 From: Innokentiy Popov <65750797+kyon4ik@users.noreply.github.com> Date: Sun, 4 May 2025 18:05:27 +0500 Subject: [PATCH] Fix `rotate_by` implementation for `Aabb2d` (#19015) # Objective Fixes #18969 ## Solution Also updated `Aabb3d` implementation for consistency. ## Testing Added tests for `Aabb2d` and `Aabb3d` to verify correct rotation behavior for angles greater than 90 degrees. --- .../bevy_math/src/bounding/bounded2d/mod.rs | 23 +++++++++++++------ .../bevy_math/src/bounding/bounded3d/mod.rs | 22 +++++++++++++----- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/crates/bevy_math/src/bounding/bounded2d/mod.rs b/crates/bevy_math/src/bounding/bounded2d/mod.rs index bea18f5808..5f11ad5233 100644 --- a/crates/bevy_math/src/bounding/bounded2d/mod.rs +++ b/crates/bevy_math/src/bounding/bounded2d/mod.rs @@ -243,13 +243,9 @@ impl BoundingVolume for Aabb2d { /// and consider storing the original AABB and rotating that every time instead. #[inline(always)] fn rotate_by(&mut self, rotation: impl Into) { - let rotation: Rot2 = rotation.into(); - let abs_rot_mat = Mat2::from_cols( - Vec2::new(rotation.cos, rotation.sin), - Vec2::new(rotation.sin, rotation.cos), - ); - let half_size = abs_rot_mat * self.half_size(); - *self = Self::new(rotation * self.center(), half_size); + let rot_mat = Mat2::from(rotation.into()); + let half_size = rot_mat.abs() * self.half_size(); + *self = Self::new(rot_mat * self.center(), half_size); } } @@ -274,6 +270,8 @@ impl IntersectsVolume for Aabb2d { #[cfg(test)] mod aabb2d_tests { + use approx::assert_relative_eq; + use super::Aabb2d; use crate::{ bounding::{BoundingCircle, BoundingVolume, IntersectsVolume}, @@ -394,6 +392,17 @@ mod aabb2d_tests { assert!(scaled.contains(&a)); } + #[test] + fn rotate() { + let a = Aabb2d { + min: Vec2::new(-2.0, -2.0), + max: Vec2::new(2.0, 2.0), + }; + let rotated = a.rotated_by(core::f32::consts::PI); + assert_relative_eq!(rotated.min, a.min); + assert_relative_eq!(rotated.max, a.max); + } + #[test] fn transform() { let a = Aabb2d { diff --git a/crates/bevy_math/src/bounding/bounded3d/mod.rs b/crates/bevy_math/src/bounding/bounded3d/mod.rs index 5a95b7711f..ca3b359798 100644 --- a/crates/bevy_math/src/bounding/bounded3d/mod.rs +++ b/crates/bevy_math/src/bounding/bounded3d/mod.rs @@ -250,12 +250,7 @@ impl BoundingVolume for Aabb3d { #[inline(always)] fn rotate_by(&mut self, rotation: impl Into) { let rot_mat = Mat3::from_quat(rotation.into()); - let abs_rot_mat = Mat3::from_cols( - rot_mat.x_axis.abs(), - rot_mat.y_axis.abs(), - rot_mat.z_axis.abs(), - ); - let half_size = abs_rot_mat * self.half_size(); + let half_size = rot_mat.abs() * self.half_size(); *self = Self::new(rot_mat * self.center(), half_size); } } @@ -279,6 +274,8 @@ impl IntersectsVolume for Aabb3d { #[cfg(test)] mod aabb3d_tests { + use approx::assert_relative_eq; + use super::Aabb3d; use crate::{ bounding::{BoundingSphere, BoundingVolume, IntersectsVolume}, @@ -398,6 +395,19 @@ mod aabb3d_tests { assert!(scaled.contains(&a)); } + #[test] + fn rotate() { + use core::f32::consts::PI; + let a = Aabb3d { + min: Vec3A::new(-2.0, -2.0, -2.0), + max: Vec3A::new(2.0, 2.0, 2.0), + }; + let rotation = Quat::from_euler(glam::EulerRot::XYZ, PI, PI, 0.0); + let rotated = a.rotated_by(rotation); + assert_relative_eq!(rotated.min, a.min); + assert_relative_eq!(rotated.max, a.max); + } + #[test] fn transform() { let a = Aabb3d {