nalgebra/geometry/
dual_quaternion.rs

1// The macros break if the references are taken out, for some reason.
2#![allow(clippy::op_ref)]
3
4#[cfg(feature = "rkyv-serialize")]
5use rkyv::bytecheck;
6
7use crate::{
8    Isometry3, Matrix4, Normed, OVector, Point3, Quaternion, Scalar, SimdRealField, Translation3,
9    Unit, UnitQuaternion, Vector3, Zero, U8,
10};
11use approx::{AbsDiffEq, RelativeEq, UlpsEq};
12#[cfg(feature = "serde-serialize-no-std")]
13use serde::{Deserialize, Deserializer, Serialize, Serializer};
14use std::fmt;
15
16use simba::scalar::{ClosedNeg, RealField};
17
18/// A dual quaternion.
19///
20/// # Indexing
21///
22/// `DualQuaternions` are stored as \[..real, ..dual\].
23/// Both of the quaternion components are laid out in `i, j, k, w` order.
24///
25/// # Example
26/// ```
27/// # use nalgebra::{DualQuaternion, Quaternion};
28///
29/// let real = Quaternion::new(1.0, 2.0, 3.0, 4.0);
30/// let dual = Quaternion::new(5.0, 6.0, 7.0, 8.0);
31///
32/// let dq = DualQuaternion::from_real_and_dual(real, dual);
33/// assert_eq!(dq[0], 2.0);
34/// assert_eq!(dq[1], 3.0);
35///
36/// assert_eq!(dq[4], 6.0);
37/// assert_eq!(dq[7], 5.0);
38/// ```
39///
40/// NOTE:
41///  As of December 2020, dual quaternion support is a work in progress.
42///  If a feature that you need is missing, feel free to open an issue or a PR.
43///  See <https://github.com/dimforge/nalgebra/issues/487>
44#[repr(C)]
45#[derive(Debug, Copy, Clone)]
46#[cfg_attr(
47    feature = "rkyv-serialize-no-std",
48    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize),
49    archive(
50        as = "DualQuaternion<T::Archived>",
51        bound(archive = "
52        T: rkyv::Archive,
53        Quaternion<T>: rkyv::Archive<Archived = Quaternion<T::Archived>>
54    ")
55    )
56)]
57#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))]
58pub struct DualQuaternion<T> {
59    /// The real component of the quaternion
60    pub real: Quaternion<T>,
61    /// The dual component of the quaternion
62    pub dual: Quaternion<T>,
63}
64
65impl<T: Scalar + Eq> Eq for DualQuaternion<T> {}
66
67impl<T: Scalar> PartialEq for DualQuaternion<T> {
68    #[inline]
69    fn eq(&self, right: &Self) -> bool {
70        self.real == right.real && self.dual == right.dual
71    }
72}
73
74impl<T: Scalar + Zero> Default for DualQuaternion<T> {
75    fn default() -> Self {
76        Self {
77            real: Quaternion::default(),
78            dual: Quaternion::default(),
79        }
80    }
81}
82
83impl<T: SimdRealField> DualQuaternion<T>
84where
85    T::Element: SimdRealField,
86{
87    /// Normalizes this quaternion.
88    ///
89    /// # Example
90    /// ```
91    /// # #[macro_use] extern crate approx;
92    /// # use nalgebra::{DualQuaternion, Quaternion};
93    /// let real = Quaternion::new(1.0, 2.0, 3.0, 4.0);
94    /// let dual = Quaternion::new(5.0, 6.0, 7.0, 8.0);
95    /// let dq = DualQuaternion::from_real_and_dual(real, dual);
96    ///
97    /// let dq_normalized = dq.normalize();
98    ///
99    /// assert_relative_eq!(dq_normalized.real.norm(), 1.0);
100    /// ```
101    #[inline]
102    #[must_use = "Did you mean to use normalize_mut()?"]
103    pub fn normalize(&self) -> Self {
104        let real_norm = self.real.norm();
105
106        Self::from_real_and_dual(
107            self.real.clone() / real_norm.clone(),
108            self.dual.clone() / real_norm,
109        )
110    }
111
112    /// Normalizes this quaternion.
113    ///
114    /// # Example
115    /// ```
116    /// # #[macro_use] extern crate approx;
117    /// # use nalgebra::{DualQuaternion, Quaternion};
118    /// let real = Quaternion::new(1.0, 2.0, 3.0, 4.0);
119    /// let dual = Quaternion::new(5.0, 6.0, 7.0, 8.0);
120    /// let mut dq = DualQuaternion::from_real_and_dual(real, dual);
121    ///
122    /// dq.normalize_mut();
123    ///
124    /// assert_relative_eq!(dq.real.norm(), 1.0);
125    /// ```
126    #[inline]
127    pub fn normalize_mut(&mut self) -> T {
128        let real_norm = self.real.norm();
129        self.real /= real_norm.clone();
130        self.dual /= real_norm.clone();
131        real_norm
132    }
133
134    /// The conjugate of this dual quaternion, containing the conjugate of
135    /// the real and imaginary parts..
136    ///
137    /// # Example
138    /// ```
139    /// # use nalgebra::{DualQuaternion, Quaternion};
140    /// let real = Quaternion::new(1.0, 2.0, 3.0, 4.0);
141    /// let dual = Quaternion::new(5.0, 6.0, 7.0, 8.0);
142    /// let dq = DualQuaternion::from_real_and_dual(real, dual);
143    ///
144    /// let conj = dq.conjugate();
145    /// assert!(conj.real.i == -2.0 && conj.real.j == -3.0 && conj.real.k == -4.0);
146    /// assert!(conj.real.w == 1.0);
147    /// assert!(conj.dual.i == -6.0 && conj.dual.j == -7.0 && conj.dual.k == -8.0);
148    /// assert!(conj.dual.w == 5.0);
149    /// ```
150    #[inline]
151    #[must_use = "Did you mean to use conjugate_mut()?"]
152    pub fn conjugate(&self) -> Self {
153        Self::from_real_and_dual(self.real.conjugate(), self.dual.conjugate())
154    }
155
156    /// Replaces this quaternion by its conjugate.
157    ///
158    /// # Example
159    /// ```
160    /// # use nalgebra::{DualQuaternion, Quaternion};
161    /// let real = Quaternion::new(1.0, 2.0, 3.0, 4.0);
162    /// let dual = Quaternion::new(5.0, 6.0, 7.0, 8.0);
163    /// let mut dq = DualQuaternion::from_real_and_dual(real, dual);
164    ///
165    /// dq.conjugate_mut();
166    /// assert!(dq.real.i == -2.0 && dq.real.j == -3.0 && dq.real.k == -4.0);
167    /// assert!(dq.real.w == 1.0);
168    /// assert!(dq.dual.i == -6.0 && dq.dual.j == -7.0 && dq.dual.k == -8.0);
169    /// assert!(dq.dual.w == 5.0);
170    /// ```
171    #[inline]
172    pub fn conjugate_mut(&mut self) {
173        self.real.conjugate_mut();
174        self.dual.conjugate_mut();
175    }
176
177    /// Inverts this dual quaternion if it is not zero.
178    ///
179    /// # Example
180    /// ```
181    /// # #[macro_use] extern crate approx;
182    /// # use nalgebra::{DualQuaternion, Quaternion};
183    /// let real = Quaternion::new(1.0, 2.0, 3.0, 4.0);
184    /// let dual = Quaternion::new(5.0, 6.0, 7.0, 8.0);
185    /// let dq = DualQuaternion::from_real_and_dual(real, dual);
186    /// let inverse = dq.try_inverse();
187    ///
188    /// assert!(inverse.is_some());
189    /// assert_relative_eq!(inverse.unwrap() * dq, DualQuaternion::identity());
190    ///
191    /// //Non-invertible case
192    /// let zero = Quaternion::new(0.0, 0.0, 0.0, 0.0);
193    /// let dq = DualQuaternion::from_real_and_dual(zero, zero);
194    /// let inverse = dq.try_inverse();
195    ///
196    /// assert!(inverse.is_none());
197    /// ```
198    #[inline]
199    #[must_use = "Did you mean to use try_inverse_mut()?"]
200    pub fn try_inverse(&self) -> Option<Self>
201    where
202        T: RealField,
203    {
204        let mut res = self.clone();
205        if res.try_inverse_mut() {
206            Some(res)
207        } else {
208            None
209        }
210    }
211
212    /// Inverts this dual quaternion in-place if it is not zero.
213    ///
214    /// # Example
215    /// ```
216    /// # #[macro_use] extern crate approx;
217    /// # use nalgebra::{DualQuaternion, Quaternion};
218    /// let real = Quaternion::new(1.0, 2.0, 3.0, 4.0);
219    /// let dual = Quaternion::new(5.0, 6.0, 7.0, 8.0);
220    /// let dq = DualQuaternion::from_real_and_dual(real, dual);
221    /// let mut dq_inverse = dq;
222    /// dq_inverse.try_inverse_mut();
223    ///
224    /// assert_relative_eq!(dq_inverse * dq, DualQuaternion::identity());
225    ///
226    /// //Non-invertible case
227    /// let zero = Quaternion::new(0.0, 0.0, 0.0, 0.0);
228    /// let mut dq = DualQuaternion::from_real_and_dual(zero, zero);
229    /// assert!(!dq.try_inverse_mut());
230    /// ```
231    #[inline]
232    pub fn try_inverse_mut(&mut self) -> bool
233    where
234        T: RealField,
235    {
236        let inverted = self.real.try_inverse_mut();
237        if inverted {
238            self.dual = -self.real.clone() * self.dual.clone() * self.real.clone();
239            true
240        } else {
241            false
242        }
243    }
244
245    /// Linear interpolation between two dual quaternions.
246    ///
247    /// Computes `self * (1 - t) + other * t`.
248    ///
249    /// # Example
250    /// ```
251    /// # use nalgebra::{DualQuaternion, Quaternion};
252    /// let dq1 = DualQuaternion::from_real_and_dual(
253    ///     Quaternion::new(1.0, 0.0, 0.0, 4.0),
254    ///     Quaternion::new(0.0, 2.0, 0.0, 0.0)
255    /// );
256    /// let dq2 = DualQuaternion::from_real_and_dual(
257    ///     Quaternion::new(2.0, 0.0, 1.0, 0.0),
258    ///     Quaternion::new(0.0, 2.0, 0.0, 0.0)
259    /// );
260    /// assert_eq!(dq1.lerp(&dq2, 0.25), DualQuaternion::from_real_and_dual(
261    ///     Quaternion::new(1.25, 0.0, 0.25, 3.0),
262    ///     Quaternion::new(0.0, 2.0, 0.0, 0.0)
263    /// ));
264    /// ```
265    #[inline]
266    #[must_use]
267    pub fn lerp(&self, other: &Self, t: T) -> Self {
268        self * (T::one() - t.clone()) + other * t
269    }
270}
271
272#[cfg(feature = "bytemuck")]
273unsafe impl<T> bytemuck::Zeroable for DualQuaternion<T>
274where
275    T: Scalar + bytemuck::Zeroable,
276    Quaternion<T>: bytemuck::Zeroable,
277{
278}
279
280#[cfg(feature = "bytemuck")]
281unsafe impl<T> bytemuck::Pod for DualQuaternion<T>
282where
283    T: Scalar + bytemuck::Pod,
284    Quaternion<T>: bytemuck::Pod,
285{
286}
287
288#[cfg(feature = "serde-serialize-no-std")]
289impl<T: SimdRealField> Serialize for DualQuaternion<T>
290where
291    T: Serialize,
292{
293    fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
294    where
295        S: Serializer,
296    {
297        self.as_ref().serialize(serializer)
298    }
299}
300
301#[cfg(feature = "serde-serialize-no-std")]
302impl<'a, T: SimdRealField> Deserialize<'a> for DualQuaternion<T>
303where
304    T: Deserialize<'a>,
305{
306    fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error>
307    where
308        Des: Deserializer<'a>,
309    {
310        type Dq<T> = [T; 8];
311
312        let dq: Dq<T> = Dq::<T>::deserialize(deserializer)?;
313
314        Ok(Self {
315            real: Quaternion::new(dq[3].clone(), dq[0].clone(), dq[1].clone(), dq[2].clone()),
316            dual: Quaternion::new(dq[7].clone(), dq[4].clone(), dq[5].clone(), dq[6].clone()),
317        })
318    }
319}
320
321impl<T: RealField> DualQuaternion<T> {
322    #[allow(clippy::wrong_self_convention)]
323    fn to_vector(&self) -> OVector<T, U8> {
324        self.as_ref().clone().into()
325    }
326}
327
328impl<T: RealField + AbsDiffEq<Epsilon = T>> AbsDiffEq for DualQuaternion<T> {
329    type Epsilon = T;
330
331    #[inline]
332    fn default_epsilon() -> Self::Epsilon {
333        T::default_epsilon()
334    }
335
336    #[inline]
337    fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
338        self.to_vector().abs_diff_eq(&other.to_vector(), epsilon.clone()) ||
339        // Account for the double-covering of S², i.e. q = -q
340        self.to_vector().iter().zip(other.to_vector().iter()).all(|(a, b)| a.abs_diff_eq(&-b.clone(), epsilon.clone()))
341    }
342}
343
344impl<T: RealField + RelativeEq<Epsilon = T>> RelativeEq for DualQuaternion<T> {
345    #[inline]
346    fn default_max_relative() -> Self::Epsilon {
347        T::default_max_relative()
348    }
349
350    #[inline]
351    fn relative_eq(
352        &self,
353        other: &Self,
354        epsilon: Self::Epsilon,
355        max_relative: Self::Epsilon,
356    ) -> bool {
357        self.to_vector().relative_eq(&other.to_vector(), epsilon.clone(), max_relative.clone()) ||
358        // Account for the double-covering of S², i.e. q = -q
359        self.to_vector().iter().zip(other.to_vector().iter()).all(|(a, b)| a.relative_eq(&-b.clone(), epsilon.clone(), max_relative.clone()))
360    }
361}
362
363impl<T: RealField + UlpsEq<Epsilon = T>> UlpsEq for DualQuaternion<T> {
364    #[inline]
365    fn default_max_ulps() -> u32 {
366        T::default_max_ulps()
367    }
368
369    #[inline]
370    fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
371        self.to_vector().ulps_eq(&other.to_vector(), epsilon.clone(), max_ulps) ||
372        // Account for the double-covering of S², i.e. q = -q.
373        self.to_vector().iter().zip(other.to_vector().iter()).all(|(a, b)| a.ulps_eq(&-b.clone(), epsilon.clone(), max_ulps))
374    }
375}
376
377/// A unit dual quaternion. May be used to represent a rotation followed by a
378/// translation.
379pub type UnitDualQuaternion<T> = Unit<DualQuaternion<T>>;
380
381impl<T: Scalar + ClosedNeg + PartialEq + SimdRealField> PartialEq for UnitDualQuaternion<T> {
382    #[inline]
383    fn eq(&self, rhs: &Self) -> bool {
384        self.as_ref().eq(rhs.as_ref())
385    }
386}
387
388impl<T: Scalar + ClosedNeg + Eq + SimdRealField> Eq for UnitDualQuaternion<T> {}
389
390impl<T: SimdRealField> Normed for DualQuaternion<T> {
391    type Norm = T::SimdRealField;
392
393    #[inline]
394    fn norm(&self) -> T::SimdRealField {
395        self.real.norm()
396    }
397
398    #[inline]
399    fn norm_squared(&self) -> T::SimdRealField {
400        self.real.norm_squared()
401    }
402
403    #[inline]
404    fn scale_mut(&mut self, n: Self::Norm) {
405        self.real.scale_mut(n.clone());
406        self.dual.scale_mut(n);
407    }
408
409    #[inline]
410    fn unscale_mut(&mut self, n: Self::Norm) {
411        self.real.unscale_mut(n.clone());
412        self.dual.unscale_mut(n);
413    }
414}
415
416impl<T: SimdRealField> UnitDualQuaternion<T>
417where
418    T::Element: SimdRealField,
419{
420    /// The underlying dual quaternion.
421    ///
422    /// Same as `self.as_ref()`.
423    ///
424    /// # Example
425    /// ```
426    /// # use nalgebra::{DualQuaternion, UnitDualQuaternion, Quaternion};
427    /// let id = UnitDualQuaternion::identity();
428    /// assert_eq!(*id.dual_quaternion(), DualQuaternion::from_real_and_dual(
429    ///     Quaternion::new(1.0, 0.0, 0.0, 0.0),
430    ///     Quaternion::new(0.0, 0.0, 0.0, 0.0)
431    /// ));
432    /// ```
433    #[inline]
434    #[must_use]
435    pub fn dual_quaternion(&self) -> &DualQuaternion<T> {
436        self.as_ref()
437    }
438
439    /// Compute the conjugate of this unit quaternion.
440    ///
441    /// # Example
442    /// ```
443    /// # use nalgebra::{UnitDualQuaternion, DualQuaternion, Quaternion};
444    /// let qr = Quaternion::new(1.0, 2.0, 3.0, 4.0);
445    /// let qd = Quaternion::new(5.0, 6.0, 7.0, 8.0);
446    /// let unit = UnitDualQuaternion::new_normalize(
447    ///     DualQuaternion::from_real_and_dual(qr, qd)
448    /// );
449    /// let conj = unit.conjugate();
450    /// assert_eq!(conj.real, unit.real.conjugate());
451    /// assert_eq!(conj.dual, unit.dual.conjugate());
452    /// ```
453    #[inline]
454    #[must_use = "Did you mean to use conjugate_mut()?"]
455    pub fn conjugate(&self) -> Self {
456        Self::new_unchecked(self.as_ref().conjugate())
457    }
458
459    /// Compute the conjugate of this unit quaternion in-place.
460    ///
461    /// # Example
462    /// ```
463    /// # use nalgebra::{UnitDualQuaternion, DualQuaternion, Quaternion};
464    /// let qr = Quaternion::new(1.0, 2.0, 3.0, 4.0);
465    /// let qd = Quaternion::new(5.0, 6.0, 7.0, 8.0);
466    /// let unit = UnitDualQuaternion::new_normalize(
467    ///     DualQuaternion::from_real_and_dual(qr, qd)
468    /// );
469    /// let mut conj = unit.clone();
470    /// conj.conjugate_mut();
471    /// assert_eq!(conj.as_ref().real, unit.as_ref().real.conjugate());
472    /// assert_eq!(conj.as_ref().dual, unit.as_ref().dual.conjugate());
473    /// ```
474    #[inline]
475    pub fn conjugate_mut(&mut self) {
476        self.as_mut_unchecked().conjugate_mut()
477    }
478
479    /// Inverts this dual quaternion if it is not zero.
480    ///
481    /// # Example
482    /// ```
483    /// # #[macro_use] extern crate approx;
484    /// # use nalgebra::{UnitDualQuaternion, Quaternion, DualQuaternion};
485    /// let qr = Quaternion::new(1.0, 2.0, 3.0, 4.0);
486    /// let qd = Quaternion::new(5.0, 6.0, 7.0, 8.0);
487    /// let unit = UnitDualQuaternion::new_normalize(DualQuaternion::from_real_and_dual(qr, qd));
488    /// let inv = unit.inverse();
489    /// assert_relative_eq!(unit * inv, UnitDualQuaternion::identity(), epsilon = 1.0e-6);
490    /// assert_relative_eq!(inv * unit, UnitDualQuaternion::identity(), epsilon = 1.0e-6);
491    /// ```
492    #[inline]
493    #[must_use = "Did you mean to use inverse_mut()?"]
494    pub fn inverse(&self) -> Self {
495        let real = Unit::new_unchecked(self.as_ref().real.clone())
496            .inverse()
497            .into_inner();
498        let dual = -real.clone() * self.as_ref().dual.clone() * real.clone();
499        UnitDualQuaternion::new_unchecked(DualQuaternion { real, dual })
500    }
501
502    /// Inverts this dual quaternion in place if it is not zero.
503    ///
504    /// # Example
505    /// ```
506    /// # #[macro_use] extern crate approx;
507    /// # use nalgebra::{UnitDualQuaternion, Quaternion, DualQuaternion};
508    /// let qr = Quaternion::new(1.0, 2.0, 3.0, 4.0);
509    /// let qd = Quaternion::new(5.0, 6.0, 7.0, 8.0);
510    /// let unit = UnitDualQuaternion::new_normalize(DualQuaternion::from_real_and_dual(qr, qd));
511    /// let mut inv = unit.clone();
512    /// inv.inverse_mut();
513    /// assert_relative_eq!(unit * inv, UnitDualQuaternion::identity(), epsilon = 1.0e-6);
514    /// assert_relative_eq!(inv * unit, UnitDualQuaternion::identity(), epsilon = 1.0e-6);
515    /// ```
516    #[inline]
517    pub fn inverse_mut(&mut self) {
518        let quat = self.as_mut_unchecked();
519        quat.real = Unit::new_unchecked(quat.real.clone())
520            .inverse()
521            .into_inner();
522        quat.dual = -quat.real.clone() * quat.dual.clone() * quat.real.clone();
523    }
524
525    /// The unit dual quaternion needed to make `self` and `other` coincide.
526    ///
527    /// The result is such that: `self.isometry_to(other) * self == other`.
528    ///
529    /// # Example
530    /// ```
531    /// # #[macro_use] extern crate approx;
532    /// # use nalgebra::{UnitDualQuaternion, DualQuaternion, Quaternion};
533    /// let qr = Quaternion::new(1.0, 2.0, 3.0, 4.0);
534    /// let qd = Quaternion::new(5.0, 6.0, 7.0, 8.0);
535    /// let dq1 = UnitDualQuaternion::new_normalize(DualQuaternion::from_real_and_dual(qr, qd));
536    /// let dq2 = UnitDualQuaternion::new_normalize(DualQuaternion::from_real_and_dual(qd, qr));
537    /// let dq_to = dq1.isometry_to(&dq2);
538    /// assert_relative_eq!(dq_to * dq1, dq2, epsilon = 1.0e-6);
539    /// ```
540    #[inline]
541    #[must_use]
542    pub fn isometry_to(&self, other: &Self) -> Self {
543        other / self
544    }
545
546    /// Linear interpolation between two unit dual quaternions.
547    ///
548    /// The result is not normalized.
549    ///
550    /// # Example
551    /// ```
552    /// # #[macro_use] extern crate approx;
553    /// # use nalgebra::{UnitDualQuaternion, DualQuaternion, Quaternion};
554    /// let dq1 = UnitDualQuaternion::new_normalize(DualQuaternion::from_real_and_dual(
555    ///     Quaternion::new(0.5, 0.0, 0.5, 0.0),
556    ///     Quaternion::new(0.0, 0.5, 0.0, 0.5)
557    /// ));
558    /// let dq2 = UnitDualQuaternion::new_normalize(DualQuaternion::from_real_and_dual(
559    ///     Quaternion::new(0.5, 0.0, 0.0, 0.5),
560    ///     Quaternion::new(0.5, 0.0, 0.5, 0.0)
561    /// ));
562    /// assert_relative_eq!(
563    ///     UnitDualQuaternion::new_normalize(dq1.lerp(&dq2, 0.5)),
564    ///     UnitDualQuaternion::new_normalize(
565    ///         DualQuaternion::from_real_and_dual(
566    ///             Quaternion::new(0.5, 0.0, 0.25, 0.25),
567    ///             Quaternion::new(0.25, 0.25, 0.25, 0.25)
568    ///         )
569    ///     ),
570    ///     epsilon = 1.0e-6
571    /// );
572    /// ```
573    #[inline]
574    #[must_use]
575    pub fn lerp(&self, other: &Self, t: T) -> DualQuaternion<T> {
576        self.as_ref().lerp(other.as_ref(), t)
577    }
578
579    /// Normalized linear interpolation between two unit quaternions.
580    ///
581    /// This is the same as `self.lerp` except that the result is normalized.
582    ///
583    /// # Example
584    /// ```
585    /// # #[macro_use] extern crate approx;
586    /// # use nalgebra::{UnitDualQuaternion, DualQuaternion, Quaternion};
587    /// let dq1 = UnitDualQuaternion::new_normalize(DualQuaternion::from_real_and_dual(
588    ///     Quaternion::new(0.5, 0.0, 0.5, 0.0),
589    ///     Quaternion::new(0.0, 0.5, 0.0, 0.5)
590    /// ));
591    /// let dq2 = UnitDualQuaternion::new_normalize(DualQuaternion::from_real_and_dual(
592    ///     Quaternion::new(0.5, 0.0, 0.0, 0.5),
593    ///     Quaternion::new(0.5, 0.0, 0.5, 0.0)
594    /// ));
595    /// assert_relative_eq!(dq1.nlerp(&dq2, 0.2), UnitDualQuaternion::new_normalize(
596    ///     DualQuaternion::from_real_and_dual(
597    ///         Quaternion::new(0.5, 0.0, 0.4, 0.1),
598    ///         Quaternion::new(0.1, 0.4, 0.1, 0.4)
599    ///     )
600    /// ), epsilon = 1.0e-6);
601    /// ```
602    #[inline]
603    #[must_use]
604    pub fn nlerp(&self, other: &Self, t: T) -> Self {
605        let mut res = self.lerp(other, t);
606        let _ = res.normalize_mut();
607
608        Self::new_unchecked(res)
609    }
610
611    /// Screw linear interpolation between two unit quaternions. This creates a
612    /// smooth arc from one dual-quaternion to another.
613    ///
614    /// Panics if the angle between both quaternion is 180 degrees (in which
615    /// case the interpolation is not well-defined). Use `.try_sclerp`
616    /// instead to avoid the panic.
617    ///
618    /// # Example
619    /// ```
620    /// # #[macro_use] extern crate approx;
621    /// # use nalgebra::{UnitDualQuaternion, DualQuaternion, UnitQuaternion, Vector3};
622    ///
623    /// let dq1 = UnitDualQuaternion::from_parts(
624    ///     Vector3::new(0.0, 3.0, 0.0).into(),
625    ///     UnitQuaternion::from_euler_angles(std::f32::consts::FRAC_PI_4, 0.0, 0.0),
626    /// );
627    ///
628    /// let dq2 = UnitDualQuaternion::from_parts(
629    ///     Vector3::new(0.0, 0.0, 3.0).into(),
630    ///     UnitQuaternion::from_euler_angles(-std::f32::consts::PI, 0.0, 0.0),
631    /// );
632    ///
633    /// let dq = dq1.sclerp(&dq2, 1.0 / 3.0);
634    ///
635    /// assert_relative_eq!(
636    ///     dq.rotation().euler_angles().0, std::f32::consts::FRAC_PI_2, epsilon = 1.0e-6
637    /// );
638    /// assert_relative_eq!(dq.translation().vector.y, 3.0, epsilon = 1.0e-6);
639    /// ```
640    #[inline]
641    #[must_use]
642    pub fn sclerp(&self, other: &Self, t: T) -> Self
643    where
644        T: RealField,
645    {
646        self.try_sclerp(other, t, T::default_epsilon())
647            .expect("DualQuaternion sclerp: ambiguous configuration.")
648    }
649
650    /// Computes the screw-linear interpolation between two unit quaternions or
651    /// returns `None` if both quaternions are approximately 180 degrees
652    /// apart (in which case the interpolation is not well-defined).
653    ///
654    /// # Arguments
655    /// * `self`: the first quaternion to interpolate from.
656    /// * `other`: the second quaternion to interpolate toward.
657    /// * `t`: the interpolation parameter. Should be between 0 and 1.
658    /// * `epsilon`: the value below which the sinus of the angle separating
659    ///   both quaternion must be to return `None`.
660    #[inline]
661    #[must_use]
662    pub fn try_sclerp(&self, other: &Self, t: T, epsilon: T) -> Option<Self>
663    where
664        T: RealField,
665    {
666        let two = T::one() + T::one();
667        let half = T::one() / two.clone();
668
669        // Invert one of the quaternions if we've got a longest-path
670        // interpolation.
671        let other = {
672            let dot_product = self.as_ref().real.coords.dot(&other.as_ref().real.coords);
673            if relative_eq!(dot_product, T::zero(), epsilon = epsilon.clone()) {
674                return None;
675            }
676
677            if dot_product < T::zero() {
678                -other.clone()
679            } else {
680                other.clone()
681            }
682        };
683
684        let difference = self.as_ref().conjugate() * other.as_ref();
685        let norm_squared = difference.real.vector().norm_squared();
686        if relative_eq!(norm_squared, T::zero(), epsilon = epsilon) {
687            return Some(Self::from_parts(
688                self.translation()
689                    .vector
690                    .lerp(&other.translation().vector, t)
691                    .into(),
692                self.rotation(),
693            ));
694        }
695
696        let scalar: T = difference.real.scalar();
697        let mut angle = two.clone() * scalar.acos();
698
699        let inverse_norm_squared: T = T::one() / norm_squared;
700        let inverse_norm = inverse_norm_squared.sqrt();
701
702        let mut pitch = -two * difference.dual.scalar() * inverse_norm.clone();
703        let direction = difference.real.vector() * inverse_norm.clone();
704        let moment = (difference.dual.vector()
705            - direction.clone() * (pitch.clone() * difference.real.scalar() * half.clone()))
706            * inverse_norm;
707
708        angle *= t.clone();
709        pitch *= t;
710
711        let sin = (half.clone() * angle.clone()).sin();
712        let cos = (half.clone() * angle).cos();
713
714        let real = Quaternion::from_parts(cos.clone(), direction.clone() * sin.clone());
715        let dual = Quaternion::from_parts(
716            -pitch.clone() * half.clone() * sin.clone(),
717            moment * sin + direction * (pitch * half * cos),
718        );
719
720        Some(
721            self * UnitDualQuaternion::new_unchecked(DualQuaternion::from_real_and_dual(
722                real, dual,
723            )),
724        )
725    }
726
727    /// Return the rotation part of this unit dual quaternion.
728    ///
729    /// # Example
730    /// ```
731    /// # #[macro_use] extern crate approx;
732    /// # use nalgebra::{UnitDualQuaternion, UnitQuaternion, Vector3};
733    /// let dq = UnitDualQuaternion::from_parts(
734    ///     Vector3::new(0.0, 3.0, 0.0).into(),
735    ///     UnitQuaternion::from_euler_angles(std::f32::consts::FRAC_PI_4, 0.0, 0.0)
736    /// );
737    ///
738    /// assert_relative_eq!(
739    ///     dq.rotation().angle(), std::f32::consts::FRAC_PI_4, epsilon = 1.0e-6
740    /// );
741    /// ```
742    #[inline]
743    #[must_use]
744    pub fn rotation(&self) -> UnitQuaternion<T> {
745        Unit::new_unchecked(self.as_ref().real.clone())
746    }
747
748    /// Return the translation part of this unit dual quaternion.
749    ///
750    /// # Example
751    /// ```
752    /// # #[macro_use] extern crate approx;
753    /// # use nalgebra::{UnitDualQuaternion, UnitQuaternion, Vector3};
754    /// let dq = UnitDualQuaternion::from_parts(
755    ///     Vector3::new(0.0, 3.0, 0.0).into(),
756    ///     UnitQuaternion::from_euler_angles(std::f32::consts::FRAC_PI_4, 0.0, 0.0)
757    /// );
758    ///
759    /// assert_relative_eq!(
760    ///     dq.translation().vector, Vector3::new(0.0, 3.0, 0.0), epsilon = 1.0e-6
761    /// );
762    /// ```
763    #[inline]
764    #[must_use]
765    pub fn translation(&self) -> Translation3<T> {
766        let two = T::one() + T::one();
767        Translation3::from(
768            ((self.as_ref().dual.clone() * self.as_ref().real.clone().conjugate()) * two)
769                .vector()
770                .into_owned(),
771        )
772    }
773
774    /// Builds an isometry from this unit dual quaternion.
775    ///
776    /// # Example
777    /// ```
778    /// # #[macro_use] extern crate approx;
779    /// # use nalgebra::{UnitDualQuaternion, UnitQuaternion, Vector3};
780    /// let rotation = UnitQuaternion::from_euler_angles(std::f32::consts::PI, 0.0, 0.0);
781    /// let translation = Vector3::new(1.0, 3.0, 2.5);
782    /// let dq = UnitDualQuaternion::from_parts(
783    ///     translation.into(),
784    ///     rotation
785    /// );
786    /// let iso = dq.to_isometry();
787    ///
788    /// assert_relative_eq!(iso.rotation.angle(), std::f32::consts::PI, epsilon = 1.0e-6);
789    /// assert_relative_eq!(iso.translation.vector, translation, epsilon = 1.0e-6);
790    /// ```
791    #[inline]
792    #[must_use]
793    pub fn to_isometry(self) -> Isometry3<T> {
794        Isometry3::from_parts(self.translation(), self.rotation())
795    }
796
797    /// Rotate and translate a point by this unit dual quaternion interpreted
798    /// as an isometry.
799    ///
800    /// This is the same as the multiplication `self * pt`.
801    ///
802    /// # Example
803    /// ```
804    /// # #[macro_use] extern crate approx;
805    /// # use nalgebra::{UnitDualQuaternion, UnitQuaternion, Vector3, Point3};
806    /// let dq = UnitDualQuaternion::from_parts(
807    ///     Vector3::new(0.0, 3.0, 0.0).into(),
808    ///     UnitQuaternion::from_euler_angles(std::f32::consts::FRAC_PI_2, 0.0, 0.0)
809    /// );
810    /// let point = Point3::new(1.0, 2.0, 3.0);
811    ///
812    /// assert_relative_eq!(
813    ///     dq.transform_point(&point), Point3::new(1.0, 0.0, 2.0), epsilon = 1.0e-6
814    /// );
815    /// ```
816    #[inline]
817    #[must_use]
818    pub fn transform_point(&self, pt: &Point3<T>) -> Point3<T> {
819        self * pt
820    }
821
822    /// Rotate a vector by this unit dual quaternion, ignoring the translational
823    /// component.
824    ///
825    /// This is the same as the multiplication `self * v`.
826    ///
827    /// # Example
828    /// ```
829    /// # #[macro_use] extern crate approx;
830    /// # use nalgebra::{UnitDualQuaternion, UnitQuaternion, Vector3};
831    /// let dq = UnitDualQuaternion::from_parts(
832    ///     Vector3::new(0.0, 3.0, 0.0).into(),
833    ///     UnitQuaternion::from_euler_angles(std::f32::consts::FRAC_PI_2, 0.0, 0.0)
834    /// );
835    /// let vector = Vector3::new(1.0, 2.0, 3.0);
836    ///
837    /// assert_relative_eq!(
838    ///     dq.transform_vector(&vector), Vector3::new(1.0, -3.0, 2.0), epsilon = 1.0e-6
839    /// );
840    /// ```
841    #[inline]
842    #[must_use]
843    pub fn transform_vector(&self, v: &Vector3<T>) -> Vector3<T> {
844        self * v
845    }
846
847    /// Rotate and translate a point by the inverse of this unit quaternion.
848    ///
849    /// This may be cheaper than inverting the unit dual quaternion and
850    /// transforming the point.
851    ///
852    /// # Example
853    /// ```
854    /// # #[macro_use] extern crate approx;
855    /// # use nalgebra::{UnitDualQuaternion, UnitQuaternion, Vector3, Point3};
856    /// let dq = UnitDualQuaternion::from_parts(
857    ///     Vector3::new(0.0, 3.0, 0.0).into(),
858    ///     UnitQuaternion::from_euler_angles(std::f32::consts::FRAC_PI_2, 0.0, 0.0)
859    /// );
860    /// let point = Point3::new(1.0, 2.0, 3.0);
861    ///
862    /// assert_relative_eq!(
863    ///     dq.inverse_transform_point(&point), Point3::new(1.0, 3.0, 1.0), epsilon = 1.0e-6
864    /// );
865    /// ```
866    #[inline]
867    #[must_use]
868    pub fn inverse_transform_point(&self, pt: &Point3<T>) -> Point3<T> {
869        self.inverse() * pt
870    }
871
872    /// Rotate a vector by the inverse of this unit quaternion, ignoring the
873    /// translational component.
874    ///
875    /// This may be cheaper than inverting the unit dual quaternion and
876    /// transforming the vector.
877    ///
878    /// # Example
879    /// ```
880    /// # #[macro_use] extern crate approx;
881    /// # use nalgebra::{UnitDualQuaternion, UnitQuaternion, Vector3};
882    /// let dq = UnitDualQuaternion::from_parts(
883    ///     Vector3::new(0.0, 3.0, 0.0).into(),
884    ///     UnitQuaternion::from_euler_angles(std::f32::consts::FRAC_PI_2, 0.0, 0.0)
885    /// );
886    /// let vector = Vector3::new(1.0, 2.0, 3.0);
887    ///
888    /// assert_relative_eq!(
889    ///     dq.inverse_transform_vector(&vector), Vector3::new(1.0, 3.0, -2.0), epsilon = 1.0e-6
890    /// );
891    /// ```
892    #[inline]
893    #[must_use]
894    pub fn inverse_transform_vector(&self, v: &Vector3<T>) -> Vector3<T> {
895        self.inverse() * v
896    }
897
898    /// Rotate a unit vector by the inverse of this unit quaternion, ignoring
899    /// the translational component. This may be
900    /// cheaper than inverting the unit dual quaternion and transforming the
901    /// vector.
902    ///
903    /// # Example
904    /// ```
905    /// # #[macro_use] extern crate approx;
906    /// # use nalgebra::{UnitDualQuaternion, UnitQuaternion, Unit, Vector3};
907    /// let dq = UnitDualQuaternion::from_parts(
908    ///     Vector3::new(0.0, 3.0, 0.0).into(),
909    ///     UnitQuaternion::from_euler_angles(std::f32::consts::FRAC_PI_2, 0.0, 0.0)
910    /// );
911    /// let vector = Unit::new_unchecked(Vector3::new(0.0, 1.0, 0.0));
912    ///
913    /// assert_relative_eq!(
914    ///     dq.inverse_transform_unit_vector(&vector),
915    ///     Unit::new_unchecked(Vector3::new(0.0, 0.0, -1.0)),
916    ///     epsilon = 1.0e-6
917    /// );
918    /// ```
919    #[inline]
920    #[must_use]
921    pub fn inverse_transform_unit_vector(&self, v: &Unit<Vector3<T>>) -> Unit<Vector3<T>> {
922        self.inverse() * v
923    }
924}
925
926impl<T: SimdRealField + RealField> UnitDualQuaternion<T>
927where
928    T::Element: SimdRealField,
929{
930    /// Converts this unit dual quaternion interpreted as an isometry
931    /// into its equivalent homogeneous transformation matrix.
932    ///
933    /// # Example
934    /// ```
935    /// # #[macro_use] extern crate approx;
936    /// # use nalgebra::{Matrix4, UnitDualQuaternion, UnitQuaternion, Vector3};
937    /// let dq = UnitDualQuaternion::from_parts(
938    ///     Vector3::new(1.0, 3.0, 2.0).into(),
939    ///     UnitQuaternion::from_axis_angle(&Vector3::z_axis(), std::f32::consts::FRAC_PI_6)
940    /// );
941    /// let expected = Matrix4::new(0.8660254, -0.5,      0.0, 1.0,
942    ///                             0.5,       0.8660254, 0.0, 3.0,
943    ///                             0.0,       0.0,       1.0, 2.0,
944    ///                             0.0,       0.0,       0.0, 1.0);
945    ///
946    /// assert_relative_eq!(dq.to_homogeneous(), expected, epsilon = 1.0e-6);
947    /// ```
948    #[inline]
949    #[must_use]
950    pub fn to_homogeneous(self) -> Matrix4<T> {
951        self.to_isometry().to_homogeneous()
952    }
953}
954
955impl<T: RealField> Default for UnitDualQuaternion<T> {
956    fn default() -> Self {
957        Self::identity()
958    }
959}
960
961impl<T: RealField + fmt::Display> fmt::Display for UnitDualQuaternion<T> {
962    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
963        if let Some(axis) = self.rotation().axis() {
964            let axis = axis.into_inner();
965            write!(
966                f,
967                "UnitDualQuaternion translation: {} − angle: {} − axis: ({}, {}, {})",
968                self.translation().vector,
969                self.rotation().angle(),
970                axis[0],
971                axis[1],
972                axis[2]
973            )
974        } else {
975            write!(
976                f,
977                "UnitDualQuaternion translation: {} − angle: {} − axis: (undefined)",
978                self.translation().vector,
979                self.rotation().angle()
980            )
981        }
982    }
983}
984
985impl<T: RealField + AbsDiffEq<Epsilon = T>> AbsDiffEq for UnitDualQuaternion<T> {
986    type Epsilon = T;
987
988    #[inline]
989    fn default_epsilon() -> Self::Epsilon {
990        T::default_epsilon()
991    }
992
993    #[inline]
994    fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
995        self.as_ref().abs_diff_eq(other.as_ref(), epsilon)
996    }
997}
998
999impl<T: RealField + RelativeEq<Epsilon = T>> RelativeEq for UnitDualQuaternion<T> {
1000    #[inline]
1001    fn default_max_relative() -> Self::Epsilon {
1002        T::default_max_relative()
1003    }
1004
1005    #[inline]
1006    fn relative_eq(
1007        &self,
1008        other: &Self,
1009        epsilon: Self::Epsilon,
1010        max_relative: Self::Epsilon,
1011    ) -> bool {
1012        self.as_ref()
1013            .relative_eq(other.as_ref(), epsilon, max_relative)
1014    }
1015}
1016
1017impl<T: RealField + UlpsEq<Epsilon = T>> UlpsEq for UnitDualQuaternion<T> {
1018    #[inline]
1019    fn default_max_ulps() -> u32 {
1020        T::default_max_ulps()
1021    }
1022
1023    #[inline]
1024    fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
1025        self.as_ref().ulps_eq(other.as_ref(), epsilon, max_ulps)
1026    }
1027}