vecmat/complex/
quaternion.rs

1use crate::{
2    complex::Complex,
3    matrix::Matrix4x4,
4    traits::{Conj, Dot, NormL1, NormL2, Normalize},
5    vector::{Vector3, Vector4},
6};
7use core::{
8    iter::{Product, Sum},
9    ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, Sub, SubAssign},
10};
11use num_traits::{Float, Inv, Num, One, Zero};
12
13/// Quaternion.
14#[repr(transparent)]
15#[derive(Clone, Copy, Default, PartialEq)]
16pub struct Quaternion<T> {
17    vec: Vector4<T>,
18}
19
20impl<T> Quaternion<T> {
21    pub fn new(w: T, x: T, y: T, z: T) -> Self {
22        Self {
23            vec: [w, x, y, z].into(),
24        }
25    }
26    pub fn from_vector(vec: Vector4<T>) -> Self {
27        Self { vec }
28    }
29    pub fn from_array(arr: [T; 4]) -> Self {
30        Self { vec: arr.into() }
31    }
32    pub fn from_tuple(tup: (T, T, T, T)) -> Self {
33        Self { vec: tup.into() }
34    }
35    pub fn from_scalar_and_vector3(w: T, vec: Vector3<T>) -> Self {
36        let (x, y, z) = vec.into();
37        Self::new(w, x, y, z)
38    }
39    pub fn into_vector(self) -> Vector4<T> {
40        self.vec
41    }
42    pub fn into_array(self) -> [T; 4] {
43        self.vec.into()
44    }
45    pub fn into_tuple(self) -> (T, T, T, T) {
46        self.vec.into()
47    }
48    pub fn into_scalar_and_vector3(self) -> (T, Vector3<T>) {
49        let (w, x, y, z) = self.vec.into();
50        (w, [x, y, z].into())
51    }
52}
53
54impl<T> From<Vector4<T>> for Quaternion<T> {
55    fn from(vec: Vector4<T>) -> Self {
56        Self::from_vector(vec)
57    }
58}
59impl<T> From<Quaternion<T>> for Vector4<T> {
60    fn from(quat: Quaternion<T>) -> Self {
61        quat.into_vector()
62    }
63}
64impl<T> From<(T, Vector3<T>)> for Quaternion<T> {
65    fn from((w, vec): (T, Vector3<T>)) -> Self {
66        Self::from_scalar_and_vector3(w, vec)
67    }
68}
69impl<T> From<Quaternion<T>> for (T, Vector3<T>) {
70    fn from(quat: Quaternion<T>) -> Self {
71        quat.into_scalar_and_vector3()
72    }
73}
74impl<T> From<[T; 4]> for Quaternion<T> {
75    fn from(arr: [T; 4]) -> Self {
76        Self::from_array(arr)
77    }
78}
79impl<T> From<Quaternion<T>> for [T; 4] {
80    fn from(quat: Quaternion<T>) -> Self {
81        quat.into_array()
82    }
83}
84impl<T> From<(T, T, T, T)> for Quaternion<T> {
85    fn from(tup: (T, T, T, T)) -> Self {
86        Self::from_tuple(tup)
87    }
88}
89impl<T> From<Quaternion<T>> for (T, T, T, T) {
90    fn from(quat: Quaternion<T>) -> Self {
91        quat.into_tuple()
92    }
93}
94
95impl<T> Quaternion<T>
96where
97    T: Copy,
98{
99    pub fn w(&self) -> T {
100        self.vec.x()
101    }
102    pub fn x(&self) -> T {
103        self.vec.y()
104    }
105    pub fn y(&self) -> T {
106        self.vec.z()
107    }
108    pub fn z(&self) -> T {
109        self.vec.w()
110    }
111    pub fn xyz(&self) -> Vector3<T> {
112        <Self as Into<(T, Vector3<T>)>>::into(*self).1
113    }
114}
115
116impl<T> Quaternion<T> {
117    pub fn w_ref(&self) -> &T {
118        self.vec.x_ref()
119    }
120    pub fn x_ref(&self) -> &T {
121        self.vec.y_ref()
122    }
123    pub fn y_ref(&self) -> &T {
124        self.vec.z_ref()
125    }
126    pub fn z_ref(&self) -> &T {
127        self.vec.w_ref()
128    }
129    pub fn w_mut(&mut self) -> &mut T {
130        self.vec.x_mut()
131    }
132    pub fn x_mut(&mut self) -> &mut T {
133        self.vec.y_mut()
134    }
135    pub fn y_mut(&mut self) -> &mut T {
136        self.vec.z_mut()
137    }
138    pub fn z_mut(&mut self) -> &mut T {
139        self.vec.w_mut()
140    }
141}
142
143impl<T> Quaternion<T>
144where
145    T: Neg<Output = T> + Copy,
146{
147    pub fn into_matrix(self) -> Matrix4x4<T> {
148        let (w, x, y, z) = self.into();
149        Matrix4x4::from([[w, -x, -y, -z], [x, w, -z, y], [y, z, w, -x], [z, -y, x, w]])
150    }
151}
152
153impl<T> Neg for Quaternion<T>
154where
155    T: Neg<Output = T>,
156{
157    type Output = Self;
158    fn neg(self) -> Self {
159        (-self.vec).into()
160    }
161}
162
163impl<T> Quaternion<T>
164where
165    T: Neg<Output = T>,
166{
167    pub fn conj(self) -> Self {
168        let (w, x, y, z) = self.into();
169        Self::new(w, -x, -y, -z)
170    }
171}
172
173impl<T> Conj for Quaternion<T>
174where
175    T: Neg<Output = T>,
176{
177    fn conj(self) -> Self {
178        Quaternion::conj(self)
179    }
180}
181
182impl<T> Add for Quaternion<T>
183where
184    T: Add<Output = T>,
185{
186    type Output = Self;
187    fn add(self, other: Self) -> Self {
188        (self.vec + other.vec).into()
189    }
190}
191impl<T> Add<Complex<T>> for Quaternion<T>
192where
193    T: Add<Output = T>,
194{
195    type Output = Self;
196    fn add(self, other: Complex<T>) -> Self {
197        let (w, x, y, z) = self.into();
198        let (re, im) = other.into();
199        Self::new(w + re, x + im, y, z)
200    }
201}
202impl<T> Add<T> for Quaternion<T>
203where
204    T: Add<Output = T>,
205{
206    type Output = Self;
207    fn add(self, other: T) -> Self {
208        let (w, x, y, z) = self.into();
209        Self::new(w + other, x, y, z)
210    }
211}
212impl<T> Sub for Quaternion<T>
213where
214    T: Sub<Output = T>,
215{
216    type Output = Self;
217    fn sub(self, other: Self) -> Self {
218        (self.vec - other.vec).into()
219    }
220}
221impl<T> Sub<Complex<T>> for Quaternion<T>
222where
223    T: Sub<Output = T>,
224{
225    type Output = Self;
226    fn sub(self, other: Complex<T>) -> Self {
227        let (w, x, y, z) = self.into();
228        let (re, im) = other.into();
229        Self::new(w - re, x - im, y, z)
230    }
231}
232impl<T> Sub<T> for Quaternion<T>
233where
234    T: Sub<Output = T>,
235{
236    type Output = Self;
237    fn sub(self, other: T) -> Self {
238        let (w, x, y, z) = self.into();
239        Self::new(w - other, x, y, z)
240    }
241}
242
243macro_rules! reverse_add_sub {
244    ($T:ident) => {
245        /// Workaround for reverse addition.
246        impl Add<Quaternion<$T>> for $T {
247            type Output = Quaternion<$T>;
248            fn add(self, other: Quaternion<$T>) -> Self::Output {
249                other + self
250            }
251        }
252        /// Workaround for reverse addition.
253        impl Add<Quaternion<$T>> for Complex<$T> {
254            type Output = Quaternion<$T>;
255            fn add(self, other: Quaternion<$T>) -> Self::Output {
256                other + self
257            }
258        }
259        /// Workaround for reverse subtraction.
260        impl Sub<Quaternion<$T>> for $T {
261            type Output = Quaternion<$T>;
262            fn sub(self, other: Quaternion<$T>) -> Self::Output {
263                -other + self
264            }
265        }
266        /// Workaround for reverse subtraction.
267        impl Sub<Quaternion<$T>> for Complex<$T> {
268            type Output = Quaternion<$T>;
269            fn sub(self, other: Quaternion<$T>) -> Self::Output {
270                -other + self
271            }
272        }
273    };
274}
275
276reverse_add_sub!(f32);
277reverse_add_sub!(f64);
278
279impl<T> AddAssign for Quaternion<T>
280where
281    T: AddAssign,
282{
283    fn add_assign(&mut self, other: Self) {
284        self.vec += other.vec;
285    }
286}
287impl<T> AddAssign<Complex<T>> for Quaternion<T>
288where
289    T: AddAssign,
290{
291    fn add_assign(&mut self, other: Complex<T>) {
292        let (re, im) = other.into();
293        *self.w_mut() += re;
294        *self.x_mut() += im;
295    }
296}
297impl<T> AddAssign<T> for Quaternion<T>
298where
299    T: AddAssign,
300{
301    fn add_assign(&mut self, other: T) {
302        *self.w_mut() += other;
303    }
304}
305impl<T> SubAssign for Quaternion<T>
306where
307    T: SubAssign,
308{
309    fn sub_assign(&mut self, other: Self) {
310        self.vec -= other.vec;
311    }
312}
313impl<T> SubAssign<Complex<T>> for Quaternion<T>
314where
315    T: SubAssign,
316{
317    fn sub_assign(&mut self, other: Complex<T>) {
318        let (re, im) = other.into();
319        *self.w_mut() -= re;
320        *self.x_mut() -= im;
321    }
322}
323impl<T> SubAssign<T> for Quaternion<T>
324where
325    T: SubAssign,
326{
327    fn sub_assign(&mut self, other: T) {
328        *self.w_mut() -= other;
329    }
330}
331
332impl<T> Zero for Quaternion<T>
333where
334    T: Zero,
335{
336    fn zero() -> Self {
337        Self::new(T::zero(), T::zero(), T::zero(), T::zero())
338    }
339    fn is_zero(&self) -> bool {
340        self.vec.is_zero()
341    }
342}
343
344impl<T> Mul for Quaternion<T>
345where
346    T: Add<Output = T> + Sub<Output = T> + Mul<Output = T> + Copy,
347{
348    type Output = Self;
349    fn mul(self, other: Self) -> Self {
350        Self::new(
351            self.w() * other.w()
352                - self.x() * other.x()
353                - self.y() * other.y()
354                - self.z() * other.z(),
355            self.w() * other.x() + self.x() * other.w() + self.y() * other.z()
356                - self.z() * other.y(),
357            self.w() * other.y() - self.x() * other.z()
358                + self.y() * other.w()
359                + self.z() * other.x(),
360            self.w() * other.z() + self.x() * other.y() - self.y() * other.x()
361                + self.z() * other.w(),
362        )
363    }
364}
365impl<T> Mul<Complex<T>> for Quaternion<T>
366where
367    T: Add<Output = T> + Sub<Output = T> + Mul<Output = T> + Copy,
368{
369    type Output = Self;
370    fn mul(self, other: Complex<T>) -> Self {
371        Self::new(
372            self.w() * other.re() - self.x() * other.im(),
373            self.w() * other.im() + self.x() * other.re(),
374            self.z() * other.im() + self.y() * other.re(),
375            self.z() * other.re() - self.y() * other.im(),
376        )
377    }
378}
379impl<T> Mul<Quaternion<T>> for Complex<T>
380where
381    T: Add<Output = T> + Sub<Output = T> + Mul<Output = T> + Copy,
382{
383    type Output = Quaternion<T>;
384    fn mul(self, other: Quaternion<T>) -> Self::Output {
385        Quaternion::new(
386            self.re() * other.w() - self.im() * other.x(),
387            self.re() * other.x() + self.im() * other.w(),
388            self.re() * other.y() - self.im() * other.z(),
389            self.re() * other.z() + self.im() * other.y(),
390        )
391    }
392}
393impl<T> Mul<T> for Quaternion<T>
394where
395    T: Mul<Output = T> + Copy,
396{
397    type Output = Self;
398    fn mul(self, other: T) -> Self {
399        (self.vec * other).into()
400    }
401}
402
403impl<T> MulAssign for Quaternion<T>
404where
405    Self: Mul<Output = Self> + Copy,
406{
407    fn mul_assign(&mut self, other: Self) {
408        *self = *self * other;
409    }
410}
411impl<T> MulAssign<Complex<T>> for Quaternion<T>
412where
413    Self: Mul<Complex<T>, Output = Self> + Copy,
414{
415    fn mul_assign(&mut self, other: Complex<T>) {
416        *self = *self * other;
417    }
418}
419impl<T> MulAssign<T> for Quaternion<T>
420where
421    Self: Mul<T, Output = Self> + Copy,
422{
423    fn mul_assign(&mut self, other: T) {
424        *self = *self * other;
425    }
426}
427
428impl<T> One for Quaternion<T>
429where
430    T: Zero + One + Sub<Output = T> + Copy,
431{
432    fn one() -> Self {
433        Self::new(T::one(), T::zero(), T::zero(), T::zero())
434    }
435}
436
437impl<T> Quaternion<T>
438where
439    T: Zero + One,
440{
441    pub fn i() -> Self {
442        Self::new(T::zero(), T::one(), T::zero(), T::zero())
443    }
444    pub fn j() -> Self {
445        Self::new(T::zero(), T::zero(), T::one(), T::zero())
446    }
447    pub fn k() -> Self {
448        Self::new(T::zero(), T::zero(), T::zero(), T::one())
449    }
450}
451
452impl<T> Quaternion<T>
453where
454    T: Add<Output = T> + Mul<Output = T> + Copy,
455{
456    pub fn norm_sqr(self) -> T {
457        self.vec.square_length()
458    }
459}
460impl<T: Float> Quaternion<T> {
461    pub fn norm(self) -> T {
462        self.vec.length()
463    }
464}
465impl<T> NormL1 for Quaternion<T>
466where
467    Vector4<T>: NormL1<Output = T>,
468{
469    type Output = T;
470    fn norm_l1(self) -> T {
471        self.vec.norm_l1()
472    }
473}
474impl<T: Float> NormL2 for Quaternion<T> {
475    type Output = T;
476    fn norm_l2(self) -> T {
477        self.norm()
478    }
479    fn norm_l2_sqr(self) -> T {
480        self.norm_sqr()
481    }
482}
483
484impl<T> Div<T> for Quaternion<T>
485where
486    T: Div<Output = T> + Copy,
487{
488    type Output = Self;
489    fn div(self, other: T) -> Self {
490        (self.vec / other).into()
491    }
492}
493
494impl<T> Quaternion<T>
495where
496    T: Float,
497{
498    pub fn normalize(self) -> Self {
499        self / self.norm()
500    }
501}
502
503impl<T> Normalize for Quaternion<T>
504where
505    T: Float,
506{
507    fn normalize(self) -> Self {
508        Quaternion::normalize(self)
509    }
510}
511
512impl<T> Quaternion<T>
513where
514    T: Neg<Output = T> + Num + Copy,
515{
516    pub fn inv(self) -> Self {
517        self.conj() / self.norm_sqr()
518    }
519}
520
521impl<T> Inv for Quaternion<T>
522where
523    T: Float,
524{
525    type Output = Self;
526    fn inv(self) -> Self {
527        Quaternion::inv(self)
528    }
529}
530
531#[allow(clippy::suspicious_arithmetic_impl)]
532impl<T> Div for Quaternion<T>
533where
534    T: Neg<Output = T> + Num + Copy,
535{
536    type Output = Self;
537    fn div(self, other: Self) -> Self {
538        self * other.inv()
539    }
540}
541#[allow(clippy::suspicious_arithmetic_impl)]
542impl<T> Div<Complex<T>> for Quaternion<T>
543where
544    T: Neg<Output = T> + Num + Copy,
545{
546    type Output = Self;
547    fn div(self, other: Complex<T>) -> Self {
548        self * other.inv()
549    }
550}
551#[allow(clippy::suspicious_arithmetic_impl)]
552impl<T> Div<Quaternion<T>> for Complex<T>
553where
554    T: Neg<Output = T> + Num + Copy,
555{
556    type Output = Quaternion<T>;
557    fn div(self, other: Quaternion<T>) -> Self::Output {
558        self * other.inv()
559    }
560}
561
562impl<T> DivAssign for Quaternion<T>
563where
564    Self: Div<Output = Self> + Copy,
565{
566    fn div_assign(&mut self, other: Self) {
567        *self = *self / other;
568    }
569}
570impl<T> DivAssign<Complex<T>> for Quaternion<T>
571where
572    Self: Div<Complex<T>, Output = Self> + Copy,
573{
574    fn div_assign(&mut self, other: Complex<T>) {
575        *self = *self / other;
576    }
577}
578impl<T> DivAssign<T> for Quaternion<T>
579where
580    Self: Div<T, Output = Self> + Copy,
581{
582    fn div_assign(&mut self, other: T) {
583        *self = *self / other;
584    }
585}
586
587impl<T: Neg<Output = T> + Num + Copy> Rem for Quaternion<T> {
588    type Output = Self;
589    fn rem(self, _other: Self) -> Self {
590        unimplemented!();
591    }
592}
593
594impl<T: Neg<Output = T> + Num + Copy> Num for Quaternion<T> {
595    type FromStrRadixErr = T::FromStrRadixErr;
596    fn from_str_radix(_s: &str, _radix: u32) -> Result<Self, Self::FromStrRadixErr> {
597        unimplemented!();
598    }
599}
600
601macro_rules! reverse_mul_div {
602    ($T:ident) => {
603        /// Workaround for reverse multiplication.
604        impl Mul<Quaternion<$T>> for $T {
605            type Output = Quaternion<$T>;
606            fn mul(self, other: Quaternion<$T>) -> Self::Output {
607                other * self
608            }
609        }
610        /// Workaround for reverse division.
611        #[allow(clippy::suspicious_arithmetic_impl)]
612        impl Div<Quaternion<$T>> for $T {
613            type Output = Quaternion<$T>;
614            fn div(self, other: Quaternion<$T>) -> Self::Output {
615                self * other.inv()
616            }
617        }
618    };
619}
620
621reverse_mul_div!(f32);
622reverse_mul_div!(f64);
623
624impl<T> Dot for Quaternion<T>
625where
626    T: Add<Output = T> + Mul<Output = T>,
627{
628    type Output = T;
629    fn dot(self, other: Self) -> T {
630        self.vec.dot(other.vec)
631    }
632}
633
634impl<T> Sum for Quaternion<T>
635where
636    Self: Zero + Add,
637{
638    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
639        iter.fold(Self::zero(), |a, x| a + x)
640    }
641}
642
643impl<T> Product for Quaternion<T>
644where
645    Self: One + Mul,
646{
647    fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
648        iter.fold(Self::one(), |a, x| a * x)
649    }
650}