1use super::Vec2;
2
3#[repr(C)]
17#[derive(Clone, Copy, PartialEq)]
18#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
19#[cfg_attr(feature = "bytemuck", derive(bytemuck::Pod, bytemuck::Zeroable))]
20pub struct Rot2 {
21 s: f32,
23
24 c: f32,
26}
27
28impl Default for Rot2 {
30 #[inline]
32 fn default() -> Self {
33 Self { s: 0.0, c: 1.0 }
34 }
35}
36
37impl Rot2 {
38 pub const IDENTITY: Self = Self { s: 0.0, c: 1.0 };
40
41 #[inline]
44 pub fn from_angle(angle: f32) -> Self {
45 let (s, c) = angle.sin_cos();
46 Self { s, c }
47 }
48
49 #[inline]
50 pub fn angle(self) -> f32 {
51 self.s.atan2(self.c)
52 }
53
54 #[inline]
56 pub fn length(self) -> f32 {
57 self.c.hypot(self.s)
58 }
59
60 #[inline]
61 pub fn length_squared(self) -> f32 {
62 self.c.powi(2) + self.s.powi(2)
63 }
64
65 #[inline]
66 pub fn is_finite(self) -> bool {
67 self.c.is_finite() && self.s.is_finite()
68 }
69
70 #[must_use]
71 #[inline]
72 pub fn inverse(self) -> Self {
73 Self {
74 s: -self.s,
75 c: self.c,
76 } / self.length_squared()
77 }
78
79 #[must_use]
80 #[inline]
81 pub fn normalized(self) -> Self {
82 let l = self.length();
83 let ret = Self {
84 c: self.c / l,
85 s: self.s / l,
86 };
87 debug_assert!(ret.is_finite());
88 ret
89 }
90}
91
92impl std::fmt::Debug for Rot2 {
93 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
94 if let Some(precision) = f.precision() {
95 write!(
96 f,
97 "Rot2 {{ angle: {:.2$}°, length: {} }}",
98 self.angle().to_degrees(),
99 self.length(),
100 precision
101 )
102 } else {
103 write!(
104 f,
105 "Rot2 {{ angle: {:.1}°, length: {} }}",
106 self.angle().to_degrees(),
107 self.length(),
108 )
109 }
110 }
111}
112
113impl std::ops::Mul<Self> for Rot2 {
114 type Output = Self;
115
116 #[inline]
117 fn mul(self, r: Self) -> Self {
118 Self {
123 c: self.c * r.c - self.s * r.s,
124 s: self.s * r.c + self.c * r.s,
125 }
126 }
127}
128
129impl std::ops::Mul<Vec2> for Rot2 {
131 type Output = Vec2;
132
133 #[inline]
134 fn mul(self, v: Vec2) -> Vec2 {
135 Vec2 {
136 x: self.c * v.x - self.s * v.y,
137 y: self.s * v.x + self.c * v.y,
138 }
139 }
140}
141
142impl std::ops::Mul<Rot2> for f32 {
144 type Output = Rot2;
145
146 #[inline]
147 fn mul(self, r: Rot2) -> Rot2 {
148 Rot2 {
149 c: self * r.c,
150 s: self * r.s,
151 }
152 }
153}
154
155impl std::ops::Mul<f32> for Rot2 {
157 type Output = Self;
158
159 #[inline]
160 fn mul(self, r: f32) -> Self {
161 Self {
162 c: self.c * r,
163 s: self.s * r,
164 }
165 }
166}
167
168impl std::ops::Div<f32> for Rot2 {
170 type Output = Self;
171
172 #[inline]
173 fn div(self, r: f32) -> Self {
174 Self {
175 c: self.c / r,
176 s: self.s / r,
177 }
178 }
179}
180
181#[cfg(test)]
182mod test {
183 use super::Rot2;
184 use crate::vec2;
185
186 #[test]
187 fn test_rotation2() {
188 {
189 let angle = std::f32::consts::TAU / 6.0;
190 let rot = Rot2::from_angle(angle);
191 assert!((rot.angle() - angle).abs() < 1e-5);
192 assert!((rot * rot.inverse()).angle().abs() < 1e-5);
193 assert!((rot.inverse() * rot).angle().abs() < 1e-5);
194 }
195
196 {
197 let angle = std::f32::consts::TAU / 4.0;
198 let rot = Rot2::from_angle(angle);
199 assert!(((rot * vec2(1.0, 0.0)) - vec2(0.0, 1.0)).length() < 1e-5);
200 }
201
202 {
203 let angle = std::f32::consts::TAU / 4.0;
205 let rot = 3.0 * Rot2::from_angle(angle);
206 let rotated = rot * vec2(1.0, 0.0);
207 let expected = vec2(0.0, 3.0);
208 assert!(
209 (rotated - expected).length() < 1e-5,
210 "Expected {rotated:?} to equal {expected:?}. rot: {rot:?}",
211 );
212
213 let undone = rot.inverse() * rot;
214 assert!(undone.angle().abs() < 1e-5);
215 assert!((undone.length() - 1.0).abs() < 1e-5,);
216 }
217 }
218}