2020-12-25 11:22:10 +00:00
|
|
|
use super::Vec2;
|
|
|
|
|
|
|
|
// {s,c} represents the rotation matrix:
|
|
|
|
//
|
|
|
|
// | c -s |
|
|
|
|
// | s c |
|
|
|
|
//
|
|
|
|
// `vec2(c,s)` represents where the X axis will end up after rotation.
|
|
|
|
//
|
|
|
|
/// Represents a rotation in the 2D plane.
|
2021-02-14 09:33:44 +00:00
|
|
|
//
|
2020-12-27 11:57:15 +00:00
|
|
|
/// A rotation of 𝞃/4 = 90° rotates the X axis to the Y axis.
|
2021-02-14 09:33:44 +00:00
|
|
|
//
|
2022-04-03 16:18:35 +00:00
|
|
|
/// Normally a [`Rot2`] is normalized (unit-length).
|
2020-12-25 11:22:10 +00:00
|
|
|
/// If not, it will also scale vectors.
|
2021-10-07 20:30:15 +00:00
|
|
|
#[repr(C)]
|
2020-12-25 11:22:10 +00:00
|
|
|
#[derive(Clone, Copy, PartialEq)]
|
2021-10-07 20:30:15 +00:00
|
|
|
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
|
|
|
#[cfg_attr(feature = "bytemuck", derive(bytemuck::Pod, bytemuck::Zeroable))]
|
2020-12-25 11:22:10 +00:00
|
|
|
pub struct Rot2 {
|
|
|
|
/// angle.sin()
|
|
|
|
s: f32,
|
2022-08-02 15:26:33 +00:00
|
|
|
|
2020-12-25 11:22:10 +00:00
|
|
|
/// angle.cos()
|
|
|
|
c: f32,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Identity rotation
|
|
|
|
impl Default for Rot2 {
|
|
|
|
/// Identity rotation
|
|
|
|
fn default() -> Self {
|
|
|
|
Self { s: 0.0, c: 1.0 }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Rot2 {
|
2021-02-05 08:49:21 +00:00
|
|
|
/// The identity rotation: nothing rotates
|
|
|
|
pub const IDENTITY: Self = Self { s: 0.0, c: 1.0 };
|
|
|
|
|
2021-09-05 07:06:53 +00:00
|
|
|
/// Angle is clockwise in radians.
|
2020-12-27 11:57:15 +00:00
|
|
|
/// A 𝞃/4 = 90° rotation means rotating the X axis to the Y axis.
|
2020-12-25 11:22:10 +00:00
|
|
|
pub fn from_angle(angle: f32) -> Self {
|
|
|
|
let (s, c) = angle.sin_cos();
|
|
|
|
Self { s, c }
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn angle(self) -> f32 {
|
|
|
|
self.s.atan2(self.c)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// The factor by which vectors will be scaled.
|
|
|
|
pub fn length(self) -> f32 {
|
|
|
|
self.c.hypot(self.s)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn length_squared(self) -> f32 {
|
|
|
|
self.c.powi(2) + self.s.powi(2)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn is_finite(self) -> bool {
|
|
|
|
self.c.is_finite() && self.s.is_finite()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[must_use]
|
|
|
|
pub fn inverse(self) -> Rot2 {
|
|
|
|
Self {
|
|
|
|
s: -self.s,
|
|
|
|
c: self.c,
|
|
|
|
} / self.length_squared()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[must_use]
|
|
|
|
pub fn normalized(self) -> Self {
|
|
|
|
let l = self.length();
|
|
|
|
let ret = Self {
|
|
|
|
c: self.c / l,
|
|
|
|
s: self.s / l,
|
|
|
|
};
|
2021-05-17 20:34:29 +00:00
|
|
|
crate::emath_assert!(ret.is_finite());
|
2020-12-25 11:22:10 +00:00
|
|
|
ret
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl std::fmt::Debug for Rot2 {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
write!(
|
|
|
|
f,
|
|
|
|
"Rot2 {{ angle: {:.1}°, length: {} }}",
|
|
|
|
self.angle().to_degrees(),
|
|
|
|
self.length()
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl std::ops::Mul<Rot2> for Rot2 {
|
|
|
|
type Output = Rot2;
|
2022-08-02 15:26:33 +00:00
|
|
|
|
2020-12-25 11:22:10 +00:00
|
|
|
fn mul(self, r: Rot2) -> Rot2 {
|
|
|
|
/*
|
|
|
|
|lc -ls| * |rc -rs|
|
|
|
|
|ls lc| |rs rc|
|
|
|
|
*/
|
|
|
|
Rot2 {
|
|
|
|
c: self.c * r.c - self.s * r.s,
|
|
|
|
s: self.s * r.c + self.c * r.s,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-14 09:33:44 +00:00
|
|
|
/// Rotates (and maybe scales) the vector.
|
2020-12-25 11:22:10 +00:00
|
|
|
impl std::ops::Mul<Vec2> for Rot2 {
|
|
|
|
type Output = Vec2;
|
2022-08-02 15:26:33 +00:00
|
|
|
|
2020-12-25 11:22:10 +00:00
|
|
|
fn mul(self, v: Vec2) -> Vec2 {
|
|
|
|
Vec2 {
|
|
|
|
x: self.c * v.x - self.s * v.y,
|
|
|
|
y: self.s * v.x + self.c * v.y,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-14 09:33:44 +00:00
|
|
|
/// Scales the rotor.
|
2020-12-25 11:22:10 +00:00
|
|
|
impl std::ops::Mul<Rot2> for f32 {
|
|
|
|
type Output = Rot2;
|
2022-08-02 15:26:33 +00:00
|
|
|
|
2020-12-25 11:22:10 +00:00
|
|
|
fn mul(self, r: Rot2) -> Rot2 {
|
|
|
|
Rot2 {
|
|
|
|
c: self * r.c,
|
|
|
|
s: self * r.s,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-14 09:33:44 +00:00
|
|
|
/// Scales the rotor.
|
2020-12-25 11:22:10 +00:00
|
|
|
impl std::ops::Mul<f32> for Rot2 {
|
|
|
|
type Output = Rot2;
|
2022-08-02 15:26:33 +00:00
|
|
|
|
2020-12-25 11:22:10 +00:00
|
|
|
fn mul(self, r: f32) -> Rot2 {
|
|
|
|
Rot2 {
|
|
|
|
c: self.c * r,
|
|
|
|
s: self.s * r,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-14 09:33:44 +00:00
|
|
|
/// Scales the rotor.
|
2020-12-25 11:22:10 +00:00
|
|
|
impl std::ops::Div<f32> for Rot2 {
|
|
|
|
type Output = Rot2;
|
2022-08-02 15:26:33 +00:00
|
|
|
|
2020-12-25 11:22:10 +00:00
|
|
|
fn div(self, r: f32) -> Rot2 {
|
|
|
|
Rot2 {
|
|
|
|
c: self.c / r,
|
|
|
|
s: self.s / r,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
|
|
|
use super::Rot2;
|
|
|
|
use crate::vec2;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_rotation2() {
|
|
|
|
{
|
|
|
|
let angle = std::f32::consts::TAU / 6.0;
|
|
|
|
let rot = Rot2::from_angle(angle);
|
|
|
|
assert!((rot.angle() - angle).abs() < 1e-5);
|
|
|
|
assert!((rot * rot.inverse()).angle().abs() < 1e-5);
|
|
|
|
assert!((rot.inverse() * rot).angle().abs() < 1e-5);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
let angle = std::f32::consts::TAU / 4.0;
|
|
|
|
let rot = Rot2::from_angle(angle);
|
|
|
|
assert!(((rot * vec2(1.0, 0.0)) - vec2(0.0, 1.0)).length() < 1e-5);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
// Test rotation and scaling
|
|
|
|
let angle = std::f32::consts::TAU / 4.0;
|
|
|
|
let rot = 3.0 * Rot2::from_angle(angle);
|
|
|
|
let rotated = rot * vec2(1.0, 0.0);
|
|
|
|
let expected = vec2(0.0, 3.0);
|
|
|
|
assert!(
|
|
|
|
(rotated - expected).length() < 1e-5,
|
|
|
|
"Expected {:?} to equal {:?}. rot: {:?}",
|
|
|
|
rotated,
|
|
|
|
expected,
|
|
|
|
rot,
|
|
|
|
);
|
|
|
|
|
|
|
|
let undone = rot.inverse() * rot;
|
|
|
|
assert!(undone.angle().abs() < 1e-5);
|
|
|
|
assert!((undone.length() - 1.0).abs() < 1e-5,);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|