1#![allow(clippy::op_ref)]
3
4use std::ops::{
57    Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign,
58};
59
60use crate::base::dimension::U3;
61use crate::base::storage::Storage;
62use crate::base::{Const, Scalar, Unit, Vector, Vector3};
63use crate::SimdRealField;
64
65use crate::geometry::{Point3, Quaternion, Rotation, UnitQuaternion};
66
67impl<T: Scalar> Index<usize> for Quaternion<T> {
68    type Output = T;
69
70    #[inline]
71    fn index(&self, i: usize) -> &Self::Output {
72        &self.coords[i]
73    }
74}
75
76impl<T: Scalar> IndexMut<usize> for Quaternion<T> {
77    #[inline]
78    fn index_mut(&mut self, i: usize) -> &mut T {
79        &mut self.coords[i]
80    }
81}
82
83macro_rules! quaternion_op_impl(
84    ($Op: ident, $op: ident;
85     $($Storage: ident: $StoragesBound: ident $(<$($BoundParam: ty),*>)*),*;
86     $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Result: ty;
87     $action: expr; $($lives: tt),*) => {
88        impl<$($lives ,)* T: SimdRealField $(, $Storage: $StoragesBound $(<$($BoundParam),*>)*)*> $Op<$Rhs> for $Lhs
89            where T::Element: SimdRealField {
90            type Output = $Result;
91
92            #[inline]
93            fn $op($lhs, $rhs: $Rhs) -> Self::Output {
94                $action
95            }
96        }
97    }
98);
99
100quaternion_op_impl!(
102    Add, add;
103    ;
104    self: &'a Quaternion<T>, rhs: &'b Quaternion<T>, Output = Quaternion<T>;
105    Quaternion::from(&self.coords + &rhs.coords);
106    'a, 'b);
107
108quaternion_op_impl!(
109    Add, add;
110    ;
111    self: &'a Quaternion<T>, rhs: Quaternion<T>, Output = Quaternion<T>;
112    Quaternion::from(&self.coords + rhs.coords);
113    'a);
114
115quaternion_op_impl!(
116    Add, add;
117    ;
118    self: Quaternion<T>, rhs: &'b Quaternion<T>, Output = Quaternion<T>;
119    Quaternion::from(self.coords + &rhs.coords);
120    'b);
121
122quaternion_op_impl!(
123    Add, add;
124    ;
125    self: Quaternion<T>, rhs: Quaternion<T>, Output = Quaternion<T>;
126    Quaternion::from(self.coords + rhs.coords); );
127
128quaternion_op_impl!(
130    Sub, sub;
131    ;
132    self: &'a Quaternion<T>, rhs: &'b Quaternion<T>, Output = Quaternion<T>;
133    Quaternion::from(&self.coords - &rhs.coords);
134    'a, 'b);
135
136quaternion_op_impl!(
137    Sub, sub;
138    ;
139    self: &'a Quaternion<T>, rhs: Quaternion<T>, Output = Quaternion<T>;
140    Quaternion::from(&self.coords - rhs.coords);
141    'a);
142
143quaternion_op_impl!(
144    Sub, sub;
145    ;
146    self: Quaternion<T>, rhs: &'b Quaternion<T>, Output = Quaternion<T>;
147    Quaternion::from(self.coords - &rhs.coords);
148    'b);
149
150quaternion_op_impl!(
151    Sub, sub;
152    ;
153    self: Quaternion<T>, rhs: Quaternion<T>, Output = Quaternion<T>;
154    Quaternion::from(self.coords - rhs.coords); );
155
156quaternion_op_impl!(
158    Mul, mul;
159    ;
160    self: &'a Quaternion<T>, rhs: &'b Quaternion<T>, Output = Quaternion<T>;
161    Quaternion::new(
162        self[3].clone() * rhs[3].clone() - self[0].clone() * rhs[0].clone() - self[1].clone() * rhs[1].clone() - self[2].clone() * rhs[2].clone(),
163        self[3].clone() * rhs[0].clone() + self[0].clone() * rhs[3].clone() + self[1].clone() * rhs[2].clone() - self[2].clone() * rhs[1].clone(),
164        self[3].clone() * rhs[1].clone() - self[0].clone() * rhs[2].clone() + self[1].clone() * rhs[3].clone() + self[2].clone() * rhs[0].clone(),
165        self[3].clone() * rhs[2].clone() + self[0].clone() * rhs[1].clone() - self[1].clone() * rhs[0].clone() + self[2].clone() * rhs[3].clone());
166    'a, 'b);
167
168quaternion_op_impl!(
169    Mul, mul;
170    ;
171    self: &'a Quaternion<T>, rhs: Quaternion<T>, Output = Quaternion<T>;
172    self * &rhs;
173    'a);
174
175quaternion_op_impl!(
176    Mul, mul;
177    ;
178    self: Quaternion<T>, rhs: &'b Quaternion<T>, Output = Quaternion<T>;
179    &self * rhs;
180    'b);
181
182quaternion_op_impl!(
183    Mul, mul;
184    ;
185    self: Quaternion<T>, rhs: Quaternion<T>, Output = Quaternion<T>;
186    &self * &rhs; );
187
188quaternion_op_impl!(
190    Mul, mul;
191    ;
192    self: &'a UnitQuaternion<T>, rhs: &'b UnitQuaternion<T>, Output = UnitQuaternion<T>;
193    UnitQuaternion::new_unchecked(self.quaternion() * rhs.quaternion());
194    'a, 'b);
195
196quaternion_op_impl!(
197    Mul, mul;
198    ;
199    self: &'a UnitQuaternion<T>, rhs: UnitQuaternion<T>, Output = UnitQuaternion<T>;
200    self * &rhs;
201    'a);
202
203quaternion_op_impl!(
204    Mul, mul;
205    ;
206    self: UnitQuaternion<T>, rhs: &'b UnitQuaternion<T>, Output = UnitQuaternion<T>;
207    &self * rhs;
208    'b);
209
210quaternion_op_impl!(
211    Mul, mul;
212    ;
213    self: UnitQuaternion<T>, rhs: UnitQuaternion<T>, Output = UnitQuaternion<T>;
214    &self * &rhs; );
215
216quaternion_op_impl!(
218    Div, div;
219    ;
220    self: &'a UnitQuaternion<T>, rhs: &'b UnitQuaternion<T>, Output = UnitQuaternion<T>;
221    #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() };
222    'a, 'b);
223
224quaternion_op_impl!(
225    Div, div;
226    ;
227    self: &'a UnitQuaternion<T>, rhs: UnitQuaternion<T>, Output = UnitQuaternion<T>;
228    self / &rhs;
229    'a);
230
231quaternion_op_impl!(
232    Div, div;
233    ;
234    self: UnitQuaternion<T>, rhs: &'b UnitQuaternion<T>, Output = UnitQuaternion<T>;
235    &self / rhs;
236    'b);
237
238quaternion_op_impl!(
239    Div, div;
240    ;
241    self: UnitQuaternion<T>, rhs: UnitQuaternion<T>, Output = UnitQuaternion<T>;
242    &self / &rhs; );
243
244quaternion_op_impl!(
246    Mul, mul;
247    ;
248    self: &'a UnitQuaternion<T>, rhs: &'b Rotation<T, 3>,
249    Output = UnitQuaternion<T>;
250    self * UnitQuaternion::<T>::from_rotation_matrix(rhs);
252    'a, 'b);
253
254quaternion_op_impl!(
255    Mul, mul;
256    ;
257    self: &'a UnitQuaternion<T>, rhs: Rotation<T, 3>,
258    Output = UnitQuaternion<T>;
259    self * UnitQuaternion::<T>::from_rotation_matrix(&rhs);
260    'a);
261
262quaternion_op_impl!(
263    Mul, mul;
264    ;
265    self: UnitQuaternion<T>, rhs: &'b Rotation<T, 3>,
266    Output = UnitQuaternion<T>;
267    self * UnitQuaternion::<T>::from_rotation_matrix(rhs);
268    'b);
269
270quaternion_op_impl!(
271    Mul, mul;
272    ;
273    self: UnitQuaternion<T>, rhs: Rotation<T, 3>,
274    Output = UnitQuaternion<T>;
275    self * UnitQuaternion::<T>::from_rotation_matrix(&rhs); );
276
277quaternion_op_impl!(
279    Div, div;
280    ;
281    self: &'a UnitQuaternion<T>, rhs: &'b Rotation<T, 3>,
282    Output = UnitQuaternion<T>;
283    self / UnitQuaternion::<T>::from_rotation_matrix(rhs);
285    'a, 'b);
286
287quaternion_op_impl!(
288    Div, div;
289    ;
290    self: &'a UnitQuaternion<T>, rhs: Rotation<T, 3>,
291    Output = UnitQuaternion<T>;
292    self / UnitQuaternion::<T>::from_rotation_matrix(&rhs);
293    'a);
294
295quaternion_op_impl!(
296    Div, div;
297    ;
298    self: UnitQuaternion<T>, rhs: &'b Rotation<T, 3>,
299    Output = UnitQuaternion<T>;
300    self / UnitQuaternion::<T>::from_rotation_matrix(rhs);
301    'b);
302
303quaternion_op_impl!(
304    Div, div;
305    ;
306    self: UnitQuaternion<T>, rhs: Rotation<T, 3>,
307    Output = UnitQuaternion<T>;
308    self / UnitQuaternion::<T>::from_rotation_matrix(&rhs); );
309
310quaternion_op_impl!(
312    Mul, mul;
313    ;
314    self: &'a Rotation<T, 3>, rhs: &'b UnitQuaternion<T>,
315    Output = UnitQuaternion<T>;
316    UnitQuaternion::<T>::from_rotation_matrix(self) * rhs;
318    'a, 'b);
319
320quaternion_op_impl!(
321    Mul, mul;
322    ;
323    self: &'a Rotation<T, 3>, rhs: UnitQuaternion<T>,
324    Output = UnitQuaternion<T>;
325    UnitQuaternion::<T>::from_rotation_matrix(self) * rhs;
326    'a);
327
328quaternion_op_impl!(
329    Mul, mul;
330    ;
331    self: Rotation<T, 3>, rhs: &'b UnitQuaternion<T>,
332    Output = UnitQuaternion<T>;
333    UnitQuaternion::<T>::from_rotation_matrix(&self) * rhs;
334    'b);
335
336quaternion_op_impl!(
337    Mul, mul;
338    ;
339    self: Rotation<T, 3>, rhs: UnitQuaternion<T>,
340    Output = UnitQuaternion<T>;
341    UnitQuaternion::<T>::from_rotation_matrix(&self) * rhs; );
342
343quaternion_op_impl!(
345    Div, div;
346    ;
347    self: &'a Rotation<T, 3>, rhs: &'b UnitQuaternion<T>,
348    Output = UnitQuaternion<T>;
349    UnitQuaternion::<T>::from_rotation_matrix(self) / rhs;
351    'a, 'b);
352
353quaternion_op_impl!(
354    Div, div;
355    ;
356    self: &'a Rotation<T, 3>, rhs: UnitQuaternion<T>,
357    Output = UnitQuaternion<T>;
358    UnitQuaternion::<T>::from_rotation_matrix(self) / rhs;
359    'a);
360
361quaternion_op_impl!(
362    Div, div;
363    ;
364    self: Rotation<T, 3>, rhs: &'b UnitQuaternion<T>,
365    Output = UnitQuaternion<T>;
366    UnitQuaternion::<T>::from_rotation_matrix(&self) / rhs;
367    'b);
368
369quaternion_op_impl!(
370    Div, div;
371    ;
372    self: Rotation<T, 3>, rhs: UnitQuaternion<T>,
373    Output = UnitQuaternion<T>;
374    UnitQuaternion::<T>::from_rotation_matrix(&self) / rhs; );
375
376quaternion_op_impl!(
378    Mul, mul;
379    SB: Storage<T, Const<3>> ;
380    self: &'a UnitQuaternion<T>, rhs: &'b Vector<T, Const<3>, SB>,
381    Output = Vector3<T>;
382    {
383        let two: T = crate::convert(2.0f64);
384        let t = self.as_ref().vector().cross(rhs) * two;
385        let cross = self.as_ref().vector().cross(&t);
386
387        t * self.as_ref().scalar() + cross + rhs
388    };
389    'a, 'b);
390
391quaternion_op_impl!(
392    Mul, mul;
393    SB: Storage<T, Const<3>> ;
394    self: &'a UnitQuaternion<T>, rhs: Vector<T, U3, SB>,
395    Output = Vector3<T>;
396    self * &rhs;
397    'a);
398
399quaternion_op_impl!(
400    Mul, mul;
401    SB: Storage<T, Const<3>> ;
402    self: UnitQuaternion<T>, rhs: &'b Vector<T, U3, SB>,
403    Output = Vector3<T>;
404    &self * rhs;
405    'b);
406
407quaternion_op_impl!(
408    Mul, mul;
409    SB: Storage<T, Const<3>> ;
410    self: UnitQuaternion<T>, rhs: Vector<T, U3, SB>,
411    Output = Vector3<T>;
412    &self * &rhs; );
413
414quaternion_op_impl!(
416    Mul, mul;
417    ;
418    self: &'a UnitQuaternion<T>, rhs: &'b Point3<T>,
419    Output = Point3<T>;
420    Point3::from(self * &rhs.coords);
421    'a, 'b);
422
423quaternion_op_impl!(
424    Mul, mul;
425    ;
426    self: &'a UnitQuaternion<T>, rhs: Point3<T>,
427    Output = Point3<T>;
428    Point3::from(self * rhs.coords);
429    'a);
430
431quaternion_op_impl!(
432    Mul, mul;
433    ;
434    self: UnitQuaternion<T>, rhs: &'b Point3<T>,
435    Output = Point3<T>;
436    Point3::from(self * &rhs.coords);
437    'b);
438
439quaternion_op_impl!(
440    Mul, mul;
441    ;
442    self: UnitQuaternion<T>, rhs: Point3<T>,
443    Output = Point3<T>;
444    Point3::from(self * rhs.coords); );
445
446quaternion_op_impl!(
448    Mul, mul;
449    SB: Storage<T, Const<3>> ;
450    self: &'a UnitQuaternion<T>, rhs: &'b Unit<Vector<T, U3, SB>>,
451    Output = Unit<Vector3<T>>;
452    Unit::new_unchecked(self * rhs.as_ref());
453    'a, 'b);
454
455quaternion_op_impl!(
456    Mul, mul;
457    SB: Storage<T, Const<3>> ;
458    self: &'a UnitQuaternion<T>, rhs: Unit<Vector<T, U3, SB>>,
459    Output = Unit<Vector3<T>>;
460    Unit::new_unchecked(self * rhs.into_inner());
461    'a);
462
463quaternion_op_impl!(
464    Mul, mul;
465    SB: Storage<T, Const<3>> ;
466    self: UnitQuaternion<T>, rhs: &'b Unit<Vector<T, U3, SB>>,
467    Output = Unit<Vector3<T>>;
468    Unit::new_unchecked(self * rhs.as_ref());
469    'b);
470
471quaternion_op_impl!(
472    Mul, mul;
473    SB: Storage<T, Const<3>> ;
474    self: UnitQuaternion<T>, rhs: Unit<Vector<T, U3, SB>>,
475    Output = Unit<Vector3<T>>;
476    Unit::new_unchecked(self * rhs.into_inner()); );
477
478macro_rules! scalar_op_impl(
479    ($($Op: ident, $op: ident, $OpAssign: ident, $op_assign: ident);* $(;)*) => {$(
480        impl<T: SimdRealField> $Op<T> for Quaternion<T>
481         where T::Element: SimdRealField {
482            type Output = Quaternion<T>;
483
484            #[inline]
485            fn $op(self, n: T) -> Self::Output {
486                Quaternion::from(self.coords.$op(n))
487            }
488        }
489
490        impl<'a, T: SimdRealField> $Op<T> for &'a Quaternion<T>
491         where T::Element: SimdRealField {
492            type Output = Quaternion<T>;
493
494            #[inline]
495            fn $op(self, n: T) -> Self::Output {
496                Quaternion::from((&self.coords).$op(n))
497            }
498        }
499
500        impl<T: SimdRealField> $OpAssign<T> for Quaternion<T>
501         where T::Element: SimdRealField {
502
503            #[inline]
504            fn $op_assign(&mut self, n: T) {
505                self.coords.$op_assign(n)
506            }
507        }
508    )*}
509);
510
511scalar_op_impl!(
512    Mul, mul, MulAssign, mul_assign;
513    Div, div, DivAssign, div_assign;
514);
515
516macro_rules! left_scalar_mul_impl(
517    ($($T: ty),* $(,)*) => {$(
518        impl Mul<Quaternion<$T>> for $T {
519            type Output = Quaternion<$T>;
520
521            #[inline]
522            fn mul(self, right: Quaternion<$T>) -> Self::Output {
523                Quaternion::from(self * right.coords)
524            }
525        }
526
527        impl<'b> Mul<&'b Quaternion<$T>> for $T {
528            type Output = Quaternion<$T>;
529
530            #[inline]
531            fn mul(self, right: &'b Quaternion<$T>) -> Self::Output {
532                Quaternion::from(self * &right.coords)
533            }
534        }
535    )*}
536);
537
538left_scalar_mul_impl!(f32, f64);
539
540impl<T: SimdRealField> Neg for Quaternion<T>
541where
542    T::Element: SimdRealField,
543{
544    type Output = Quaternion<T>;
545
546    #[inline]
547    fn neg(self) -> Self::Output {
548        Self::Output::from(-self.coords)
549    }
550}
551
552impl<'a, T: SimdRealField> Neg for &'a Quaternion<T>
553where
554    T::Element: SimdRealField,
555{
556    type Output = Quaternion<T>;
557
558    #[inline]
559    fn neg(self) -> Self::Output {
560        Self::Output::from(-&self.coords)
561    }
562}
563
564macro_rules! quaternion_op_impl(
565    ($OpAssign: ident, $op_assign: ident;
566     $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty $(=> $VDimA: ty, $VDimB: ty)*;
567     $action: expr; $($lives: tt),*) => {
568        impl<$($lives ,)* T: SimdRealField> $OpAssign<$Rhs> for $Lhs
569            where T::Element: SimdRealField {
570
571            #[inline]
572            fn $op_assign(&mut $lhs, $rhs: $Rhs) {
573                $action
574            }
575        }
576    }
577);
578
579quaternion_op_impl!(
581    AddAssign, add_assign;
582    self: Quaternion<T>, rhs: &'b Quaternion<T>;
583    self.coords += &rhs.coords;
584    'b);
585
586quaternion_op_impl!(
587    AddAssign, add_assign;
588    self: Quaternion<T>, rhs: Quaternion<T>;
589    self.coords += rhs.coords; );
590
591quaternion_op_impl!(
593    SubAssign, sub_assign;
594    self: Quaternion<T>, rhs: &'b Quaternion<T>;
595    self.coords -= &rhs.coords;
596    'b);
597
598quaternion_op_impl!(
599    SubAssign, sub_assign;
600    self: Quaternion<T>, rhs: Quaternion<T>;
601    self.coords -= rhs.coords; );
602
603quaternion_op_impl!(
605    MulAssign, mul_assign;
606    self: Quaternion<T>, rhs: &'b Quaternion<T>;
607    {
608        let res = &*self * rhs;
609        self.coords.copy_from(&res.coords);
611    };
612    'b);
613
614quaternion_op_impl!(
615    MulAssign, mul_assign;
616    self: Quaternion<T>, rhs: Quaternion<T>;
617    *self *= &rhs; );
618
619quaternion_op_impl!(
621    MulAssign, mul_assign;
622    self: UnitQuaternion<T>, rhs: &'b UnitQuaternion<T>;
623    {
624        let res = &*self * rhs;
625        self.as_mut_unchecked().coords.copy_from(&res.as_ref().coords);
626    };
627    'b);
628
629quaternion_op_impl!(
630    MulAssign, mul_assign;
631    self: UnitQuaternion<T>, rhs: UnitQuaternion<T>;
632    *self *= &rhs; );
633
634quaternion_op_impl!(
636    DivAssign, div_assign;
637    self: UnitQuaternion<T>, rhs: &'b UnitQuaternion<T>;
638    {
639        let res = &*self / rhs;
640        self.as_mut_unchecked().coords.copy_from(&res.as_ref().coords);
641    };
642    'b);
643
644quaternion_op_impl!(
645    DivAssign, div_assign;
646    self: UnitQuaternion<T>, rhs: UnitQuaternion<T>;
647    *self /= &rhs; );
648
649quaternion_op_impl!(
651    MulAssign, mul_assign;
652    self: UnitQuaternion<T>, rhs: &'b Rotation<T, 3>;
653    {
654        let res = &*self * rhs;
655        self.as_mut_unchecked().coords.copy_from(&res.as_ref().coords);
656    };
657    'b);
658
659quaternion_op_impl!(
660    MulAssign, mul_assign;
661    self: UnitQuaternion<T>, rhs: Rotation<T, 3>;
662    *self *= &rhs; );
663
664quaternion_op_impl!(
666    DivAssign, div_assign;
667    self: UnitQuaternion<T>, rhs: &'b Rotation<T, 3>;
668    {
669        let res = &*self / rhs;
670        self.as_mut_unchecked().coords.copy_from(&res.as_ref().coords);
671    };
672    'b);
673
674quaternion_op_impl!(
675    DivAssign, div_assign;
676    self: UnitQuaternion<T>, rhs: Rotation<T, 3>;
677    *self /= &rhs; );