nalgebra/geometry/
dual_quaternion_ops.rs

1// The macros break if the references are taken out, for some reason.
2#![allow(clippy::op_ref)]
3
4/*
5 * This file provides:
6 *
7 * NOTE: Work in progress https://github.com/dimforge/nalgebra/issues/487
8 *
9 * (Dual Quaternion)
10 *
11 * Index<usize>
12 * IndexMut<usize>
13 *
14 * (Assignment Operators)
15 *
16 * -DualQuaternion
17 * DualQuaternion × Scalar
18 * DualQuaternion × DualQuaternion
19 * DualQuaternion + DualQuaternion
20 * DualQuaternion - DualQuaternion
21 * DualQuaternion × UnitDualQuaternion
22 * DualQuaternion ÷ UnitDualQuaternion
23 * -UnitDualQuaternion
24 * UnitDualQuaternion × DualQuaternion
25 * UnitDualQuaternion × UnitDualQuaternion
26 * UnitDualQuaternion ÷ UnitDualQuaternion
27 * UnitDualQuaternion × Translation3
28 * UnitDualQuaternion ÷ Translation3
29 * UnitDualQuaternion × UnitQuaternion
30 * UnitDualQuaternion ÷ UnitQuaternion
31 * Translation3 × UnitDualQuaternion
32 * Translation3 ÷ UnitDualQuaternion
33 * UnitQuaternion × UnitDualQuaternion
34 * UnitQuaternion ÷ UnitDualQuaternion
35 * UnitDualQuaternion × Isometry3
36 * UnitDualQuaternion ÷ Isometry3
37 * Isometry3 × UnitDualQuaternion
38 * Isometry3 ÷ UnitDualQuaternion
39 * UnitDualQuaternion × Point
40 * UnitDualQuaternion × Vector
41 * UnitDualQuaternion × Unit<Vector>
42 *
43 * ---
44 *
45 * References:
46 *   Multiplication:
47 *   - https://cs.gmu.edu/~jmlien/teaching/cs451/uploads/Main/dual-quaternion.pdf
48 */
49
50use crate::base::storage::Storage;
51use crate::{
52    DualQuaternion, Isometry3, Point, Point3, Quaternion, SimdRealField, Translation3, Unit,
53    UnitDualQuaternion, UnitQuaternion, Vector, Vector3, U3,
54};
55use std::ops::{
56    Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign,
57};
58
59impl<T: SimdRealField> AsRef<[T; 8]> for DualQuaternion<T> {
60    #[inline]
61    fn as_ref(&self) -> &[T; 8] {
62        unsafe { &*(self as *const Self as *const [T; 8]) }
63    }
64}
65
66impl<T: SimdRealField> AsMut<[T; 8]> for DualQuaternion<T> {
67    #[inline]
68    fn as_mut(&mut self) -> &mut [T; 8] {
69        unsafe { &mut *(self as *mut Self as *mut [T; 8]) }
70    }
71}
72
73impl<T: SimdRealField> Index<usize> for DualQuaternion<T> {
74    type Output = T;
75
76    #[inline]
77    fn index(&self, i: usize) -> &Self::Output {
78        &self.as_ref()[i]
79    }
80}
81
82impl<T: SimdRealField> IndexMut<usize> for DualQuaternion<T> {
83    #[inline]
84    fn index_mut(&mut self, i: usize) -> &mut T {
85        &mut self.as_mut()[i]
86    }
87}
88
89impl<T: SimdRealField> Neg for DualQuaternion<T>
90where
91    T::Element: SimdRealField,
92{
93    type Output = DualQuaternion<T>;
94
95    #[inline]
96    fn neg(self) -> Self::Output {
97        DualQuaternion::from_real_and_dual(-self.real, -self.dual)
98    }
99}
100
101impl<'a, T: SimdRealField> Neg for &'a DualQuaternion<T>
102where
103    T::Element: SimdRealField,
104{
105    type Output = DualQuaternion<T>;
106
107    #[inline]
108    fn neg(self) -> Self::Output {
109        DualQuaternion::from_real_and_dual(-&self.real, -&self.dual)
110    }
111}
112
113impl<T: SimdRealField> Neg for UnitDualQuaternion<T>
114where
115    T::Element: SimdRealField,
116{
117    type Output = UnitDualQuaternion<T>;
118
119    #[inline]
120    fn neg(self) -> Self::Output {
121        UnitDualQuaternion::new_unchecked(-self.into_inner())
122    }
123}
124
125impl<'a, T: SimdRealField> Neg for &'a UnitDualQuaternion<T>
126where
127    T::Element: SimdRealField,
128{
129    type Output = UnitDualQuaternion<T>;
130
131    #[inline]
132    fn neg(self) -> Self::Output {
133        UnitDualQuaternion::new_unchecked(-self.as_ref())
134    }
135}
136
137macro_rules! dual_quaternion_op_impl(
138    ($Op: ident, $op: ident;
139     ($LhsRDim: ident, $LhsCDim: ident), ($RhsRDim: ident, $RhsCDim: ident)
140     $(for $Storage: ident: $StoragesBound: ident $(<$($BoundParam: ty),*>)*),*;
141     $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Result: ty $(=> $VDimA: ty, $VDimB: ty)*;
142     $action: expr; $($lives: tt),*) => {
143        impl<$($lives ,)* T: SimdRealField $(, $Storage: $StoragesBound $(<$($BoundParam),*>)*)*> $Op<$Rhs> for $Lhs
144            where T::Element: SimdRealField, {
145            type Output = $Result;
146
147            #[inline]
148            fn $op($lhs, $rhs: $Rhs) -> Self::Output {
149                $action
150            }
151        }
152    }
153);
154
155// DualQuaternion + DualQuaternion
156dual_quaternion_op_impl!(
157    Add, add;
158    (U4, U1), (U4, U1);
159    self: &'a DualQuaternion<T>, rhs: &'b DualQuaternion<T>, Output = DualQuaternion<T>;
160    DualQuaternion::from_real_and_dual(
161        &self.real + &rhs.real,
162        &self.dual + &rhs.dual,
163    );
164    'a, 'b);
165
166dual_quaternion_op_impl!(
167    Add, add;
168    (U4, U1), (U4, U1);
169    self: &'a DualQuaternion<T>, rhs: DualQuaternion<T>, Output = DualQuaternion<T>;
170    DualQuaternion::from_real_and_dual(
171        &self.real + rhs.real,
172        &self.dual + rhs.dual,
173    );
174    'a);
175
176dual_quaternion_op_impl!(
177    Add, add;
178    (U4, U1), (U4, U1);
179    self: DualQuaternion<T>, rhs: &'b DualQuaternion<T>, Output = DualQuaternion<T>;
180    DualQuaternion::from_real_and_dual(
181        self.real + &rhs.real,
182        self.dual + &rhs.dual,
183    );
184    'b);
185
186dual_quaternion_op_impl!(
187    Add, add;
188    (U4, U1), (U4, U1);
189    self: DualQuaternion<T>, rhs: DualQuaternion<T>, Output = DualQuaternion<T>;
190    DualQuaternion::from_real_and_dual(
191        self.real + rhs.real,
192        self.dual + rhs.dual,
193    ); );
194
195// DualQuaternion - DualQuaternion
196dual_quaternion_op_impl!(
197    Sub, sub;
198    (U4, U1), (U4, U1);
199    self: &'a DualQuaternion<T>, rhs: &'b DualQuaternion<T>, Output = DualQuaternion<T>;
200    DualQuaternion::from_real_and_dual(
201        &self.real - &rhs.real,
202        &self.dual - &rhs.dual,
203    );
204    'a, 'b);
205
206dual_quaternion_op_impl!(
207    Sub, sub;
208    (U4, U1), (U4, U1);
209    self: &'a DualQuaternion<T>, rhs: DualQuaternion<T>, Output = DualQuaternion<T>;
210    DualQuaternion::from_real_and_dual(
211        &self.real - rhs.real,
212        &self.dual - rhs.dual,
213    );
214    'a);
215
216dual_quaternion_op_impl!(
217    Sub, sub;
218    (U4, U1), (U4, U1);
219    self: DualQuaternion<T>, rhs: &'b DualQuaternion<T>, Output = DualQuaternion<T>;
220    DualQuaternion::from_real_and_dual(
221        self.real - &rhs.real,
222        self.dual - &rhs.dual,
223    );
224    'b);
225
226dual_quaternion_op_impl!(
227    Sub, sub;
228    (U4, U1), (U4, U1);
229    self: DualQuaternion<T>, rhs: DualQuaternion<T>, Output = DualQuaternion<T>;
230    DualQuaternion::from_real_and_dual(
231        self.real - rhs.real,
232        self.dual - rhs.dual,
233    ); );
234
235// DualQuaternion × DualQuaternion
236dual_quaternion_op_impl!(
237    Mul, mul;
238    (U4, U1), (U4, U1);
239    self: &'a DualQuaternion<T>, rhs: &'b DualQuaternion<T>, Output = DualQuaternion<T>;
240    DualQuaternion::from_real_and_dual(
241        &self.real * &rhs.real,
242        &self.real * &rhs.dual + &self.dual * &rhs.real,
243    );
244    'a, 'b);
245
246dual_quaternion_op_impl!(
247    Mul, mul;
248    (U4, U1), (U4, U1);
249    self: &'a DualQuaternion<T>, rhs: DualQuaternion<T>, Output = DualQuaternion<T>;
250    self * &rhs;
251    'a);
252
253dual_quaternion_op_impl!(
254    Mul, mul;
255    (U4, U1), (U4, U1);
256    self: DualQuaternion<T>, rhs: &'b DualQuaternion<T>, Output = DualQuaternion<T>;
257    &self * rhs;
258    'b);
259
260dual_quaternion_op_impl!(
261    Mul, mul;
262    (U4, U1), (U4, U1);
263    self: DualQuaternion<T>, rhs: DualQuaternion<T>, Output = DualQuaternion<T>;
264    &self * &rhs; );
265
266// DualQuaternion × UnitDualQuaternion
267dual_quaternion_op_impl!(
268    Mul, mul;
269    (U4, U1), (U4, U1);
270    self: &'a DualQuaternion<T>, rhs: &'b UnitDualQuaternion<T>, Output = DualQuaternion<T>;
271    self * rhs.dual_quaternion();
272    'a, 'b);
273
274dual_quaternion_op_impl!(
275    Mul, mul;
276    (U4, U1), (U4, U1);
277    self: &'a DualQuaternion<T>, rhs: UnitDualQuaternion<T>, Output = DualQuaternion<T>;
278    self * rhs.dual_quaternion();
279    'a);
280
281dual_quaternion_op_impl!(
282    Mul, mul;
283    (U4, U1), (U4, U1);
284    self: DualQuaternion<T>, rhs: &'b UnitDualQuaternion<T>, Output = DualQuaternion<T>;
285    self * rhs.dual_quaternion();
286    'b);
287
288dual_quaternion_op_impl!(
289    Mul, mul;
290    (U4, U1), (U4, U1);
291    self: DualQuaternion<T>, rhs: UnitDualQuaternion<T>, Output = DualQuaternion<T>;
292    self * rhs.dual_quaternion(););
293
294// DualQuaternion ÷ UnitDualQuaternion
295dual_quaternion_op_impl!(
296    Div, div;
297    (U4, U1), (U4, U1);
298    self: &'a DualQuaternion<T>, rhs: &'b UnitDualQuaternion<T>, Output = DualQuaternion<T>;
299    #[allow(clippy::suspicious_arithmetic_impl)]
300    { self * rhs.inverse().dual_quaternion() };
301    'a, 'b);
302
303dual_quaternion_op_impl!(
304    Div, div;
305    (U4, U1), (U4, U1);
306    self: &'a DualQuaternion<T>, rhs: UnitDualQuaternion<T>, Output = DualQuaternion<T>;
307    #[allow(clippy::suspicious_arithmetic_impl)]
308    { self * rhs.inverse().dual_quaternion() };
309    'a);
310
311dual_quaternion_op_impl!(
312    Div, div;
313    (U4, U1), (U4, U1);
314    self: DualQuaternion<T>, rhs: &'b UnitDualQuaternion<T>, Output = DualQuaternion<T>;
315    #[allow(clippy::suspicious_arithmetic_impl)]
316    { self * rhs.inverse().dual_quaternion() };
317    'b);
318
319dual_quaternion_op_impl!(
320    Div, div;
321    (U4, U1), (U4, U1);
322    self: DualQuaternion<T>, rhs: UnitDualQuaternion<T>, Output = DualQuaternion<T>;
323    #[allow(clippy::suspicious_arithmetic_impl)]
324    { self * rhs.inverse().dual_quaternion() };);
325
326// UnitDualQuaternion × UnitDualQuaternion
327dual_quaternion_op_impl!(
328    Mul, mul;
329    (U4, U1), (U4, U1);
330    self: &'a UnitDualQuaternion<T>, rhs: &'b UnitDualQuaternion<T>, Output = UnitDualQuaternion<T>;
331    UnitDualQuaternion::new_unchecked(self.as_ref() * rhs.as_ref());
332    'a, 'b);
333
334dual_quaternion_op_impl!(
335    Mul, mul;
336    (U4, U1), (U4, U1);
337    self: &'a UnitDualQuaternion<T>, rhs: UnitDualQuaternion<T>, Output = UnitDualQuaternion<T>;
338    self * &rhs;
339    'a);
340
341dual_quaternion_op_impl!(
342    Mul, mul;
343    (U4, U1), (U4, U1);
344    self: UnitDualQuaternion<T>, rhs: &'b UnitDualQuaternion<T>, Output = UnitDualQuaternion<T>;
345    &self * rhs;
346    'b);
347
348dual_quaternion_op_impl!(
349    Mul, mul;
350    (U4, U1), (U4, U1);
351    self: UnitDualQuaternion<T>, rhs: UnitDualQuaternion<T>, Output = UnitDualQuaternion<T>;
352    &self * &rhs; );
353
354// UnitDualQuaternion ÷ UnitDualQuaternion
355dual_quaternion_op_impl!(
356    Div, div;
357    (U4, U1), (U4, U1);
358    self: &'a UnitDualQuaternion<T>, rhs: &'b UnitDualQuaternion<T>, Output = UnitDualQuaternion<T>;
359    #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() };
360    'a, 'b);
361
362dual_quaternion_op_impl!(
363    Div, div;
364    (U4, U1), (U4, U1);
365    self: &'a UnitDualQuaternion<T>, rhs: UnitDualQuaternion<T>, Output = UnitDualQuaternion<T>;
366    self / &rhs;
367    'a);
368
369dual_quaternion_op_impl!(
370    Div, div;
371    (U4, U1), (U4, U1);
372    self: UnitDualQuaternion<T>, rhs: &'b UnitDualQuaternion<T>, Output = UnitDualQuaternion<T>;
373    &self / rhs;
374    'b);
375
376dual_quaternion_op_impl!(
377    Div, div;
378    (U4, U1), (U4, U1);
379    self: UnitDualQuaternion<T>, rhs: UnitDualQuaternion<T>, Output = UnitDualQuaternion<T>;
380    &self / &rhs; );
381
382// UnitDualQuaternion × DualQuaternion
383dual_quaternion_op_impl!(
384    Mul, mul;
385    (U4, U1), (U4, U1);
386    self: &'a UnitDualQuaternion<T>, rhs: &'b DualQuaternion<T>,
387    Output = DualQuaternion<T> => U1, U4;
388    self.dual_quaternion() * rhs;
389    'a, 'b);
390
391dual_quaternion_op_impl!(
392    Mul, mul;
393    (U4, U1), (U4, U1);
394    self: &'a UnitDualQuaternion<T>, rhs: DualQuaternion<T>,
395    Output = DualQuaternion<T> => U3, U3;
396    self.dual_quaternion() * rhs;
397    'a);
398
399dual_quaternion_op_impl!(
400    Mul, mul;
401    (U4, U1), (U4, U1);
402    self: UnitDualQuaternion<T>, rhs: &'b DualQuaternion<T>,
403    Output = DualQuaternion<T> => U3, U3;
404    self.dual_quaternion() * rhs;
405    'b);
406
407dual_quaternion_op_impl!(
408    Mul, mul;
409    (U4, U1), (U4, U1);
410    self: UnitDualQuaternion<T>, rhs: DualQuaternion<T>,
411    Output = DualQuaternion<T> => U3, U3;
412    self.dual_quaternion() * rhs;);
413
414// UnitDualQuaternion × UnitQuaternion
415dual_quaternion_op_impl!(
416    Mul, mul;
417    (U4, U1), (U4, U1);
418    self: &'a UnitDualQuaternion<T>, rhs: &'b UnitQuaternion<T>,
419    Output = UnitDualQuaternion<T> => U1, U4;
420    self * UnitDualQuaternion::<T>::new_unchecked(DualQuaternion::from_real(rhs.clone().into_inner()));
421    'a, 'b);
422
423dual_quaternion_op_impl!(
424    Mul, mul;
425    (U4, U1), (U4, U1);
426    self: &'a UnitDualQuaternion<T>, rhs: UnitQuaternion<T>,
427    Output = UnitDualQuaternion<T> => U3, U3;
428    self * UnitDualQuaternion::<T>::new_unchecked(DualQuaternion::from_real(rhs.into_inner()));
429    'a);
430
431dual_quaternion_op_impl!(
432    Mul, mul;
433    (U4, U1), (U4, U1);
434    self: UnitDualQuaternion<T>, rhs: &'b UnitQuaternion<T>,
435    Output = UnitDualQuaternion<T> => U3, U3;
436    self * UnitDualQuaternion::<T>::new_unchecked(DualQuaternion::from_real(rhs.clone().into_inner()));
437    'b);
438
439dual_quaternion_op_impl!(
440    Mul, mul;
441    (U4, U1), (U4, U1);
442    self: UnitDualQuaternion<T>, rhs: UnitQuaternion<T>,
443    Output = UnitDualQuaternion<T> => U3, U3;
444    self * UnitDualQuaternion::<T>::new_unchecked(DualQuaternion::from_real(rhs.into_inner())););
445
446// UnitQuaternion × UnitDualQuaternion
447dual_quaternion_op_impl!(
448    Mul, mul;
449    (U4, U1), (U4, U1);
450    self: &'a UnitQuaternion<T>, rhs: &'b UnitDualQuaternion<T>,
451    Output = UnitDualQuaternion<T> => U1, U4;
452    UnitDualQuaternion::<T>::new_unchecked(DualQuaternion::from_real(self.clone().into_inner())) * rhs;
453    'a, 'b);
454
455dual_quaternion_op_impl!(
456    Mul, mul;
457    (U4, U1), (U4, U1);
458    self: &'a UnitQuaternion<T>, rhs: UnitDualQuaternion<T>,
459    Output = UnitDualQuaternion<T> => U3, U3;
460    UnitDualQuaternion::<T>::new_unchecked(DualQuaternion::from_real(self.clone().into_inner())) * rhs;
461    'a);
462
463dual_quaternion_op_impl!(
464    Mul, mul;
465    (U4, U1), (U4, U1);
466    self: UnitQuaternion<T>, rhs: &'b UnitDualQuaternion<T>,
467    Output = UnitDualQuaternion<T> => U3, U3;
468    UnitDualQuaternion::<T>::new_unchecked(DualQuaternion::from_real(self.into_inner())) * rhs;
469    'b);
470
471dual_quaternion_op_impl!(
472    Mul, mul;
473    (U4, U1), (U4, U1);
474    self: UnitQuaternion<T>, rhs: UnitDualQuaternion<T>,
475    Output = UnitDualQuaternion<T> => U3, U3;
476    UnitDualQuaternion::<T>::new_unchecked(DualQuaternion::from_real(self.into_inner())) * rhs;);
477
478// UnitDualQuaternion ÷ UnitQuaternion
479dual_quaternion_op_impl!(
480    Div, div;
481    (U4, U1), (U4, U1);
482    self: &'a UnitDualQuaternion<T>, rhs: &'b UnitQuaternion<T>,
483    Output = UnitDualQuaternion<T> => U1, U4;
484    #[allow(clippy::suspicious_arithmetic_impl)]
485    { self * UnitDualQuaternion::<T>::from_rotation(rhs.inverse()) };
486    'a, 'b);
487
488dual_quaternion_op_impl!(
489    Div, div;
490    (U4, U1), (U4, U1);
491    self: &'a UnitDualQuaternion<T>, rhs: UnitQuaternion<T>,
492    Output = UnitDualQuaternion<T> => U3, U3;
493    #[allow(clippy::suspicious_arithmetic_impl)]
494    { self * UnitDualQuaternion::<T>::from_rotation(rhs.inverse()) };
495    'a);
496
497dual_quaternion_op_impl!(
498    Div, div;
499    (U4, U1), (U4, U1);
500    self: UnitDualQuaternion<T>, rhs: &'b UnitQuaternion<T>,
501    Output = UnitDualQuaternion<T> => U3, U3;
502    #[allow(clippy::suspicious_arithmetic_impl)]
503    { self * UnitDualQuaternion::<T>::from_rotation(rhs.inverse()) };
504    'b);
505
506dual_quaternion_op_impl!(
507    Div, div;
508    (U4, U1), (U4, U1);
509    self: UnitDualQuaternion<T>, rhs: UnitQuaternion<T>,
510    Output = UnitDualQuaternion<T> => U3, U3;
511    #[allow(clippy::suspicious_arithmetic_impl)]
512    { self * UnitDualQuaternion::<T>::from_rotation(rhs.inverse()) };);
513
514// UnitQuaternion ÷ UnitDualQuaternion
515dual_quaternion_op_impl!(
516    Div, div;
517    (U4, U1), (U4, U1);
518    self: &'a UnitQuaternion<T>, rhs: &'b UnitDualQuaternion<T>,
519    Output = UnitDualQuaternion<T> => U1, U4;
520    #[allow(clippy::suspicious_arithmetic_impl)]
521    {
522        UnitDualQuaternion::<T>::new_unchecked(
523            DualQuaternion::from_real(self.clone().into_inner())
524        ) * rhs.inverse()
525    }; 'a, 'b);
526
527dual_quaternion_op_impl!(
528    Div, div;
529    (U4, U1), (U4, U1);
530    self: &'a UnitQuaternion<T>, rhs: UnitDualQuaternion<T>,
531    Output = UnitDualQuaternion<T> => U3, U3;
532    #[allow(clippy::suspicious_arithmetic_impl)]
533    {
534        UnitDualQuaternion::<T>::new_unchecked(
535            DualQuaternion::from_real(self.clone().into_inner())
536        ) * rhs.inverse()
537    }; 'a);
538
539dual_quaternion_op_impl!(
540    Div, div;
541    (U4, U1), (U4, U1);
542    self: UnitQuaternion<T>, rhs: &'b UnitDualQuaternion<T>,
543    Output = UnitDualQuaternion<T> => U3, U3;
544    #[allow(clippy::suspicious_arithmetic_impl)]
545    {
546        UnitDualQuaternion::<T>::new_unchecked(
547            DualQuaternion::from_real(self.into_inner())
548        ) * rhs.inverse()
549    }; 'b);
550
551dual_quaternion_op_impl!(
552    Div, div;
553    (U4, U1), (U4, U1);
554    self: UnitQuaternion<T>, rhs: UnitDualQuaternion<T>,
555    Output = UnitDualQuaternion<T> => U3, U3;
556    #[allow(clippy::suspicious_arithmetic_impl)]
557    {
558        UnitDualQuaternion::<T>::new_unchecked(
559            DualQuaternion::from_real(self.into_inner())
560        ) * rhs.inverse()
561    };);
562
563// UnitDualQuaternion × Translation3
564dual_quaternion_op_impl!(
565    Mul, mul;
566    (U4, U1), (U3, U1);
567    self: &'a UnitDualQuaternion<T>, rhs: &'b Translation3<T>,
568    Output = UnitDualQuaternion<T> => U3, U1;
569    self * UnitDualQuaternion::<T>::from_parts(rhs.clone(), UnitQuaternion::identity());
570    'a, 'b);
571
572dual_quaternion_op_impl!(
573    Mul, mul;
574    (U4, U1), (U3, U3);
575    self: &'a UnitDualQuaternion<T>, rhs: Translation3<T>,
576    Output = UnitDualQuaternion<T> => U3, U1;
577    self * UnitDualQuaternion::<T>::from_parts(rhs, UnitQuaternion::identity());
578    'a);
579
580dual_quaternion_op_impl!(
581    Mul, mul;
582    (U4, U1), (U3, U3);
583    self: UnitDualQuaternion<T>, rhs: &'b Translation3<T>,
584    Output = UnitDualQuaternion<T> => U3, U1;
585    self * UnitDualQuaternion::<T>::from_parts(rhs.clone(), UnitQuaternion::identity());
586    'b);
587
588dual_quaternion_op_impl!(
589    Mul, mul;
590    (U4, U1), (U3, U3);
591    self: UnitDualQuaternion<T>, rhs: Translation3<T>,
592    Output = UnitDualQuaternion<T> => U3, U1;
593    self * UnitDualQuaternion::<T>::from_parts(rhs, UnitQuaternion::identity()); );
594
595// UnitDualQuaternion ÷ Translation3
596dual_quaternion_op_impl!(
597    Div, div;
598    (U4, U1), (U3, U1);
599    self: &'a UnitDualQuaternion<T>, rhs: &'b Translation3<T>,
600    Output = UnitDualQuaternion<T> => U3, U1;
601    #[allow(clippy::suspicious_arithmetic_impl)]
602    { self * UnitDualQuaternion::<T>::from_parts(rhs.inverse(), UnitQuaternion::identity()) };
603    'a, 'b);
604
605dual_quaternion_op_impl!(
606    Div, div;
607    (U4, U1), (U3, U3);
608    self: &'a UnitDualQuaternion<T>, rhs: Translation3<T>,
609    Output = UnitDualQuaternion<T> => U3, U1;
610    #[allow(clippy::suspicious_arithmetic_impl)]
611    { self * UnitDualQuaternion::<T>::from_parts(rhs.inverse(), UnitQuaternion::identity()) };
612    'a);
613
614dual_quaternion_op_impl!(
615    Div, div;
616    (U4, U1), (U3, U3);
617    self: UnitDualQuaternion<T>, rhs: &'b Translation3<T>,
618    Output = UnitDualQuaternion<T> => U3, U1;
619    #[allow(clippy::suspicious_arithmetic_impl)]
620    { self * UnitDualQuaternion::<T>::from_parts(rhs.inverse(), UnitQuaternion::identity()) };
621    'b);
622
623dual_quaternion_op_impl!(
624    Div, div;
625    (U4, U1), (U3, U3);
626    self: UnitDualQuaternion<T>, rhs: Translation3<T>,
627    Output = UnitDualQuaternion<T> => U3, U1;
628    #[allow(clippy::suspicious_arithmetic_impl)]
629    { self * UnitDualQuaternion::<T>::from_parts(rhs.inverse(), UnitQuaternion::identity()) };);
630
631// Translation3 × UnitDualQuaternion
632dual_quaternion_op_impl!(
633    Mul, mul;
634    (U3, U1), (U4, U1);
635    self: &'b Translation3<T>, rhs: &'a UnitDualQuaternion<T>,
636    Output = UnitDualQuaternion<T> => U3, U1;
637    UnitDualQuaternion::<T>::from_parts(self.clone(), UnitQuaternion::identity()) * rhs;
638    'a, 'b);
639
640dual_quaternion_op_impl!(
641    Mul, mul;
642    (U3, U1), (U4, U1);
643    self: &'a Translation3<T>, rhs: UnitDualQuaternion<T>,
644    Output = UnitDualQuaternion<T> => U3, U1;
645    UnitDualQuaternion::<T>::from_parts(self.clone(), UnitQuaternion::identity()) * rhs;
646    'a);
647
648dual_quaternion_op_impl!(
649    Mul, mul;
650    (U3, U1), (U4, U1);
651    self: Translation3<T>, rhs: &'b UnitDualQuaternion<T>,
652    Output = UnitDualQuaternion<T> => U3, U1;
653    UnitDualQuaternion::<T>::from_parts(self, UnitQuaternion::identity()) * rhs;
654    'b);
655
656dual_quaternion_op_impl!(
657    Mul, mul;
658    (U3, U1), (U4, U1);
659    self: Translation3<T>, rhs: UnitDualQuaternion<T>,
660    Output = UnitDualQuaternion<T> => U3, U1;
661    UnitDualQuaternion::<T>::from_parts(self, UnitQuaternion::identity()) * rhs;);
662
663// Translation3 ÷ UnitDualQuaternion
664dual_quaternion_op_impl!(
665    Div, div;
666    (U3, U1), (U4, U1);
667    self: &'b Translation3<T>, rhs: &'a UnitDualQuaternion<T>,
668    Output = UnitDualQuaternion<T> => U3, U1;
669    UnitDualQuaternion::<T>::from_parts(self.clone(), UnitQuaternion::identity()) / rhs;
670    'a, 'b);
671
672dual_quaternion_op_impl!(
673    Div, div;
674    (U3, U1), (U4, U1);
675    self: &'a Translation3<T>, rhs: UnitDualQuaternion<T>,
676    Output = UnitDualQuaternion<T> => U3, U1;
677    UnitDualQuaternion::<T>::from_parts(self.clone(), UnitQuaternion::identity()) / rhs;
678    'a);
679
680dual_quaternion_op_impl!(
681    Div, div;
682    (U3, U1), (U4, U1);
683    self: Translation3<T>, rhs: &'b UnitDualQuaternion<T>,
684    Output = UnitDualQuaternion<T> => U3, U1;
685    UnitDualQuaternion::<T>::from_parts(self, UnitQuaternion::identity()) / rhs;
686    'b);
687
688dual_quaternion_op_impl!(
689    Div, div;
690    (U3, U1), (U4, U1);
691    self: Translation3<T>, rhs: UnitDualQuaternion<T>,
692    Output = UnitDualQuaternion<T> => U3, U1;
693    UnitDualQuaternion::<T>::from_parts(self, UnitQuaternion::identity()) / rhs;);
694
695// UnitDualQuaternion × Isometry3
696dual_quaternion_op_impl!(
697    Mul, mul;
698    (U4, U1), (U3, U1);
699    self: &'a UnitDualQuaternion<T>, rhs: &'b Isometry3<T>,
700    Output = UnitDualQuaternion<T> => U3, U1;
701    self * UnitDualQuaternion::<T>::from_isometry(rhs);
702    'a, 'b);
703
704dual_quaternion_op_impl!(
705    Mul, mul;
706    (U4, U1), (U3, U3);
707    self: &'a UnitDualQuaternion<T>, rhs: Isometry3<T>,
708    Output = UnitDualQuaternion<T> => U3, U1;
709    self * UnitDualQuaternion::<T>::from_isometry(&rhs);
710    'a);
711
712dual_quaternion_op_impl!(
713    Mul, mul;
714    (U4, U1), (U3, U3);
715    self: UnitDualQuaternion<T>, rhs: &'b Isometry3<T>,
716    Output = UnitDualQuaternion<T> => U3, U1;
717    self * UnitDualQuaternion::<T>::from_isometry(rhs);
718    'b);
719
720dual_quaternion_op_impl!(
721    Mul, mul;
722    (U4, U1), (U3, U3);
723    self: UnitDualQuaternion<T>, rhs: Isometry3<T>,
724    Output = UnitDualQuaternion<T> => U3, U1;
725    self * UnitDualQuaternion::<T>::from_isometry(&rhs); );
726
727// UnitDualQuaternion ÷ Isometry3
728dual_quaternion_op_impl!(
729    Div, div;
730    (U4, U1), (U3, U1);
731    self: &'a UnitDualQuaternion<T>, rhs: &'b Isometry3<T>,
732    Output = UnitDualQuaternion<T> => U3, U1;
733    // TODO: can we avoid the conversion to a rotation matrix?
734    self / UnitDualQuaternion::<T>::from_isometry(rhs);
735    'a, 'b);
736
737dual_quaternion_op_impl!(
738    Div, div;
739    (U4, U1), (U3, U3);
740    self: &'a UnitDualQuaternion<T>, rhs: Isometry3<T>,
741    Output = UnitDualQuaternion<T> => U3, U1;
742    self / UnitDualQuaternion::<T>::from_isometry(&rhs);
743    'a);
744
745dual_quaternion_op_impl!(
746    Div, div;
747    (U4, U1), (U3, U3);
748    self: UnitDualQuaternion<T>, rhs: &'b Isometry3<T>,
749    Output = UnitDualQuaternion<T> => U3, U1;
750    self / UnitDualQuaternion::<T>::from_isometry(rhs);
751    'b);
752
753dual_quaternion_op_impl!(
754    Div, div;
755    (U4, U1), (U3, U3);
756    self: UnitDualQuaternion<T>, rhs: Isometry3<T>,
757    Output = UnitDualQuaternion<T> => U3, U1;
758    self / UnitDualQuaternion::<T>::from_isometry(&rhs); );
759
760// Isometry × UnitDualQuaternion
761dual_quaternion_op_impl!(
762    Mul, mul;
763    (U3, U1), (U4, U1);
764    self: &'a Isometry3<T>, rhs: &'b UnitDualQuaternion<T>,
765    Output = UnitDualQuaternion<T> => U3, U1;
766    UnitDualQuaternion::<T>::from_isometry(self) * rhs;
767    'a, 'b);
768
769dual_quaternion_op_impl!(
770    Mul, mul;
771    (U3, U1), (U4, U1);
772    self: &'a Isometry3<T>, rhs: UnitDualQuaternion<T>,
773    Output = UnitDualQuaternion<T> => U3, U1;
774    UnitDualQuaternion::<T>::from_isometry(self) * rhs;
775    'a);
776
777dual_quaternion_op_impl!(
778    Mul, mul;
779    (U3, U1), (U4, U1);
780    self: Isometry3<T>, rhs: &'b UnitDualQuaternion<T>,
781    Output = UnitDualQuaternion<T> => U3, U1;
782    UnitDualQuaternion::<T>::from_isometry(&self) * rhs;
783    'b);
784
785dual_quaternion_op_impl!(
786    Mul, mul;
787    (U3, U1), (U4, U1);
788    self: Isometry3<T>, rhs: UnitDualQuaternion<T>,
789    Output = UnitDualQuaternion<T> => U3, U1;
790    UnitDualQuaternion::<T>::from_isometry(&self) * rhs; );
791
792// Isometry ÷ UnitDualQuaternion
793dual_quaternion_op_impl!(
794    Div, div;
795    (U3, U1), (U4, U1);
796    self: &'a Isometry3<T>, rhs: &'b UnitDualQuaternion<T>,
797    Output = UnitDualQuaternion<T> => U3, U1;
798    // TODO: can we avoid the conversion from a rotation matrix?
799    UnitDualQuaternion::<T>::from_isometry(self) / rhs;
800    'a, 'b);
801
802dual_quaternion_op_impl!(
803    Div, div;
804    (U3, U1), (U4, U1);
805    self: &'a Isometry3<T>, rhs: UnitDualQuaternion<T>,
806    Output = UnitDualQuaternion<T> => U3, U1;
807    UnitDualQuaternion::<T>::from_isometry(self) / rhs;
808    'a);
809
810dual_quaternion_op_impl!(
811    Div, div;
812    (U3, U1), (U4, U1);
813    self: Isometry3<T>, rhs: &'b UnitDualQuaternion<T>,
814    Output = UnitDualQuaternion<T> => U3, U1;
815    UnitDualQuaternion::<T>::from_isometry(&self) / rhs;
816    'b);
817
818dual_quaternion_op_impl!(
819    Div, div;
820    (U3, U1), (U4, U1);
821    self: Isometry3<T>, rhs: UnitDualQuaternion<T>,
822    Output = UnitDualQuaternion<T> => U3, U1;
823    UnitDualQuaternion::<T>::from_isometry(&self) / rhs; );
824
825// UnitDualQuaternion × Vector
826dual_quaternion_op_impl!(
827    Mul, mul;
828    (U4, U1), (U3, U1) for SB: Storage<T, U3> ;
829    self: &'a UnitDualQuaternion<T>, rhs: &'b Vector<T, U3, SB>,
830    Output = Vector3<T> => U3, U1;
831    Unit::new_unchecked(self.as_ref().real.clone()) * rhs;
832    'a, 'b);
833
834dual_quaternion_op_impl!(
835    Mul, mul;
836    (U4, U1), (U3, U1) for SB: Storage<T, U3> ;
837    self: &'a UnitDualQuaternion<T>, rhs: Vector<T, U3, SB>,
838    Output = Vector3<T> => U3, U1;
839    self * &rhs;
840    'a);
841
842dual_quaternion_op_impl!(
843    Mul, mul;
844    (U4, U1), (U3, U1) for SB: Storage<T, U3> ;
845    self: UnitDualQuaternion<T>, rhs: &'b Vector<T, U3, SB>,
846    Output = Vector3<T> => U3, U1;
847    &self * rhs;
848    'b);
849
850dual_quaternion_op_impl!(
851    Mul, mul;
852    (U4, U1), (U3, U1) for SB: Storage<T, U3> ;
853    self: UnitDualQuaternion<T>, rhs: Vector<T, U3, SB>,
854    Output = Vector3<T> => U3, U1;
855    &self * &rhs; );
856
857// UnitDualQuaternion × Point
858dual_quaternion_op_impl!(
859    Mul, mul;
860    (U4, U1), (U3, U1);
861    self: &'a UnitDualQuaternion<T>, rhs: &'b Point3<T>,
862    Output = Point3<T> => U3, U1;
863    {
864        let two: T = crate::convert(2.0f64);
865        let q_point = Quaternion::from_parts(T::zero(), rhs.coords.clone());
866        Point::from(
867            ((self.as_ref().real.clone() * q_point + self.as_ref().dual.clone() * two) * self.as_ref().real.clone().conjugate())
868                .vector()
869                .into_owned(),
870        )
871    };
872    'a, 'b);
873
874dual_quaternion_op_impl!(
875    Mul, mul;
876    (U4, U1), (U3, U1);
877    self: &'a UnitDualQuaternion<T>, rhs: Point3<T>,
878    Output = Point3<T> => U3, U1;
879    self * &rhs;
880    'a);
881
882dual_quaternion_op_impl!(
883    Mul, mul;
884    (U4, U1), (U3, U1);
885    self: UnitDualQuaternion<T>, rhs: &'b Point3<T>,
886    Output = Point3<T> => U3, U1;
887    &self * rhs;
888    'b);
889
890dual_quaternion_op_impl!(
891    Mul, mul;
892    (U4, U1), (U3, U1);
893    self: UnitDualQuaternion<T>, rhs: Point3<T>,
894    Output = Point3<T> => U3, U1;
895    &self * &rhs; );
896
897// UnitDualQuaternion × Unit<Vector>
898dual_quaternion_op_impl!(
899    Mul, mul;
900    (U4, U1), (U3, U1) for SB: Storage<T, U3> ;
901    self: &'a UnitDualQuaternion<T>, rhs: &'b Unit<Vector<T, U3, SB>>,
902    Output = Unit<Vector3<T>> => U3, U4;
903    Unit::new_unchecked(self * rhs.as_ref());
904    'a, 'b);
905
906dual_quaternion_op_impl!(
907    Mul, mul;
908    (U4, U1), (U3, U1) for SB: Storage<T, U3> ;
909    self: &'a UnitDualQuaternion<T>, rhs: Unit<Vector<T, U3, SB>>,
910    Output = Unit<Vector3<T>> => U3, U4;
911    Unit::new_unchecked(self * rhs.into_inner());
912    'a);
913
914dual_quaternion_op_impl!(
915    Mul, mul;
916    (U4, U1), (U3, U1) for SB: Storage<T, U3> ;
917    self: UnitDualQuaternion<T>, rhs: &'b Unit<Vector<T, U3, SB>>,
918    Output = Unit<Vector3<T>> => U3, U4;
919    Unit::new_unchecked(self * rhs.as_ref());
920    'b);
921
922dual_quaternion_op_impl!(
923    Mul, mul;
924    (U4, U1), (U3, U1) for SB: Storage<T, U3> ;
925    self: UnitDualQuaternion<T>, rhs: Unit<Vector<T, U3, SB>>,
926    Output = Unit<Vector3<T>> => U3, U4;
927    Unit::new_unchecked(self * rhs.into_inner()); );
928
929macro_rules! left_scalar_mul_impl(
930    ($($T: ty),* $(,)*) => {$(
931        impl Mul<DualQuaternion<$T>> for $T {
932            type Output = DualQuaternion<$T>;
933
934            #[inline]
935            fn mul(self, right: DualQuaternion<$T>) -> Self::Output {
936                DualQuaternion::from_real_and_dual(
937                    self * right.real,
938                    self * right.dual
939                )
940            }
941        }
942
943        impl<'b> Mul<&'b DualQuaternion<$T>> for $T {
944            type Output = DualQuaternion<$T>;
945
946            #[inline]
947            fn mul(self, right: &'b DualQuaternion<$T>) -> Self::Output {
948                DualQuaternion::from_real_and_dual(
949                    self * &right.real,
950                    self * &right.dual
951                )
952            }
953        }
954    )*}
955);
956
957left_scalar_mul_impl!(f32, f64);
958
959macro_rules! dual_quaternion_op_impl(
960    ($OpAssign: ident, $op_assign: ident;
961     ($LhsRDim: ident, $LhsCDim: ident), ($RhsRDim: ident, $RhsCDim: ident);
962     $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty $(=> $VDimA: ty, $VDimB: ty)*;
963     $action: expr; $($lives: tt),*) => {
964        impl<$($lives ,)* T: SimdRealField> $OpAssign<$Rhs> for $Lhs
965            where T::Element: SimdRealField {
966
967            #[inline]
968            fn $op_assign(&mut $lhs, $rhs: $Rhs) {
969                $action
970            }
971        }
972    }
973);
974
975// DualQuaternion += DualQuaternion
976dual_quaternion_op_impl!(
977    AddAssign, add_assign;
978    (U4, U1), (U4, U1);
979    self: DualQuaternion<T>, rhs: &'b DualQuaternion<T>;
980    {
981        self.real += &rhs.real;
982        self.dual += &rhs.dual;
983    };
984    'b);
985
986dual_quaternion_op_impl!(
987    AddAssign, add_assign;
988    (U4, U1), (U4, U1);
989    self: DualQuaternion<T>, rhs: DualQuaternion<T>;
990    {
991        self.real += rhs.real;
992        self.dual += rhs.dual;
993    };);
994
995// DualQuaternion -= DualQuaternion
996dual_quaternion_op_impl!(
997    SubAssign, sub_assign;
998    (U4, U1), (U4, U1);
999    self: DualQuaternion<T>, rhs: &'b DualQuaternion<T>;
1000    {
1001        self.real -= &rhs.real;
1002        self.dual -= &rhs.dual;
1003    };
1004    'b);
1005
1006dual_quaternion_op_impl!(
1007    SubAssign, sub_assign;
1008    (U4, U1), (U4, U1);
1009    self: DualQuaternion<T>, rhs: DualQuaternion<T>;
1010    {
1011        self.real -= rhs.real;
1012        self.dual -= rhs.dual;
1013    };);
1014
1015// DualQuaternion ×= DualQuaternion
1016dual_quaternion_op_impl!(
1017    MulAssign, mul_assign;
1018    (U4, U1), (U4, U1);
1019    self: DualQuaternion<T>, rhs: &'b DualQuaternion<T>;
1020    {
1021        let res = &*self * rhs;
1022        self.real.coords.copy_from(&res.real.coords);
1023        self.dual.coords.copy_from(&res.dual.coords);
1024    };
1025    'b);
1026
1027dual_quaternion_op_impl!(
1028    MulAssign, mul_assign;
1029    (U4, U1), (U4, U1);
1030    self: DualQuaternion<T>, rhs: DualQuaternion<T>;
1031    *self *= &rhs;);
1032
1033// DualQuaternion ×= UnitDualQuaternion
1034dual_quaternion_op_impl!(
1035    MulAssign, mul_assign;
1036    (U4, U1), (U4, U1);
1037    self: DualQuaternion<T>, rhs: &'b UnitDualQuaternion<T>;
1038    {
1039        let res = &*self * rhs;
1040        self.real.coords.copy_from(&res.real.coords);
1041        self.dual.coords.copy_from(&res.dual.coords);
1042    };
1043    'b);
1044
1045dual_quaternion_op_impl!(
1046    MulAssign, mul_assign;
1047    (U4, U1), (U4, U1);
1048    self: DualQuaternion<T>, rhs: UnitDualQuaternion<T>;
1049    *self *= &rhs; );
1050
1051// DualQuaternion ÷= UnitDualQuaternion
1052dual_quaternion_op_impl!(
1053    DivAssign, div_assign;
1054    (U4, U1), (U4, U1);
1055    self: DualQuaternion<T>, rhs: &'b UnitDualQuaternion<T>;
1056    {
1057        let res = &*self / rhs;
1058        self.real.coords.copy_from(&res.real.coords);
1059        self.dual.coords.copy_from(&res.dual.coords);
1060    };
1061    'b);
1062
1063dual_quaternion_op_impl!(
1064    DivAssign, div_assign;
1065    (U4, U1), (U4, U1);
1066    self: DualQuaternion<T>, rhs: UnitDualQuaternion<T>;
1067    *self /= &rhs; );
1068
1069// UnitDualQuaternion ×= UnitDualQuaternion
1070dual_quaternion_op_impl!(
1071    MulAssign, mul_assign;
1072    (U4, U1), (U4, U1);
1073    self: UnitDualQuaternion<T>, rhs: &'b UnitDualQuaternion<T>;
1074    {
1075        let res = &*self * rhs;
1076        self.as_mut_unchecked().real.coords.copy_from(&res.as_ref().real.coords);
1077        self.as_mut_unchecked().dual.coords.copy_from(&res.as_ref().dual.coords);
1078    };
1079    'b);
1080
1081dual_quaternion_op_impl!(
1082    MulAssign, mul_assign;
1083    (U4, U1), (U4, U1);
1084    self: UnitDualQuaternion<T>, rhs: UnitDualQuaternion<T>;
1085    *self *= &rhs; );
1086
1087// UnitDualQuaternion ÷= UnitDualQuaternion
1088dual_quaternion_op_impl!(
1089    DivAssign, div_assign;
1090    (U4, U1), (U4, U1);
1091    self: UnitDualQuaternion<T>, rhs: &'b UnitDualQuaternion<T>;
1092    {
1093        let res = &*self / rhs;
1094        self.as_mut_unchecked().real.coords.copy_from(&res.as_ref().real.coords);
1095        self.as_mut_unchecked().dual.coords.copy_from(&res.as_ref().dual.coords);
1096    };
1097    'b);
1098
1099dual_quaternion_op_impl!(
1100    DivAssign, div_assign;
1101    (U4, U1), (U4, U1);
1102    self: UnitDualQuaternion<T>, rhs: UnitDualQuaternion<T>;
1103    *self /= &rhs; );
1104
1105// UnitDualQuaternion ×= UnitQuaternion
1106dual_quaternion_op_impl!(
1107    MulAssign, mul_assign;
1108    (U4, U1), (U4, U1);
1109    self: UnitDualQuaternion<T>, rhs: UnitQuaternion<T>;
1110    {
1111        let res = &*self * UnitDualQuaternion::from_rotation(rhs);
1112        self.as_mut_unchecked().real.coords.copy_from(&res.as_ref().real.coords);
1113        self.as_mut_unchecked().dual.coords.copy_from(&res.as_ref().dual.coords);
1114    };);
1115
1116dual_quaternion_op_impl!(
1117    MulAssign, mul_assign;
1118    (U4, U1), (U4, U1);
1119    self: UnitDualQuaternion<T>, rhs: &'b UnitQuaternion<T>;
1120    *self *= rhs.clone(); 'b);
1121
1122// UnitDualQuaternion ÷= UnitQuaternion
1123dual_quaternion_op_impl!(
1124    DivAssign, div_assign;
1125    (U4, U1), (U4, U1);
1126    self: UnitDualQuaternion<T>, rhs: &'b UnitQuaternion<T>;
1127    #[allow(clippy::suspicious_op_assign_impl)]
1128    {
1129        let res = &*self * UnitDualQuaternion::from_rotation(rhs.inverse());
1130        self.as_mut_unchecked().real.coords.copy_from(&res.as_ref().real.coords);
1131        self.as_mut_unchecked().dual.coords.copy_from(&res.as_ref().dual.coords);
1132    };
1133    'b);
1134
1135dual_quaternion_op_impl!(
1136    DivAssign, div_assign;
1137    (U4, U1), (U4, U1);
1138    self: UnitDualQuaternion<T>, rhs: UnitQuaternion<T>;
1139    *self /= &rhs; );
1140
1141// UnitDualQuaternion ×= Translation3
1142dual_quaternion_op_impl!(
1143    MulAssign, mul_assign;
1144    (U4, U1), (U4, U1);
1145    self: UnitDualQuaternion<T>, rhs: Translation3<T>;
1146    {
1147        let res = &*self * UnitDualQuaternion::from_parts(rhs, UnitQuaternion::identity());
1148        self.as_mut_unchecked().real.coords.copy_from(&res.as_ref().real.coords);
1149        self.as_mut_unchecked().dual.coords.copy_from(&res.as_ref().dual.coords);
1150    };);
1151
1152dual_quaternion_op_impl!(
1153    MulAssign, mul_assign;
1154    (U4, U1), (U4, U1);
1155    self: UnitDualQuaternion<T>, rhs: &'b Translation3<T>;
1156    *self *= rhs.clone(); 'b);
1157
1158// UnitDualQuaternion ÷= Translation3
1159dual_quaternion_op_impl!(
1160    DivAssign, div_assign;
1161    (U4, U1), (U4, U1);
1162    self: UnitDualQuaternion<T>, rhs: &'b Translation3<T>;
1163    #[allow(clippy::suspicious_op_assign_impl)]
1164    {
1165        let res = &*self * UnitDualQuaternion::from_parts(rhs.inverse(), UnitQuaternion::identity());
1166        self.as_mut_unchecked().real.coords.copy_from(&res.as_ref().real.coords);
1167        self.as_mut_unchecked().dual.coords.copy_from(&res.as_ref().dual.coords);
1168    };
1169    'b);
1170
1171dual_quaternion_op_impl!(
1172    DivAssign, div_assign;
1173    (U4, U1), (U4, U1);
1174    self: UnitDualQuaternion<T>, rhs: Translation3<T>;
1175    *self /= &rhs; );
1176
1177// UnitDualQuaternion ×= Isometry3
1178dual_quaternion_op_impl!(
1179    MulAssign, mul_assign;
1180    (U4, U1), (U3, U1);
1181    self: UnitDualQuaternion<T>, rhs: &'b Isometry3<T> => U3, U1;
1182    {
1183        let res = &*self * rhs;
1184        self.as_mut_unchecked().real.coords.copy_from(&res.as_ref().real.coords);
1185        self.as_mut_unchecked().dual.coords.copy_from(&res.as_ref().dual.coords);
1186    };
1187    'b);
1188
1189dual_quaternion_op_impl!(
1190    MulAssign, mul_assign;
1191    (U4, U1), (U3, U1);
1192    self: UnitDualQuaternion<T>, rhs: Isometry3<T> => U3, U1;
1193    *self *= &rhs; );
1194
1195// UnitDualQuaternion ÷= Isometry3
1196dual_quaternion_op_impl!(
1197    DivAssign, div_assign;
1198    (U4, U1), (U3, U1);
1199    self: UnitDualQuaternion<T>, rhs: &'b Isometry3<T> => U3, U1;
1200    {
1201        let res = &*self / rhs;
1202        self.as_mut_unchecked().real.coords.copy_from(&res.as_ref().real.coords);
1203        self.as_mut_unchecked().dual.coords.copy_from(&res.as_ref().dual.coords);
1204    };
1205    'b);
1206
1207dual_quaternion_op_impl!(
1208    DivAssign, div_assign;
1209    (U4, U1), (U3, U1);
1210    self: UnitDualQuaternion<T>, rhs: Isometry3<T> => U3, U1;
1211    *self /= &rhs; );
1212
1213macro_rules! scalar_op_impl(
1214    ($($Op: ident, $op: ident, $OpAssign: ident, $op_assign: ident);* $(;)*) => {$(
1215        impl<T: SimdRealField> $Op<T> for DualQuaternion<T>
1216         where T::Element: SimdRealField {
1217            type Output = DualQuaternion<T>;
1218
1219            #[inline]
1220            fn $op(self, n: T) -> Self::Output {
1221                DualQuaternion::from_real_and_dual(
1222                    self.real.clone().$op(n.clone()),
1223                    self.dual.clone().$op(n)
1224                )
1225            }
1226        }
1227
1228        impl<'a, T: SimdRealField> $Op<T> for &'a DualQuaternion<T>
1229         where T::Element: SimdRealField {
1230            type Output = DualQuaternion<T>;
1231
1232            #[inline]
1233            fn $op(self, n: T) -> Self::Output {
1234                DualQuaternion::from_real_and_dual(
1235                    self.real.clone().$op(n.clone()),
1236                    self.dual.clone().$op(n)
1237                )
1238            }
1239        }
1240
1241        impl<T: SimdRealField> $OpAssign<T> for DualQuaternion<T>
1242         where T::Element: SimdRealField {
1243
1244            #[inline]
1245            fn $op_assign(&mut self, n: T) {
1246                self.real.$op_assign(n.clone());
1247                self.dual.$op_assign(n);
1248            }
1249        }
1250    )*}
1251);
1252
1253scalar_op_impl!(
1254    Mul, mul, MulAssign, mul_assign;
1255    Div, div, DivAssign, div_assign;
1256);