Rename Rotation2d to Rot2 (#13694)

# Objective

- `Rotation2d` is a very long name for a commonly used type.

## Solution

- Rename it to `Rot2` to match `glam`'s naming convention (e.g. `Vec2`)

I ran a poll, and `Rot2` was the favorite of the candidate names.

This is not actually a breaking change, since `Rotation2d` has not been
shipped yet.

---------

Co-authored-by: Alice Cecile <alice.i.cecil@gmail.com>
This commit is contained in:
Alice Cecile 2024-06-05 17:51:13 -04:00 committed by GitHub
parent 2eb9d5cc38
commit 2165f2218f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 145 additions and 222 deletions

View file

@ -8,7 +8,7 @@ use bevy_ecs::{
system::{Deferred, ReadOnlySystemParam, Res, Resource, SystemBuffer, SystemMeta, SystemParam},
world::{unsafe_world_cell::UnsafeWorldCell, World},
};
use bevy_math::{Quat, Rotation2d, Vec2, Vec3};
use bevy_math::{Quat, Rot2, Vec2, Vec3};
use bevy_transform::TransformPoint;
use bevy_utils::default;
@ -707,14 +707,14 @@ where
pub fn rect_2d(
&mut self,
position: Vec2,
rotation: impl Into<Rotation2d>,
rotation: impl Into<Rot2>,
size: Vec2,
color: impl Into<Color>,
) {
if !self.enabled {
return;
}
let rotation: Rotation2d = rotation.into();
let rotation: Rot2 = rotation.into();
let [tl, tr, br, bl] = rect_inner(size).map(|vec2| position + rotation * vec2);
self.linestrip_2d([tl, tr, br, bl, tl], color);
}

View file

@ -1,7 +1,7 @@
mod primitive_impls;
use super::{BoundingVolume, IntersectsVolume};
use crate::prelude::{Mat2, Rotation2d, Vec2};
use crate::prelude::{Mat2, Rot2, Vec2};
#[cfg(feature = "bevy_reflect")]
use bevy_reflect::Reflect;
@ -22,11 +22,10 @@ fn point_cloud_2d_center(points: &[Vec2]) -> Vec2 {
pub trait Bounded2d {
/// Get an axis-aligned bounding box for the shape with the given translation and rotation.
/// The rotation is in radians, counterclockwise, with 0 meaning no rotation.
fn aabb_2d(&self, translation: Vec2, rotation: impl Into<Rotation2d>) -> Aabb2d;
fn aabb_2d(&self, translation: Vec2, rotation: impl Into<Rot2>) -> Aabb2d;
/// Get a bounding circle for the shape
/// The rotation is in radians, counterclockwise, with 0 meaning no rotation.
fn bounding_circle(&self, translation: Vec2, rotation: impl Into<Rotation2d>)
-> BoundingCircle;
fn bounding_circle(&self, translation: Vec2, rotation: impl Into<Rot2>) -> BoundingCircle;
}
/// A 2D axis-aligned bounding box, or bounding rectangle
@ -60,11 +59,11 @@ impl Aabb2d {
#[inline(always)]
pub fn from_point_cloud(
translation: Vec2,
rotation: impl Into<Rotation2d>,
rotation: impl Into<Rot2>,
points: &[Vec2],
) -> Aabb2d {
// Transform all points by rotation
let rotation: Rotation2d = rotation.into();
let rotation: Rot2 = rotation.into();
let mut iter = points.iter().map(|point| rotation * *point);
let first = iter
@ -101,7 +100,7 @@ impl Aabb2d {
impl BoundingVolume for Aabb2d {
type Translation = Vec2;
type Rotation = Rotation2d;
type Rotation = Rot2;
type HalfSize = Vec2;
#[inline(always)]
@ -232,7 +231,7 @@ 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<Self::Rotation>) {
let rotation: Rotation2d = rotation.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),
@ -479,10 +478,10 @@ impl BoundingCircle {
#[inline(always)]
pub fn from_point_cloud(
translation: Vec2,
rotation: impl Into<Rotation2d>,
rotation: impl Into<Rot2>,
points: &[Vec2],
) -> BoundingCircle {
let rotation: Rotation2d = rotation.into();
let rotation: Rot2 = rotation.into();
let center = point_cloud_2d_center(points);
let mut radius_squared = 0.0;
@ -524,7 +523,7 @@ impl BoundingCircle {
impl BoundingVolume for BoundingCircle {
type Translation = Vec2;
type Rotation = Rotation2d;
type Rotation = Rot2;
type HalfSize = f32;
#[inline(always)]
@ -594,7 +593,7 @@ impl BoundingVolume for BoundingCircle {
#[inline(always)]
fn rotate_by(&mut self, rotation: impl Into<Self::Rotation>) {
let rotation: Rotation2d = rotation.into();
let rotation: Rot2 = rotation.into();
self.center = rotation * self.center;
}
}

View file

@ -6,7 +6,7 @@ use crate::{
Ellipse, Line2d, Plane2d, Polygon, Polyline2d, Rectangle, RegularPolygon, Rhombus,
Segment2d, Triangle2d,
},
Dir2, Mat2, Rotation2d, Vec2,
Dir2, Mat2, Rot2, Vec2,
};
use std::f32::consts::{FRAC_PI_2, PI, TAU};
@ -15,15 +15,11 @@ use smallvec::SmallVec;
use super::{Aabb2d, Bounded2d, BoundingCircle};
impl Bounded2d for Circle {
fn aabb_2d(&self, translation: Vec2, _rotation: impl Into<Rotation2d>) -> Aabb2d {
fn aabb_2d(&self, translation: Vec2, _rotation: impl Into<Rot2>) -> Aabb2d {
Aabb2d::new(translation, Vec2::splat(self.radius))
}
fn bounding_circle(
&self,
translation: Vec2,
_rotation: impl Into<Rotation2d>,
) -> BoundingCircle {
fn bounding_circle(&self, translation: Vec2, _rotation: impl Into<Rot2>) -> BoundingCircle {
BoundingCircle::new(translation, self.radius)
}
}
@ -31,7 +27,7 @@ impl Bounded2d for Circle {
// Compute the axis-aligned bounding points of a rotated arc, used for computing the AABB of arcs and derived shapes.
// The return type has room for 7 points so that the CircularSector code can add an additional point.
#[inline]
fn arc_bounding_points(arc: Arc2d, rotation: impl Into<Rotation2d>) -> SmallVec<[Vec2; 7]> {
fn arc_bounding_points(arc: Arc2d, rotation: impl Into<Rot2>) -> SmallVec<[Vec2; 7]> {
// Otherwise, the extreme points will always be either the endpoints or the axis-aligned extrema of the arc's circle.
// We need to compute which axis-aligned extrema are actually contained within the rotated arc.
let mut bounds = SmallVec::<[Vec2; 7]>::new();
@ -61,7 +57,7 @@ fn arc_bounding_points(arc: Arc2d, rotation: impl Into<Rotation2d>) -> SmallVec<
}
impl Bounded2d for Arc2d {
fn aabb_2d(&self, translation: Vec2, rotation: impl Into<Rotation2d>) -> Aabb2d {
fn aabb_2d(&self, translation: Vec2, rotation: impl Into<Rot2>) -> 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(translation, rotation);
@ -70,11 +66,7 @@ impl Bounded2d for Arc2d {
Aabb2d::from_point_cloud(translation, 0.0, &arc_bounding_points(*self, rotation))
}
fn bounding_circle(
&self,
translation: Vec2,
rotation: impl Into<Rotation2d>,
) -> BoundingCircle {
fn bounding_circle(&self, translation: Vec2, rotation: impl Into<Rot2>) -> 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;
@ -90,7 +82,7 @@ impl Bounded2d for Arc2d {
}
impl Bounded2d for CircularSector {
fn aabb_2d(&self, translation: Vec2, rotation: impl Into<Rotation2d>) -> Aabb2d {
fn aabb_2d(&self, translation: Vec2, rotation: impl Into<Rot2>) -> 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(translation, rotation);
@ -103,11 +95,7 @@ impl Bounded2d for CircularSector {
Aabb2d::from_point_cloud(translation, 0.0, &bounds)
}
fn bounding_circle(
&self,
translation: Vec2,
rotation: impl Into<Rotation2d>,
) -> BoundingCircle {
fn bounding_circle(&self, translation: Vec2, rotation: impl Into<Rot2>) -> BoundingCircle {
if self.arc.is_major() {
// If the arc is major, that is, greater than a semicircle,
// then bounding circle is just the circle defining the sector.
@ -129,22 +117,18 @@ impl Bounded2d for CircularSector {
}
impl Bounded2d for CircularSegment {
fn aabb_2d(&self, translation: Vec2, rotation: impl Into<Rotation2d>) -> Aabb2d {
fn aabb_2d(&self, translation: Vec2, rotation: impl Into<Rot2>) -> Aabb2d {
self.arc.aabb_2d(translation, rotation)
}
fn bounding_circle(
&self,
translation: Vec2,
rotation: impl Into<Rotation2d>,
) -> BoundingCircle {
fn bounding_circle(&self, translation: Vec2, rotation: impl Into<Rot2>) -> BoundingCircle {
self.arc.bounding_circle(translation, rotation)
}
}
impl Bounded2d for Ellipse {
fn aabb_2d(&self, translation: Vec2, rotation: impl Into<Rotation2d>) -> Aabb2d {
let rotation: Rotation2d = rotation.into();
fn aabb_2d(&self, translation: Vec2, rotation: impl Into<Rot2>) -> Aabb2d {
let rotation: Rot2 = rotation.into();
// V = (hh * cos(beta), hh * sin(beta))
// #####*#####
@ -174,17 +158,13 @@ impl Bounded2d for Ellipse {
Aabb2d::new(translation, half_size)
}
fn bounding_circle(
&self,
translation: Vec2,
_rotation: impl Into<Rotation2d>,
) -> BoundingCircle {
fn bounding_circle(&self, translation: Vec2, _rotation: impl Into<Rot2>) -> BoundingCircle {
BoundingCircle::new(translation, self.semi_major())
}
}
impl Bounded2d for Rhombus {
fn aabb_2d(&self, translation: Vec2, rotation: impl Into<Rotation2d>) -> Aabb2d {
fn aabb_2d(&self, translation: Vec2, rotation: impl Into<Rot2>) -> Aabb2d {
let rotation_mat = rotation.into();
let [rotated_x_half_diagonal, rotated_y_half_diagonal] = [
@ -201,18 +181,14 @@ impl Bounded2d for Rhombus {
}
}
fn bounding_circle(
&self,
translation: Vec2,
_rotation: impl Into<Rotation2d>,
) -> BoundingCircle {
fn bounding_circle(&self, translation: Vec2, _rotation: impl Into<Rot2>) -> BoundingCircle {
BoundingCircle::new(translation, self.circumradius())
}
}
impl Bounded2d for Plane2d {
fn aabb_2d(&self, translation: Vec2, rotation: impl Into<Rotation2d>) -> Aabb2d {
let rotation: Rotation2d = rotation.into();
fn aabb_2d(&self, translation: Vec2, rotation: impl Into<Rot2>) -> Aabb2d {
let rotation: Rot2 = rotation.into();
let normal = rotation * *self.normal;
let facing_x = normal == Vec2::X || normal == Vec2::NEG_X;
let facing_y = normal == Vec2::Y || normal == Vec2::NEG_Y;
@ -226,18 +202,14 @@ impl Bounded2d for Plane2d {
Aabb2d::new(translation, half_size)
}
fn bounding_circle(
&self,
translation: Vec2,
_rotation: impl Into<Rotation2d>,
) -> BoundingCircle {
fn bounding_circle(&self, translation: Vec2, _rotation: impl Into<Rot2>) -> BoundingCircle {
BoundingCircle::new(translation, f32::MAX / 2.0)
}
}
impl Bounded2d for Line2d {
fn aabb_2d(&self, translation: Vec2, rotation: impl Into<Rotation2d>) -> Aabb2d {
let rotation: Rotation2d = rotation.into();
fn aabb_2d(&self, translation: Vec2, rotation: impl Into<Rot2>) -> Aabb2d {
let rotation: Rot2 = rotation.into();
let direction = rotation * *self.direction;
// Dividing `f32::MAX` by 2.0 is helpful so that we can do operations
@ -250,65 +222,49 @@ impl Bounded2d for Line2d {
Aabb2d::new(translation, half_size)
}
fn bounding_circle(
&self,
translation: Vec2,
_rotation: impl Into<Rotation2d>,
) -> BoundingCircle {
fn bounding_circle(&self, translation: Vec2, _rotation: impl Into<Rot2>) -> BoundingCircle {
BoundingCircle::new(translation, f32::MAX / 2.0)
}
}
impl Bounded2d for Segment2d {
fn aabb_2d(&self, translation: Vec2, rotation: impl Into<Rotation2d>) -> Aabb2d {
fn aabb_2d(&self, translation: Vec2, rotation: impl Into<Rot2>) -> Aabb2d {
// Rotate the segment by `rotation`
let rotation: Rotation2d = rotation.into();
let rotation: Rot2 = rotation.into();
let direction = rotation * *self.direction;
let half_size = (self.half_length * direction).abs();
Aabb2d::new(translation, half_size)
}
fn bounding_circle(
&self,
translation: Vec2,
_rotation: impl Into<Rotation2d>,
) -> BoundingCircle {
fn bounding_circle(&self, translation: Vec2, _rotation: impl Into<Rot2>) -> BoundingCircle {
BoundingCircle::new(translation, self.half_length)
}
}
impl<const N: usize> Bounded2d for Polyline2d<N> {
fn aabb_2d(&self, translation: Vec2, rotation: impl Into<Rotation2d>) -> Aabb2d {
fn aabb_2d(&self, translation: Vec2, rotation: impl Into<Rot2>) -> Aabb2d {
Aabb2d::from_point_cloud(translation, rotation, &self.vertices)
}
fn bounding_circle(
&self,
translation: Vec2,
rotation: impl Into<Rotation2d>,
) -> BoundingCircle {
fn bounding_circle(&self, translation: Vec2, rotation: impl Into<Rot2>) -> BoundingCircle {
BoundingCircle::from_point_cloud(translation, rotation, &self.vertices)
}
}
impl Bounded2d for BoxedPolyline2d {
fn aabb_2d(&self, translation: Vec2, rotation: impl Into<Rotation2d>) -> Aabb2d {
fn aabb_2d(&self, translation: Vec2, rotation: impl Into<Rot2>) -> Aabb2d {
Aabb2d::from_point_cloud(translation, rotation, &self.vertices)
}
fn bounding_circle(
&self,
translation: Vec2,
rotation: impl Into<Rotation2d>,
) -> BoundingCircle {
fn bounding_circle(&self, translation: Vec2, rotation: impl Into<Rot2>) -> BoundingCircle {
BoundingCircle::from_point_cloud(translation, rotation, &self.vertices)
}
}
impl Bounded2d for Triangle2d {
fn aabb_2d(&self, translation: Vec2, rotation: impl Into<Rotation2d>) -> Aabb2d {
let rotation: Rotation2d = rotation.into();
fn aabb_2d(&self, translation: Vec2, rotation: impl Into<Rot2>) -> Aabb2d {
let rotation: Rot2 = rotation.into();
let [a, b, c] = self.vertices.map(|vtx| rotation * vtx);
let min = Vec2::new(a.x.min(b.x).min(c.x), a.y.min(b.y).min(c.y));
@ -320,12 +276,8 @@ impl Bounded2d for Triangle2d {
}
}
fn bounding_circle(
&self,
translation: Vec2,
rotation: impl Into<Rotation2d>,
) -> BoundingCircle {
let rotation: Rotation2d = rotation.into();
fn bounding_circle(&self, translation: Vec2, rotation: impl Into<Rot2>) -> BoundingCircle {
let rotation: Rot2 = rotation.into();
let [a, b, c] = self.vertices;
// The points of the segment opposite to the obtuse or right angle if one exists
@ -356,8 +308,8 @@ impl Bounded2d for Triangle2d {
}
impl Bounded2d for Rectangle {
fn aabb_2d(&self, translation: Vec2, rotation: impl Into<Rotation2d>) -> Aabb2d {
let rotation: Rotation2d = rotation.into();
fn aabb_2d(&self, translation: Vec2, rotation: impl Into<Rot2>) -> Aabb2d {
let rotation: Rot2 = rotation.into();
// Compute the AABB of the rotated rectangle by transforming the half-extents
// by an absolute rotation matrix.
@ -368,47 +320,35 @@ impl Bounded2d for Rectangle {
Aabb2d::new(translation, half_size)
}
fn bounding_circle(
&self,
translation: Vec2,
_rotation: impl Into<Rotation2d>,
) -> BoundingCircle {
fn bounding_circle(&self, translation: Vec2, _rotation: impl Into<Rot2>) -> BoundingCircle {
let radius = self.half_size.length();
BoundingCircle::new(translation, radius)
}
}
impl<const N: usize> Bounded2d for Polygon<N> {
fn aabb_2d(&self, translation: Vec2, rotation: impl Into<Rotation2d>) -> Aabb2d {
fn aabb_2d(&self, translation: Vec2, rotation: impl Into<Rot2>) -> Aabb2d {
Aabb2d::from_point_cloud(translation, rotation, &self.vertices)
}
fn bounding_circle(
&self,
translation: Vec2,
rotation: impl Into<Rotation2d>,
) -> BoundingCircle {
fn bounding_circle(&self, translation: Vec2, rotation: impl Into<Rot2>) -> BoundingCircle {
BoundingCircle::from_point_cloud(translation, rotation, &self.vertices)
}
}
impl Bounded2d for BoxedPolygon {
fn aabb_2d(&self, translation: Vec2, rotation: impl Into<Rotation2d>) -> Aabb2d {
fn aabb_2d(&self, translation: Vec2, rotation: impl Into<Rot2>) -> Aabb2d {
Aabb2d::from_point_cloud(translation, rotation, &self.vertices)
}
fn bounding_circle(
&self,
translation: Vec2,
rotation: impl Into<Rotation2d>,
) -> BoundingCircle {
fn bounding_circle(&self, translation: Vec2, rotation: impl Into<Rot2>) -> BoundingCircle {
BoundingCircle::from_point_cloud(translation, rotation, &self.vertices)
}
}
impl Bounded2d for RegularPolygon {
fn aabb_2d(&self, translation: Vec2, rotation: impl Into<Rotation2d>) -> Aabb2d {
let rotation: Rotation2d = rotation.into();
fn aabb_2d(&self, translation: Vec2, rotation: impl Into<Rot2>) -> Aabb2d {
let rotation: Rot2 = rotation.into();
let mut min = Vec2::ZERO;
let mut max = Vec2::ZERO;
@ -424,18 +364,14 @@ impl Bounded2d for RegularPolygon {
}
}
fn bounding_circle(
&self,
translation: Vec2,
_rotation: impl Into<Rotation2d>,
) -> BoundingCircle {
fn bounding_circle(&self, translation: Vec2, _rotation: impl Into<Rot2>) -> BoundingCircle {
BoundingCircle::new(translation, self.circumcircle.radius)
}
}
impl Bounded2d for Capsule2d {
fn aabb_2d(&self, translation: Vec2, rotation: impl Into<Rotation2d>) -> Aabb2d {
let rotation: Rotation2d = rotation.into();
fn aabb_2d(&self, translation: Vec2, rotation: impl Into<Rot2>) -> Aabb2d {
let rotation: Rot2 = rotation.into();
// Get the line segment between the hemicircles of the rotated capsule
let segment = Segment2d {
@ -455,11 +391,7 @@ impl Bounded2d for Capsule2d {
}
}
fn bounding_circle(
&self,
translation: Vec2,
_rotation: impl Into<Rotation2d>,
) -> BoundingCircle {
fn bounding_circle(&self, translation: Vec2, _rotation: impl Into<Rot2>) -> BoundingCircle {
BoundingCircle::new(translation, self.radius + self.half_length)
}
}

View file

@ -1,6 +1,6 @@
use crate::{
primitives::{Primitive2d, Primitive3d},
Quat, Rotation2d, Vec2, Vec3, Vec3A,
Quat, Rot2, Vec2, Vec3, Vec3A,
};
use core::f32::consts::FRAC_1_SQRT_2;
@ -200,47 +200,47 @@ impl Dir2 {
#[inline]
pub fn slerp(self, rhs: Self, s: f32) -> Self {
let angle = self.angle_between(rhs.0);
Rotation2d::radians(angle * s) * self
Rot2::radians(angle * s) * self
}
/// Get the rotation that rotates this direction to `other`.
#[inline]
pub fn rotation_to(self, other: Self) -> Rotation2d {
pub fn rotation_to(self, other: Self) -> Rot2 {
// Rotate `self` to X-axis, then X-axis to `other`:
other.rotation_from_x() * self.rotation_to_x()
}
/// Get the rotation that rotates `other` to this direction.
#[inline]
pub fn rotation_from(self, other: Self) -> Rotation2d {
pub fn rotation_from(self, other: Self) -> Rot2 {
other.rotation_to(self)
}
/// Get the rotation that rotates the X-axis to this direction.
#[inline]
pub fn rotation_from_x(self) -> Rotation2d {
Rotation2d::from_sin_cos(self.0.y, self.0.x)
pub fn rotation_from_x(self) -> Rot2 {
Rot2::from_sin_cos(self.0.y, self.0.x)
}
/// Get the rotation that rotates this direction to the X-axis.
#[inline]
pub fn rotation_to_x(self) -> Rotation2d {
pub fn rotation_to_x(self) -> Rot2 {
// (This is cheap, it just negates one component.)
self.rotation_from_x().inverse()
}
/// Get the rotation that rotates this direction to the Y-axis.
#[inline]
pub fn rotation_from_y(self) -> Rotation2d {
pub fn rotation_from_y(self) -> Rot2 {
// `x <- y`, `y <- -x` correspond to rotating clockwise by pi/2;
// this transforms the Y-axis into the X-axis, maintaining the relative position
// of our direction. Then we just use the same technique as `rotation_from_x`.
Rotation2d::from_sin_cos(-self.0.x, self.0.y)
Rot2::from_sin_cos(-self.0.x, self.0.y)
}
/// Get the rotation that rotates the Y-axis to this direction.
#[inline]
pub fn rotation_to_y(self) -> Rotation2d {
pub fn rotation_to_y(self) -> Rot2 {
self.rotation_from_y().inverse()
}
}
@ -287,10 +287,10 @@ impl std::ops::Mul<Dir2> for f32 {
}
}
impl std::ops::Mul<Dir2> for Rotation2d {
impl std::ops::Mul<Dir2> for Rot2 {
type Output = Dir2;
/// Rotates the [`Dir2`] using a [`Rotation2d`].
/// Rotates the [`Dir2`] using a [`Rot2`].
fn mul(self, direction: Dir2) -> Self::Output {
let rotated = self * *direction;
@ -807,21 +807,12 @@ mod tests {
#[test]
fn dir2_to_rotation2d() {
assert_relative_eq!(
Dir2::EAST.rotation_to(Dir2::NORTH_EAST),
Rotation2d::FRAC_PI_4
);
assert_relative_eq!(
Dir2::NORTH.rotation_from(Dir2::NORTH_EAST),
Rotation2d::FRAC_PI_4
);
assert_relative_eq!(Dir2::SOUTH.rotation_to_x(), Rotation2d::FRAC_PI_2);
assert_relative_eq!(Dir2::SOUTH.rotation_to_y(), Rotation2d::PI);
assert_relative_eq!(
Dir2::NORTH_WEST.rotation_from_x(),
Rotation2d::degrees(135.0)
);
assert_relative_eq!(Dir2::NORTH_WEST.rotation_from_y(), Rotation2d::FRAC_PI_4);
assert_relative_eq!(Dir2::EAST.rotation_to(Dir2::NORTH_EAST), Rot2::FRAC_PI_4);
assert_relative_eq!(Dir2::NORTH.rotation_from(Dir2::NORTH_EAST), Rot2::FRAC_PI_4);
assert_relative_eq!(Dir2::SOUTH.rotation_to_x(), Rot2::FRAC_PI_2);
assert_relative_eq!(Dir2::SOUTH.rotation_to_y(), Rot2::PI);
assert_relative_eq!(Dir2::NORTH_WEST.rotation_from_x(), Rot2::degrees(135.0));
assert_relative_eq!(Dir2::NORTH_WEST.rotation_from_y(), Rot2::FRAC_PI_4);
}
#[test]

View file

@ -34,7 +34,7 @@ pub use direction::*;
pub use float_ord::*;
pub use ray::{Ray2d, Ray3d};
pub use rects::*;
pub use rotation2d::Rotation2d;
pub use rotation2d::Rot2;
#[cfg(feature = "rand")]
pub use sampling::{FromRng, ShapeSample};
@ -53,7 +53,7 @@ pub mod prelude {
direction::{Dir2, Dir3, Dir3A},
primitives::*,
BVec2, BVec3, BVec4, EulerRot, FloatExt, IRect, IVec2, IVec3, IVec4, Mat2, Mat3, Mat4,
Quat, Ray2d, Ray3d, Rect, Rotation2d, URect, UVec2, UVec3, UVec4, Vec2, Vec2Swizzles, Vec3,
Quat, Ray2d, Ray3d, Rect, Rot2, URect, UVec2, UVec3, UVec4, Vec2, Vec2Swizzles, Vec3,
Vec3Swizzles, Vec4, Vec4Swizzles,
};
}

View file

@ -13,19 +13,19 @@ use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
///
/// ```
/// # use approx::assert_relative_eq;
/// # use bevy_math::{Rotation2d, Vec2};
/// # use bevy_math::{Rot2, Vec2};
/// use std::f32::consts::PI;
///
/// // Create rotations from radians or degrees
/// let rotation1 = Rotation2d::radians(PI / 2.0);
/// let rotation2 = Rotation2d::degrees(45.0);
/// let rotation1 = Rot2::radians(PI / 2.0);
/// let rotation2 = Rot2::degrees(45.0);
///
/// // Get the angle back as radians or degrees
/// assert_eq!(rotation1.as_degrees(), 90.0);
/// assert_eq!(rotation2.as_radians(), PI / 4.0);
///
/// // "Add" rotations together using `*`
/// assert_relative_eq!(rotation1 * rotation2, Rotation2d::degrees(135.0));
/// assert_relative_eq!(rotation1 * rotation2, Rot2::degrees(135.0));
///
/// // Rotate vectors
/// assert_relative_eq!(rotation1 * Vec2::X, Vec2::Y);
@ -41,7 +41,8 @@ use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
all(feature = "serialize", feature = "bevy_reflect"),
reflect(Serialize, Deserialize)
)]
pub struct Rotation2d {
#[doc(alias = "rotation", alias = "rotation2d", alias = "rotation_2d")]
pub struct Rot2 {
/// The cosine of the rotation angle in radians.
///
/// This is the real part of the unit complex number representing the rotation.
@ -52,13 +53,13 @@ pub struct Rotation2d {
pub sin: f32,
}
impl Default for Rotation2d {
impl Default for Rot2 {
fn default() -> Self {
Self::IDENTITY
}
}
impl Rotation2d {
impl Rot2 {
/// No rotation.
pub const IDENTITY: Self = Self { cos: 1.0, sin: 0.0 };
@ -95,7 +96,7 @@ impl Rotation2d {
sin: 0.382_683_43,
};
/// Creates a [`Rotation2d`] from a counterclockwise angle in radians.
/// Creates a [`Rot2`] from a counterclockwise angle in radians.
#[inline]
pub fn radians(radians: f32) -> Self {
#[cfg(feature = "libm")]
@ -109,13 +110,13 @@ impl Rotation2d {
Self::from_sin_cos(sin, cos)
}
/// Creates a [`Rotation2d`] from a counterclockwise angle in degrees.
/// Creates a [`Rot2`] from a counterclockwise angle in degrees.
#[inline]
pub fn degrees(degrees: f32) -> Self {
Self::radians(degrees.to_radians())
}
/// Creates a [`Rotation2d`] from the sine and cosine of an angle in radians.
/// Creates a [`Rot2`] from the sine and cosine of an angle in radians.
///
/// The rotation is only valid if `sin * sin + cos * cos == 1.0`.
///
@ -170,7 +171,7 @@ impl Rotation2d {
/// Computes the squared length or norm of the complex number used to represent the rotation.
///
/// This is generally faster than [`Rotation2d::length()`], as it avoids a square
/// This is generally faster than [`Rot2::length()`], as it avoids a square
/// root operation.
///
/// The length is typically expected to be `1.0`. Unexpectedly denormalized rotations
@ -195,7 +196,7 @@ impl Rotation2d {
/// `None` will be returned if the sine and cosine of `self` are both zero (or very close to zero),
/// or if either of them is NaN or infinite.
///
/// Note that [`Rotation2d`] should typically already be normalized by design.
/// Note that [`Rot2`] should typically already be normalized by design.
/// Manual normalization is only needed when successive operations result in
/// accumulated floating point error, or if the rotation was constructed
/// with invalid values.
@ -211,7 +212,7 @@ impl Rotation2d {
/// Returns `self` with a length of `1.0`.
///
/// Note that [`Rotation2d`] should typically already be normalized by design.
/// Note that [`Rot2`] should typically already be normalized by design.
/// Manual normalization is only needed when successive operations result in
/// accumulated floating point error, or if the rotation was constructed
/// with invalid values.
@ -248,7 +249,7 @@ impl Rotation2d {
(self.length_squared() - 1.0).abs() <= 2e-4
}
/// Returns `true` if the rotation is near [`Rotation2d::IDENTITY`].
/// Returns `true` if the rotation is near [`Rot2::IDENTITY`].
#[inline]
pub fn is_near_identity(self) -> bool {
// Same as `Quat::is_near_identity`, but using sine and cosine
@ -300,10 +301,10 @@ impl Rotation2d {
/// # Example
///
/// ```
/// # use bevy_math::Rotation2d;
/// # use bevy_math::Rot2;
/// #
/// let rot1 = Rotation2d::IDENTITY;
/// let rot2 = Rotation2d::degrees(135.0);
/// let rot1 = Rot2::IDENTITY;
/// let rot2 = Rot2::degrees(135.0);
///
/// let result1 = rot1.nlerp(rot2, 1.0 / 3.0);
/// assert_eq!(result1.as_degrees(), 28.675055);
@ -338,10 +339,10 @@ impl Rotation2d {
/// # Example
///
/// ```
/// # use bevy_math::Rotation2d;
/// # use bevy_math::Rot2;
/// #
/// let rot1 = Rotation2d::IDENTITY;
/// let rot2 = Rotation2d::degrees(135.0);
/// let rot1 = Rot2::IDENTITY;
/// let rot2 = Rot2::degrees(135.0);
///
/// let result1 = rot1.slerp(rot2, 1.0 / 3.0);
/// assert_eq!(result1.as_degrees(), 45.0);
@ -355,21 +356,21 @@ impl Rotation2d {
}
}
impl From<f32> for Rotation2d {
/// Creates a [`Rotation2d`] from a counterclockwise angle in radians.
impl From<f32> for Rot2 {
/// Creates a [`Rot2`] from a counterclockwise angle in radians.
fn from(rotation: f32) -> Self {
Self::radians(rotation)
}
}
impl From<Rotation2d> for Mat2 {
/// Creates a [`Mat2`] rotation matrix from a [`Rotation2d`].
fn from(rot: Rotation2d) -> Self {
impl From<Rot2> for Mat2 {
/// Creates a [`Mat2`] rotation matrix from a [`Rot2`].
fn from(rot: Rot2) -> Self {
Mat2::from_cols_array(&[rot.cos, -rot.sin, rot.sin, rot.cos])
}
}
impl std::ops::Mul for Rotation2d {
impl std::ops::Mul for Rot2 {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
@ -380,16 +381,16 @@ impl std::ops::Mul for Rotation2d {
}
}
impl std::ops::MulAssign for Rotation2d {
impl std::ops::MulAssign for Rot2 {
fn mul_assign(&mut self, rhs: Self) {
*self = *self * rhs;
}
}
impl std::ops::Mul<Vec2> for Rotation2d {
impl std::ops::Mul<Vec2> for Rot2 {
type Output = Vec2;
/// Rotates a [`Vec2`] by a [`Rotation2d`].
/// Rotates a [`Vec2`] by a [`Rot2`].
fn mul(self, rhs: Vec2) -> Self::Output {
Vec2::new(
rhs.x * self.cos - rhs.y * self.sin,
@ -399,7 +400,7 @@ impl std::ops::Mul<Vec2> for Rotation2d {
}
#[cfg(any(feature = "approx", test))]
impl approx::AbsDiffEq for Rotation2d {
impl approx::AbsDiffEq for Rot2 {
type Epsilon = f32;
fn default_epsilon() -> f32 {
f32::EPSILON
@ -410,7 +411,7 @@ impl approx::AbsDiffEq for Rotation2d {
}
#[cfg(any(feature = "approx", test))]
impl approx::RelativeEq for Rotation2d {
impl approx::RelativeEq for Rot2 {
fn default_max_relative() -> f32 {
f32::EPSILON
}
@ -421,7 +422,7 @@ impl approx::RelativeEq for Rotation2d {
}
#[cfg(any(feature = "approx", test))]
impl approx::UlpsEq for Rotation2d {
impl approx::UlpsEq for Rot2 {
fn default_max_ulps() -> u32 {
4
}
@ -435,13 +436,13 @@ impl approx::UlpsEq for Rotation2d {
mod tests {
use approx::assert_relative_eq;
use crate::{Dir2, Rotation2d, Vec2};
use crate::{Dir2, Rot2, Vec2};
#[test]
fn creation() {
let rotation1 = Rotation2d::radians(std::f32::consts::FRAC_PI_2);
let rotation2 = Rotation2d::degrees(90.0);
let rotation3 = Rotation2d::from_sin_cos(1.0, 0.0);
let rotation1 = Rot2::radians(std::f32::consts::FRAC_PI_2);
let rotation2 = Rot2::degrees(90.0);
let rotation3 = Rot2::from_sin_cos(1.0, 0.0);
// All three rotations should be equal
assert_relative_eq!(rotation1.sin, rotation2.sin);
@ -456,7 +457,7 @@ mod tests {
#[test]
fn rotate() {
let rotation = Rotation2d::degrees(90.0);
let rotation = Rot2::degrees(90.0);
assert_relative_eq!(rotation * Vec2::X, Vec2::Y);
assert_relative_eq!(rotation * Dir2::Y, Dir2::NEG_X);
@ -464,8 +465,8 @@ mod tests {
#[test]
fn add() {
let rotation1 = Rotation2d::degrees(90.0);
let rotation2 = Rotation2d::degrees(180.0);
let rotation1 = Rot2::degrees(90.0);
let rotation2 = Rot2::degrees(180.0);
// 90 deg + 180 deg becomes -90 deg after it wraps around to be within the ]-180, 180] range
assert_eq!((rotation1 * rotation2).as_degrees(), -90.0);
@ -473,8 +474,8 @@ mod tests {
#[test]
fn subtract() {
let rotation1 = Rotation2d::degrees(90.0);
let rotation2 = Rotation2d::degrees(45.0);
let rotation1 = Rot2::degrees(90.0);
let rotation2 = Rot2::degrees(45.0);
assert_relative_eq!((rotation1 * rotation2.inverse()).as_degrees(), 45.0);
@ -487,7 +488,7 @@ mod tests {
#[test]
fn length() {
let rotation = Rotation2d {
let rotation = Rot2 {
sin: 10.0,
cos: 5.0,
};
@ -499,16 +500,16 @@ mod tests {
#[test]
fn is_near_identity() {
assert!(!Rotation2d::radians(0.1).is_near_identity());
assert!(!Rotation2d::radians(-0.1).is_near_identity());
assert!(Rotation2d::radians(0.00001).is_near_identity());
assert!(Rotation2d::radians(-0.00001).is_near_identity());
assert!(Rotation2d::radians(0.0).is_near_identity());
assert!(!Rot2::radians(0.1).is_near_identity());
assert!(!Rot2::radians(-0.1).is_near_identity());
assert!(Rot2::radians(0.00001).is_near_identity());
assert!(Rot2::radians(-0.00001).is_near_identity());
assert!(Rot2::radians(0.0).is_near_identity());
}
#[test]
fn normalize() {
let rotation = Rotation2d {
let rotation = Rot2 {
sin: 10.0,
cos: 5.0,
};
@ -524,7 +525,7 @@ mod tests {
#[test]
fn try_normalize() {
// Valid
assert!(Rotation2d {
assert!(Rot2 {
sin: 10.0,
cos: 5.0,
}
@ -532,7 +533,7 @@ mod tests {
.is_some());
// NaN
assert!(Rotation2d {
assert!(Rot2 {
sin: f32::NAN,
cos: 5.0,
}
@ -540,10 +541,10 @@ mod tests {
.is_none());
// Zero
assert!(Rotation2d { sin: 0.0, cos: 0.0 }.try_normalize().is_none());
assert!(Rot2 { sin: 0.0, cos: 0.0 }.try_normalize().is_none());
// Non-finite
assert!(Rotation2d {
assert!(Rot2 {
sin: f32::INFINITY,
cos: 5.0,
}
@ -553,16 +554,16 @@ mod tests {
#[test]
fn nlerp() {
let rot1 = Rotation2d::IDENTITY;
let rot2 = Rotation2d::degrees(135.0);
let rot1 = Rot2::IDENTITY;
let rot2 = Rot2::degrees(135.0);
assert_eq!(rot1.nlerp(rot2, 1.0 / 3.0).as_degrees(), 28.675055);
assert!(rot1.nlerp(rot2, 0.0).is_near_identity());
assert_eq!(rot1.nlerp(rot2, 0.5).as_degrees(), 67.5);
assert_eq!(rot1.nlerp(rot2, 1.0).as_degrees(), 135.0);
let rot1 = Rotation2d::IDENTITY;
let rot2 = Rotation2d::from_sin_cos(0.0, -1.0);
let rot1 = Rot2::IDENTITY;
let rot2 = Rot2::from_sin_cos(0.0, -1.0);
assert!(rot1.nlerp(rot2, 1.0 / 3.0).is_near_identity());
assert!(rot1.nlerp(rot2, 0.0).is_near_identity());
@ -573,16 +574,16 @@ mod tests {
#[test]
fn slerp() {
let rot1 = Rotation2d::IDENTITY;
let rot2 = Rotation2d::degrees(135.0);
let rot1 = Rot2::IDENTITY;
let rot2 = Rot2::degrees(135.0);
assert_eq!(rot1.slerp(rot2, 1.0 / 3.0).as_degrees(), 45.0);
assert!(rot1.slerp(rot2, 0.0).is_near_identity());
assert_eq!(rot1.slerp(rot2, 0.5).as_degrees(), 67.5);
assert_eq!(rot1.slerp(rot2, 1.0).as_degrees(), 135.0);
let rot1 = Rotation2d::IDENTITY;
let rot2 = Rotation2d::from_sin_cos(0.0, -1.0);
let rot1 = Rot2::IDENTITY;
let rot2 = Rot2::from_sin_cos(0.0, -1.0);
assert!((rot1.slerp(rot2, 1.0 / 3.0).as_degrees() - 60.0).abs() < 10e-6);
assert!(rot1.slerp(rot2, 0.0).is_near_identity());

View file

@ -25,7 +25,7 @@ use std::f32::consts::TAU;
use crate::{
primitives::{Circle, Sphere},
Dir2, Dir3, Dir3A, Quat, Rotation2d, ShapeSample, Vec3A,
Dir2, Dir3, Dir3A, Quat, Rot2, ShapeSample, Vec3A,
};
use rand::{
distributions::{Distribution, Standard},
@ -86,14 +86,14 @@ impl Distribution<Dir3A> for Standard {
impl FromRng for Dir3A {}
impl Distribution<Rotation2d> for Standard {
impl Distribution<Rot2> for Standard {
#[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Rotation2d {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Rot2 {
let angle = rng.gen_range(0.0..TAU);
Rotation2d::radians(angle)
Rot2::radians(angle)
}
}
impl FromRng for Rotation2d {}
impl FromRng for Rot2 {}
impl FromRng for Quat {}