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]
212 pub fn slerp(&self, other: &Self, t: $Real) -> Self {
213 *self * Self::new(self.angle_between(other) * t)
214 }
215
216 #[inline]
220 pub fn powf(&self, n: $Real) -> Self {
221 Self::new(self.angle() * n)
222 }
223
224 #[inline]
231 pub fn rotate_towards(&self, rhs: &Self, max_angle: $Real) -> Self {
232 let angle_between = self.angle_between(rhs);
233 if angle_between.abs() <= max_angle.abs() {
234 *rhs
235 } else {
236 self.slerp(rhs, max_angle / angle_between)
237 }
238 }
239
240 #[inline]
242 pub fn angle_between(&self, rhs: &Self) -> $Real {
243 let diff = self.inverse() * *rhs;
244 diff.angle()
245 }
246
247 #[inline]
251 pub fn dot(&self, rhs: Self) -> $Real {
252 self.re * rhs.re + self.im * rhs.im
253 }
254
255 #[inline]
262 pub fn lerp(&self, rhs: Self, s: $Real) -> Self {
263 Self {
264 re: self.re + (rhs.re - self.re) * s,
265 im: self.im + (rhs.im - self.im) * s,
266 }
267 }
268
269 #[inline]
273 pub fn normalize_mut(&mut self) {
274 *self = self.normalize();
275 }
276 }
277
278 impl Mul<$Rot2> for $Rot2 {
280 type Output = Self;
281
282 #[inline]
283 fn mul(self, rhs: Self) -> Self::Output {
284 Self {
286 re: self.re * rhs.re - self.im * rhs.im,
287 im: self.re * rhs.im + self.im * rhs.re,
288 }
289 }
290 }
291
292 impl Mul<$Rot2> for &$Rot2 {
294 type Output = $Rot2;
295
296 #[inline]
297 fn mul(self, rhs: $Rot2) -> Self::Output {
298 *self * rhs
299 }
300 }
301
302 impl MulAssign<$Rot2> for $Rot2 {
303 #[inline]
304 fn mul_assign(&mut self, rhs: Self) {
305 *self = *self * rhs;
306 }
307 }
308
309 impl Mul<$Vec2> for $Rot2 {
311 type Output = $Vec2;
312
313 #[inline]
314 fn mul(self, rhs: $Vec2) -> Self::Output {
315 self.transform_vector(rhs)
316 }
317 }
318
319 impl Default for $Rot2 {
320 fn default() -> Self {
321 Self::identity()
322 }
323 }
324
325 #[cfg(feature = "approx")]
326 impl approx::AbsDiffEq for $Rot2 {
327 type Epsilon = $Real;
328
329 fn default_epsilon() -> Self::Epsilon {
330 <$Real>::EPSILON
331 }
332
333 fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
334 (self.re - other.re).abs() <= epsilon && (self.im - other.im).abs() <= epsilon
335 }
336 }
337
338 #[cfg(feature = "approx")]
339 impl approx::RelativeEq for $Rot2 {
340 fn default_max_relative() -> Self::Epsilon {
341 <$Real>::EPSILON
342 }
343
344 fn relative_eq(
345 &self,
346 other: &Self,
347 epsilon: Self::Epsilon,
348 max_relative: Self::Epsilon,
349 ) -> bool {
350 approx::AbsDiffEq::abs_diff_eq(self, other, epsilon.max(max_relative))
351 }
352 }
353
354 #[cfg(feature = "approx")]
355 impl approx::UlpsEq for $Rot2 {
356 fn default_max_ulps() -> u32 {
357 4
358 }
359
360 fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
361 approx::AbsDiffEq::abs_diff_eq(self, other, epsilon)
362 || (self.re.to_bits().abs_diff(other.re.to_bits()) <= max_ulps as _
363 && self.im.to_bits().abs_diff(other.im.to_bits()) <= max_ulps as _)
364 }
365 }
366 };
367}
368
369impl_rot2!(Rot2, f32, glam::Vec2, glam::Mat2);
370#[cfg(feature = "f64")]
371impl_rot2!(DRot2, f64, glam::DVec2, glam::DMat2);
372
373#[cfg(feature = "f64")]
375impl From<Rot2> for DRot2 {
376 #[inline]
377 fn from(r: Rot2) -> Self {
378 Self {
379 re: r.re as f64,
380 im: r.im as f64,
381 }
382 }
383}
384
385#[cfg(feature = "f64")]
386impl From<DRot2> for Rot2 {
387 #[inline]
388 fn from(r: DRot2) -> Self {
389 Self {
390 re: r.re as f32,
391 im: r.im as f32,
392 }
393 }
394}
395
396#[cfg(feature = "nalgebra")]
398mod nalgebra_conv {
399 use super::*;
400
401 impl From<Rot2> for nalgebra::UnitComplex<f32> {
402 fn from(r: Rot2) -> Self {
403 nalgebra::UnitComplex::from_cos_sin_unchecked(r.re, r.im)
404 }
405 }
406
407 impl From<nalgebra::UnitComplex<f32>> for Rot2 {
408 fn from(r: nalgebra::UnitComplex<f32>) -> Self {
409 Self { re: r.re, im: r.im }
410 }
411 }
412
413 #[cfg(feature = "f64")]
414 impl From<DRot2> for nalgebra::UnitComplex<f64> {
415 fn from(r: DRot2) -> Self {
416 nalgebra::UnitComplex::from_cos_sin_unchecked(r.re, r.im)
417 }
418 }
419
420 #[cfg(feature = "f64")]
421 impl From<nalgebra::UnitComplex<f64>> for DRot2 {
422 fn from(r: nalgebra::UnitComplex<f64>) -> Self {
423 Self { re: r.re, im: r.im }
424 }
425 }
426}
427
428#[cfg(test)]
429mod tests {
430 use super::*;
431 use approx::assert_relative_eq;
432 use core::f32::consts::PI;
433
434 #[test]
435 fn test_rot2_identity() {
436 let r = Rot2::IDENTITY;
437 assert_eq!(r.re, 1.0);
438 assert_eq!(r.im, 0.0);
439 assert!(r.is_normalized());
440 }
441
442 #[test]
443 fn test_rot2_new() {
444 let r = Rot2::new(PI / 2.0);
445 assert_relative_eq!(r.re, 0.0, epsilon = 1e-6);
446 assert_relative_eq!(r.im, 1.0, epsilon = 1e-6);
447 assert!(r.is_normalized());
448 }
449
450 #[test]
451 fn test_rot2_angle() {
452 let angle = 0.5;
453 let r = Rot2::new(angle);
454 assert_relative_eq!(r.angle(), angle, epsilon = 1e-6);
455 assert_relative_eq!(r.angle(), angle, epsilon = 1e-6);
456 }
457
458 #[test]
459 fn test_rot2_inverse() {
460 let r = Rot2::new(0.5);
461 let inv = r.inverse();
462 let identity = r * inv;
463 assert_relative_eq!(identity.re, 1.0, epsilon = 1e-6);
464 assert_relative_eq!(identity.im, 0.0, epsilon = 1e-6);
465 }
466
467 #[test]
468 fn test_rot2_transform_vector() {
469 let r = Rot2::new(PI / 2.0);
470 let v = glam::Vec2::new(1.0, 0.0);
471 let result = r.transform_vector(v);
472 assert_relative_eq!(result.x, 0.0, epsilon = 1e-6);
473 assert_relative_eq!(result.y, 1.0, epsilon = 1e-6);
474 let result2 = r * v;
476 assert_relative_eq!(result2.x, 0.0, epsilon = 1e-6);
477 assert_relative_eq!(result2.y, 1.0, epsilon = 1e-6);
478 }
479
480 #[test]
481 fn test_rot2_length() {
482 let r = Rot2::new(0.5);
483 assert_relative_eq!(r.length(), 1.0, epsilon = 1e-6);
484 assert_relative_eq!(r.length_squared(), 1.0, epsilon = 1e-6);
485 }
486
487 #[test]
488 fn test_rot2_from_rotation_arc() {
489 let from = glam::Vec2::new(1.0, 0.0);
490 let to = glam::Vec2::new(0.0, 1.0);
491 let r = Rot2::from_rotation_arc(from, to);
492 assert_relative_eq!(r.angle(), PI / 2.0, epsilon = 1e-6);
493 }
494
495 #[test]
496 fn test_rot2_to_mat2() {
497 let r = Rot2::new(PI / 4.0);
498 let m = r.to_mat();
499 let from_mat = Rot2::from_mat(m);
500 assert_relative_eq!(r.re, from_mat.re, epsilon = 1e-6);
501 assert_relative_eq!(r.im, from_mat.im, epsilon = 1e-6);
502 }
503
504 #[test]
505 fn test_rot2_angle_between() {
506 let r1 = Rot2::new(0.0);
507 let r2 = Rot2::new(PI / 2.0);
508 assert_relative_eq!(r1.angle_between(&r2), PI / 2.0, epsilon = 1e-6);
509 }
510
511 #[test]
512 fn test_rot2_slerp() {
513 let r1 = Rot2::new(0.2);
514 let r2 = Rot2::new(1.0);
515 assert_relative_eq!(r1.slerp(&r2, 0.0).angle(), 0.2, epsilon = 1e-6);
516 assert_relative_eq!(r1.slerp(&r2, 1.0).angle(), 1.0, epsilon = 1e-6);
517 assert_relative_eq!(r1.slerp(&r2, 0.5).angle(), 0.6, epsilon = 1e-6);
518 assert!(r1.slerp(&r2, 0.5).is_normalized());
519 }
520
521 #[test]
522 fn test_rot2_slerp_shortest_arc() {
523 let r1 = Rot2::new(0.0);
525 let r2 = Rot2::new(3.0 * PI / 2.0);
526 assert_relative_eq!(r1.slerp(&r2, 0.5).angle(), -PI / 4.0, epsilon = 1e-6);
527 }
528
529 #[test]
530 fn test_rot2_slerp_across_branch_cut() {
531 let r1 = Rot2::new(3.13);
533 let r2 = Rot2::new(3.15);
534 assert_relative_eq!(r1.slerp(&r2, 0.5).angle(), 3.14, epsilon = 1e-6);
535 assert_relative_eq!(r1.slerp(&r2, 1.0).angle(), r2.angle(), epsilon = 1e-6);
536 }
537
538 #[cfg(feature = "f64")]
539 #[test]
540 fn test_drot2_new() {
541 let r = DRot2::new(core::f64::consts::PI / 2.0);
542 assert_relative_eq!(r.re, 0.0, epsilon = 1e-10);
543 assert_relative_eq!(r.im, 1.0, epsilon = 1e-10);
544 assert!(r.is_normalized());
545 }
546}