1use core::ops::{Mul, MulAssign};
4use simba::scalar::{ComplexField, RealField};
5
6macro_rules! impl_rot2 {
8 ($Rot2:ident, $Real:ty, $Vec2:ty, $Mat2:ty $(, #[$attr:meta])*) => {
9 #[doc = concat!("A 2D rotation represented as a unit complex number (", stringify!($Real), " precision).")]
10 #[derive(Copy, Clone, Debug, PartialEq)]
13 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
14 #[cfg_attr(feature = "bytemuck", derive(bytemuck::Pod, bytemuck::Zeroable))]
15 #[cfg_attr(feature = "rkyv", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
16 #[repr(C)]
17 $(#[$attr])*
18 pub struct $Rot2 {
19 pub re: $Real,
21 pub im: $Real,
23 }
24
25 impl $Rot2 {
26 pub const IDENTITY: Self = Self { re: 1.0, im: 0.0 };
28
29 #[inline]
33 pub const fn from_cos_sin_unchecked(re: $Real, im: $Real) -> Self {
34 Self { re, im }
35 }
36
37 #[inline]
39 pub fn from_matrix_unchecked(mat: $Mat2) -> Self {
40 Self {
41 re: mat.x_axis.x,
42 im: mat.x_axis.y,
43 }
44 }
45
46 #[inline]
48 pub fn identity() -> Self {
49 Self::IDENTITY
50 }
51
52 #[inline]
54 pub fn new(angle: $Real) -> Self {
55 let (im, re) = <$Real as ComplexField>::sin_cos(angle);
56 Self { re, im }
57 }
58
59 #[inline]
61 pub fn from_angle(angle: $Real) -> Self {
62 Self::new(angle)
63 }
64
65 #[inline]
67 pub fn angle(&self) -> $Real {
68 RealField::atan2(self.im, self.re)
69 }
70
71 #[inline]
73 pub fn cos(&self) -> $Real {
74 self.re
75 }
76
77 #[inline]
79 pub fn sin(&self) -> $Real {
80 self.im
81 }
82
83 #[inline]
85 pub fn inverse(self) -> Self {
86 Self {
87 re: self.re,
88 im: -self.im,
89 }
90 }
91
92 #[inline]
96 pub fn length(&self) -> $Real {
97 <$Real as ComplexField>::sqrt(self.re * self.re + self.im * self.im)
98 }
99
100 #[inline]
105 pub fn length_squared(&self) -> $Real {
106 self.re * self.re + self.im * self.im
107 }
108
109 #[inline]
111 pub fn length_recip(&self) -> $Real {
112 1.0 / self.length()
113 }
114
115 #[inline]
119 pub fn normalize(&self) -> Self {
120 let len = self.length();
121 if len > <$Real>::EPSILON {
122 Self {
123 re: self.re / len,
124 im: self.im / len,
125 }
126 } else {
127 Self::IDENTITY
128 }
129 }
130
131 #[inline]
133 pub fn is_finite(&self) -> bool {
134 self.re.is_finite() && self.im.is_finite()
135 }
136
137 #[inline]
139 pub fn is_nan(&self) -> bool {
140 self.re.is_nan() || self.im.is_nan()
141 }
142
143 #[inline]
147 pub fn is_normalized(&self) -> bool {
148 (self.length_squared() - 1.0).abs() < 2e-4
149 }
150
151 #[inline]
153 pub fn transform_vector(&self, v: $Vec2) -> $Vec2 {
154 <$Vec2>::new(self.re * v.x - self.im * v.y, self.im * v.x + self.re * v.y)
155 }
156
157 #[inline]
159 pub fn inverse_transform_vector(&self, v: $Vec2) -> $Vec2 {
160 <$Vec2>::new(
161 self.re * v.x + self.im * v.y,
162 -self.im * v.x + self.re * v.y,
163 )
164 }
165
166 #[inline]
168 pub fn to_mat(&self) -> $Mat2 {
169 <$Mat2>::from_cols(
170 <$Vec2>::new(self.re, self.im),
171 <$Vec2>::new(-self.im, self.re),
172 )
173 }
174
175 #[inline]
179 pub fn from_mat(mat: $Mat2) -> Self {
180 Self::from_mat_unchecked(mat).normalize()
181 }
182
183 #[inline]
187 pub fn from_mat_unchecked(mat: $Mat2) -> Self {
188 Self::from_matrix_unchecked(mat)
189 }
190
191 #[inline]
196 pub fn from_rotation_arc(from: $Vec2, to: $Vec2) -> Self {
197 let re = from.dot(to);
201 let im = from.x * to.y - from.y * to.x;
202 Self { re, im }
203 }
204
205 #[inline]
207 pub fn slerp(&self, other: &Self, t: $Real) -> Self {
208 let angle_diff = other.angle() - self.angle();
209 Self::new(self.angle() + t * angle_diff)
210 }
211
212 #[inline]
216 pub fn powf(&self, n: $Real) -> Self {
217 Self::new(self.angle() * n)
218 }
219
220 #[inline]
227 pub fn rotate_towards(&self, rhs: &Self, max_angle: $Real) -> Self {
228 let angle_between = self.angle_between(rhs);
229 if angle_between.abs() <= max_angle.abs() {
230 *rhs
231 } else {
232 self.slerp(rhs, max_angle / angle_between)
233 }
234 }
235
236 #[inline]
238 pub fn angle_between(&self, rhs: &Self) -> $Real {
239 let diff = self.inverse() * *rhs;
240 diff.angle()
241 }
242
243 #[inline]
247 pub fn dot(&self, rhs: Self) -> $Real {
248 self.re * rhs.re + self.im * rhs.im
249 }
250
251 #[inline]
258 pub fn lerp(&self, rhs: Self, s: $Real) -> Self {
259 Self {
260 re: self.re + (rhs.re - self.re) * s,
261 im: self.im + (rhs.im - self.im) * s,
262 }
263 }
264
265 #[inline]
269 pub fn normalize_mut(&mut self) {
270 *self = self.normalize();
271 }
272 }
273
274 impl Mul<$Rot2> for $Rot2 {
276 type Output = Self;
277
278 #[inline]
279 fn mul(self, rhs: Self) -> Self::Output {
280 Self {
282 re: self.re * rhs.re - self.im * rhs.im,
283 im: self.re * rhs.im + self.im * rhs.re,
284 }
285 }
286 }
287
288 impl Mul<$Rot2> for &$Rot2 {
290 type Output = $Rot2;
291
292 #[inline]
293 fn mul(self, rhs: $Rot2) -> Self::Output {
294 *self * rhs
295 }
296 }
297
298 impl MulAssign<$Rot2> for $Rot2 {
299 #[inline]
300 fn mul_assign(&mut self, rhs: Self) {
301 *self = *self * rhs;
302 }
303 }
304
305 impl Mul<$Vec2> for $Rot2 {
307 type Output = $Vec2;
308
309 #[inline]
310 fn mul(self, rhs: $Vec2) -> Self::Output {
311 self.transform_vector(rhs)
312 }
313 }
314
315 impl Default for $Rot2 {
316 fn default() -> Self {
317 Self::identity()
318 }
319 }
320
321 #[cfg(feature = "approx")]
322 impl approx::AbsDiffEq for $Rot2 {
323 type Epsilon = $Real;
324
325 fn default_epsilon() -> Self::Epsilon {
326 <$Real>::EPSILON
327 }
328
329 fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
330 (self.re - other.re).abs() <= epsilon && (self.im - other.im).abs() <= epsilon
331 }
332 }
333
334 #[cfg(feature = "approx")]
335 impl approx::RelativeEq for $Rot2 {
336 fn default_max_relative() -> Self::Epsilon {
337 <$Real>::EPSILON
338 }
339
340 fn relative_eq(
341 &self,
342 other: &Self,
343 epsilon: Self::Epsilon,
344 max_relative: Self::Epsilon,
345 ) -> bool {
346 approx::AbsDiffEq::abs_diff_eq(self, other, epsilon.max(max_relative))
347 }
348 }
349
350 #[cfg(feature = "approx")]
351 impl approx::UlpsEq for $Rot2 {
352 fn default_max_ulps() -> u32 {
353 4
354 }
355
356 fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
357 approx::AbsDiffEq::abs_diff_eq(self, other, epsilon)
358 || (self.re.to_bits().abs_diff(other.re.to_bits()) <= max_ulps as _
359 && self.im.to_bits().abs_diff(other.im.to_bits()) <= max_ulps as _)
360 }
361 }
362 };
363}
364
365impl_rot2!(Rot2, f32, glam::Vec2, glam::Mat2);
366impl_rot2!(DRot2, f64, glam::DVec2, glam::DMat2);
367
368impl From<Rot2> for DRot2 {
370 #[inline]
371 fn from(r: Rot2) -> Self {
372 Self {
373 re: r.re as f64,
374 im: r.im as f64,
375 }
376 }
377}
378
379impl From<DRot2> for Rot2 {
380 #[inline]
381 fn from(r: DRot2) -> Self {
382 Self {
383 re: r.re as f32,
384 im: r.im as f32,
385 }
386 }
387}
388
389#[cfg(feature = "nalgebra")]
391mod nalgebra_conv {
392 use super::*;
393
394 impl From<Rot2> for nalgebra::UnitComplex<f32> {
395 fn from(r: Rot2) -> Self {
396 nalgebra::UnitComplex::from_cos_sin_unchecked(r.re, r.im)
397 }
398 }
399
400 impl From<nalgebra::UnitComplex<f32>> for Rot2 {
401 fn from(r: nalgebra::UnitComplex<f32>) -> Self {
402 Self { re: r.re, im: r.im }
403 }
404 }
405
406 impl From<DRot2> for nalgebra::UnitComplex<f64> {
407 fn from(r: DRot2) -> Self {
408 nalgebra::UnitComplex::from_cos_sin_unchecked(r.re, r.im)
409 }
410 }
411
412 impl From<nalgebra::UnitComplex<f64>> for DRot2 {
413 fn from(r: nalgebra::UnitComplex<f64>) -> Self {
414 Self { re: r.re, im: r.im }
415 }
416 }
417}
418
419#[cfg(test)]
420mod tests {
421 use super::*;
422 use approx::assert_relative_eq;
423 use core::f32::consts::PI;
424
425 #[test]
426 fn test_rot2_identity() {
427 let r = Rot2::IDENTITY;
428 assert_eq!(r.re, 1.0);
429 assert_eq!(r.im, 0.0);
430 assert!(r.is_normalized());
431 }
432
433 #[test]
434 fn test_rot2_new() {
435 let r = Rot2::new(PI / 2.0);
436 assert_relative_eq!(r.re, 0.0, epsilon = 1e-6);
437 assert_relative_eq!(r.im, 1.0, epsilon = 1e-6);
438 assert!(r.is_normalized());
439 }
440
441 #[test]
442 fn test_rot2_angle() {
443 let angle = 0.5;
444 let r = Rot2::new(angle);
445 assert_relative_eq!(r.angle(), angle, epsilon = 1e-6);
446 assert_relative_eq!(r.angle(), angle, epsilon = 1e-6);
447 }
448
449 #[test]
450 fn test_rot2_inverse() {
451 let r = Rot2::new(0.5);
452 let inv = r.inverse();
453 let identity = r * inv;
454 assert_relative_eq!(identity.re, 1.0, epsilon = 1e-6);
455 assert_relative_eq!(identity.im, 0.0, epsilon = 1e-6);
456 }
457
458 #[test]
459 fn test_rot2_transform_vector() {
460 let r = Rot2::new(PI / 2.0);
461 let v = glam::Vec2::new(1.0, 0.0);
462 let result = r.transform_vector(v);
463 assert_relative_eq!(result.x, 0.0, epsilon = 1e-6);
464 assert_relative_eq!(result.y, 1.0, epsilon = 1e-6);
465 let result2 = r * v;
467 assert_relative_eq!(result2.x, 0.0, epsilon = 1e-6);
468 assert_relative_eq!(result2.y, 1.0, epsilon = 1e-6);
469 }
470
471 #[test]
472 fn test_rot2_length() {
473 let r = Rot2::new(0.5);
474 assert_relative_eq!(r.length(), 1.0, epsilon = 1e-6);
475 assert_relative_eq!(r.length_squared(), 1.0, epsilon = 1e-6);
476 }
477
478 #[test]
479 fn test_rot2_from_rotation_arc() {
480 let from = glam::Vec2::new(1.0, 0.0);
481 let to = glam::Vec2::new(0.0, 1.0);
482 let r = Rot2::from_rotation_arc(from, to);
483 assert_relative_eq!(r.angle(), PI / 2.0, epsilon = 1e-6);
484 }
485
486 #[test]
487 fn test_rot2_to_mat2() {
488 let r = Rot2::new(PI / 4.0);
489 let m = r.to_mat();
490 let from_mat = Rot2::from_mat(m);
491 assert_relative_eq!(r.re, from_mat.re, epsilon = 1e-6);
492 assert_relative_eq!(r.im, from_mat.im, epsilon = 1e-6);
493 }
494
495 #[test]
496 fn test_rot2_angle_between() {
497 let r1 = Rot2::new(0.0);
498 let r2 = Rot2::new(PI / 2.0);
499 assert_relative_eq!(r1.angle_between(&r2), PI / 2.0, epsilon = 1e-6);
500 }
501
502 #[test]
503 fn test_drot2_new() {
504 let r = DRot2::new(core::f64::consts::PI / 2.0);
505 assert_relative_eq!(r.re, 0.0, epsilon = 1e-10);
506 assert_relative_eq!(r.im, 1.0, epsilon = 1e-10);
507 assert!(r.is_normalized());
508 }
509}