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#[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 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 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 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 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 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 #[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}