Skip to content

Add Rotation2d #11658

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 38 commits into from
Mar 11, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
f39c6ea
Add `Rotation2d`
Jondolf Feb 1, 2024
fef12d6
Use `Rotation2d`
Jondolf Feb 1, 2024
f51a8c9
Reflect `Rotation2d`
Jondolf Feb 1, 2024
82892c9
Add `libm`
Jondolf Feb 1, 2024
174a09e
Merge branch 'main' into rotation2d
Jondolf Feb 1, 2024
98f1db4
Add some docs to impls
Jondolf Feb 1, 2024
a986cdc
Add tests
Jondolf Feb 1, 2024
2c3d020
Rotate directions
Jondolf Feb 1, 2024
47b0742
Add constants to `Rotation2d`
Jondolf Feb 1, 2024
0c30306
Mention angle range in docs
Jondolf Feb 1, 2024
6eb039a
Fix libm input
Jondolf Feb 1, 2024
deddf7b
Add missing doc comment
Jondolf Feb 1, 2024
d62e5fa
Fix condition
Jondolf Feb 2, 2024
c16b146
Note conditions for valid rotation using `from_sin_cos`
Jondolf Feb 2, 2024
52ea83d
Use parenthesis interval notation
Jondolf Feb 2, 2024
fc6f582
Remove `Rotation2d::new`
Jondolf Feb 2, 2024
260ec57
Impl `approx` traits and improve docs
Jondolf Feb 2, 2024
f518c96
Rename `from_radians` to `radians` and `from_degrees` to `degrees`
Jondolf Feb 2, 2024
d700581
Use `angle_between` to simplify logic
Jondolf Feb 3, 2024
dc63b0a
Merge branch 'main' into rotation2d
Jondolf Feb 3, 2024
b80c875
Fix doc comment and add `debug_assert!`
Jondolf Feb 28, 2024
702c1f6
Add length and normalization helpers and fix `lerp`
Jondolf Feb 29, 2024
e612c8d
Use sin and cos directly for `is_near_identity`
Jondolf Feb 29, 2024
5804977
Improve lerp and slerp docs and tests
Jondolf Feb 29, 2024
586fb49
Merge branch 'main' into rotation2d
Jondolf Feb 29, 2024
4de7b2a
Fix direction type
Jondolf Feb 29, 2024
6de3be0
Improve `lerp` docs
Jondolf Mar 4, 2024
8d5a2eb
Merge branch 'main' into rotation2d
Jondolf Mar 4, 2024
f8a393a
Rename `lerp` to `nlerp`
Jondolf Mar 4, 2024
c34b9dc
Revert accidental argument type change
Jondolf Mar 4, 2024
57d333b
Use consistent assertions for unit-length after rotating `Dir2`
Jondolf Mar 4, 2024
617a5b4
Fix typo
Jondolf Mar 4, 2024
c1904f5
Address review comments regarding normalization
Jondolf Mar 7, 2024
16b078d
Merge branch 'main' into rotation2d
Jondolf Mar 7, 2024
7e61be6
Use `Rotation2d` for 2D bounding volumes
Jondolf Mar 7, 2024
7b53dfe
Fix test
Jondolf Mar 7, 2024
3e0fa74
Explain `is_normalized` threshold value
Jondolf Mar 8, 2024
58cf454
Merge branch 'main' into rotation2d
Jondolf Mar 8, 2024
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
38 changes: 25 additions & 13 deletions crates/bevy_math/src/bounding/bounded2d/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
mod primitive_impls;

use super::{BoundingVolume, IntersectsVolume};
use crate::prelude::{Rotation2d, Vec2};
use crate::prelude::{Mat2, Rotation2d, Vec2};

/// Computes the geometric center of the given set of points.
#[inline(always)]
Expand Down Expand Up @@ -97,7 +97,7 @@ impl Aabb2d {

impl BoundingVolume for Aabb2d {
type Translation = Vec2;
type Rotation = f32;
type Rotation = Rotation2d;
type HalfSize = Vec2;

#[inline(always)]
Expand Down Expand Up @@ -160,7 +160,11 @@ impl BoundingVolume for Aabb2d {
/// can cause the AABB to grow indefinitely. Avoid applying multiple rotations to the same AABB,
/// and consider storing the original AABB and rotating that every time instead.
#[inline(always)]
fn transformed_by(mut self, translation: Self::Translation, rotation: Self::Rotation) -> Self {
fn transformed_by(
mut self,
translation: Self::Translation,
rotation: impl Into<Self::Rotation>,
) -> Self {
self.transform_by(translation, rotation);
self
}
Expand All @@ -173,7 +177,11 @@ impl BoundingVolume for Aabb2d {
/// can cause the AABB to grow indefinitely. Avoid applying multiple rotations to the same AABB,
/// and consider storing the original AABB and rotating that every time instead.
#[inline(always)]
fn transform_by(&mut self, translation: Self::Translation, rotation: Self::Rotation) {
fn transform_by(
&mut self,
translation: Self::Translation,
rotation: impl Into<Self::Rotation>,
) {
self.rotate_by(rotation);
self.translate_by(translation);
}
Expand All @@ -192,7 +200,7 @@ impl BoundingVolume for Aabb2d {
/// can cause the AABB to grow indefinitely. Avoid applying multiple rotations to the same AABB,
/// and consider storing the original AABB and rotating that every time instead.
#[inline(always)]
fn rotated_by(mut self, rotation: Self::Rotation) -> Self {
fn rotated_by(mut self, rotation: impl Into<Self::Rotation>) -> Self {
self.rotate_by(rotation);
self
}
Expand All @@ -205,11 +213,14 @@ impl BoundingVolume for Aabb2d {
/// can cause the AABB to grow indefinitely. Avoid applying multiple rotations to the same AABB,
/// and consider storing the original AABB and rotating that every time instead.
#[inline(always)]
fn rotate_by(&mut self, rotation: Self::Rotation) {
let rot_mat = Mat2::from_angle(rotation);
let abs_rot_mat = Mat2::from_cols(rot_mat.x_axis.abs(), rot_mat.y_axis.abs());
fn rotate_by(&mut self, rotation: impl Into<Self::Rotation>) {
let rotation: Rotation2d = 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(rot_mat * self.center(), half_size);
*self = Self::new(rotation * self.center(), half_size);
}
}

Expand Down Expand Up @@ -481,7 +492,7 @@ impl BoundingCircle {

impl BoundingVolume for BoundingCircle {
type Translation = Vec2;
type Rotation = f32;
type Rotation = Rotation2d;
type HalfSize = f32;

#[inline(always)]
Expand Down Expand Up @@ -536,13 +547,14 @@ impl BoundingVolume for BoundingCircle {
}

#[inline(always)]
fn translate_by(&mut self, translation: Vec2) {
fn translate_by(&mut self, translation: Self::Translation) {
self.center += translation;
}

#[inline(always)]
fn rotate_by(&mut self, rotation: f32) {
self.center = Mat2::from_angle(rotation) * self.center;
fn rotate_by(&mut self, rotation: impl Into<Self::Rotation>) {
let rotation: Rotation2d = rotation.into();
self.center = rotation * self.center;
}
}

Expand Down
23 changes: 16 additions & 7 deletions crates/bevy_math/src/bounding/bounded3d/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,11 @@ impl BoundingVolume for Aabb3d {
/// can cause the AABB to grow indefinitely. Avoid applying multiple rotations to the same AABB,
/// and consider storing the original AABB and rotating that every time instead.
#[inline(always)]
fn transformed_by(mut self, translation: Self::Translation, rotation: Self::Rotation) -> Self {
fn transformed_by(
mut self,
translation: Self::Translation,
rotation: impl Into<Self::Rotation>,
) -> Self {
self.transform_by(translation, rotation);
self
}
Expand All @@ -168,7 +172,11 @@ impl BoundingVolume for Aabb3d {
/// can cause the AABB to grow indefinitely. Avoid applying multiple rotations to the same AABB,
/// and consider storing the original AABB and rotating that every time instead.
#[inline(always)]
fn transform_by(&mut self, translation: Self::Translation, rotation: Self::Rotation) {
fn transform_by(
&mut self,
translation: Self::Translation,
rotation: impl Into<Self::Rotation>,
) {
self.rotate_by(rotation);
self.translate_by(translation);
}
Expand All @@ -187,7 +195,7 @@ impl BoundingVolume for Aabb3d {
/// can cause the AABB to grow indefinitely. Avoid applying multiple rotations to the same AABB,
/// and consider storing the original AABB and rotating that every time instead.
#[inline(always)]
fn rotated_by(mut self, rotation: Self::Rotation) -> Self {
fn rotated_by(mut self, rotation: impl Into<Self::Rotation>) -> Self {
self.rotate_by(rotation);
self
}
Expand All @@ -200,8 +208,8 @@ impl BoundingVolume for Aabb3d {
/// can cause the AABB to grow indefinitely. Avoid applying multiple rotations to the same AABB,
/// and consider storing the original AABB and rotating that every time instead.
#[inline(always)]
fn rotate_by(&mut self, rotation: Self::Rotation) {
let rot_mat = Mat3::from_quat(rotation);
fn rotate_by(&mut self, rotation: impl Into<Self::Rotation>) {
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(),
Expand Down Expand Up @@ -542,12 +550,13 @@ impl BoundingVolume for BoundingSphere {
}

#[inline(always)]
fn translate_by(&mut self, translation: Vec3) {
fn translate_by(&mut self, translation: Self::Translation) {
self.center += translation;
}

#[inline(always)]
fn rotate_by(&mut self, rotation: Quat) {
fn rotate_by(&mut self, rotation: impl Into<Self::Rotation>) {
let rotation: Quat = rotation.into();
self.center = rotation * self.center;
}
}
Expand Down
16 changes: 12 additions & 4 deletions crates/bevy_math/src/bounding/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,21 @@ pub trait BoundingVolume: Sized {
fn shrink(&self, amount: Self::HalfSize) -> Self;

/// Transforms the bounding volume by first rotating it around the origin and then applying a translation.
fn transformed_by(mut self, translation: Self::Translation, rotation: Self::Rotation) -> Self {
fn transformed_by(
mut self,
translation: Self::Translation,
rotation: impl Into<Self::Rotation>,
) -> Self {
self.transform_by(translation, rotation);
self
}

/// Transforms the bounding volume by first rotating it around the origin and then applying a translation.
fn transform_by(&mut self, translation: Self::Translation, rotation: Self::Rotation) {
fn transform_by(
&mut self,
translation: Self::Translation,
rotation: impl Into<Self::Rotation>,
) {
self.rotate_by(rotation);
self.translate_by(translation);
}
Expand All @@ -73,7 +81,7 @@ pub trait BoundingVolume: Sized {
///
/// The result is a combination of the original volume and the rotated volume,
/// so it is guaranteed to be either the same size or larger than the original.
fn rotated_by(mut self, rotation: Self::Rotation) -> Self {
fn rotated_by(mut self, rotation: impl Into<Self::Rotation>) -> Self {
self.rotate_by(rotation);
self
}
Expand All @@ -82,7 +90,7 @@ pub trait BoundingVolume: Sized {
///
/// The result is a combination of the original volume and the rotated volume,
/// so it is guaranteed to be either the same size or larger than the original.
fn rotate_by(&mut self, rotation: Self::Rotation);
fn rotate_by(&mut self, rotation: impl Into<Self::Rotation>);
}

/// A trait that generalizes intersection tests against a volume.
Expand Down
16 changes: 7 additions & 9 deletions crates/bevy_math/src/rotation2d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,12 +206,11 @@ impl Rotation2d {
///
/// # Panics
///
/// Panics if `self` has a length of zero, NaN, or infinity when the `glam_assert`
/// feature is enabled.
/// Panics if `self` has a length of zero, NaN, or infinity when debug assertions are enabled.
#[inline]
pub fn normalize(self) -> Self {
let length = self.length();
Self::from_sin_cos(self.sin / length, self.cos / length)
let length_recip = self.length_recip();
Self::from_sin_cos(self.sin * length_recip, self.cos * length_recip)
}

/// Returns `true` if the rotation is neither infinite nor NaN.
Expand All @@ -228,11 +227,10 @@ impl Rotation2d {

/// Returns whether `self` has a length of `1.0` or not.
///
/// Uses a precision threshold of `1e-6`.
/// Uses a precision threshold of approximately `1e-4`.
#[inline]
pub fn is_normalized(self) -> bool {
let length = self.sin.hypot(self.cos);
length - 1.0 <= 1e-6
(self.length_squared() - 1.0).abs() <= 2e-4
}

/// Returns `true` if the rotation is near [`Rotation2d::IDENTITY`].
Expand Down Expand Up @@ -501,8 +499,8 @@ mod tests {
};
let normalized_rotation = rotation.normalize();

assert_eq!(normalized_rotation.sin, 0.8944272);
assert_eq!(normalized_rotation.cos, 0.4472136);
assert_eq!(normalized_rotation.sin, 0.89442724);
assert_eq!(normalized_rotation.cos, 0.44721362);

assert!(!rotation.is_normalized());
assert!(normalized_rotation.is_normalized());
Expand Down