nalgebra/geometry/
dual_quaternion_construction.rs

1use crate::{
2    DualQuaternion, Isometry3, Quaternion, Scalar, SimdRealField, Translation3, UnitDualQuaternion,
3    UnitQuaternion,
4};
5use num::{One, Zero};
6#[cfg(feature = "arbitrary")]
7use quickcheck::{Arbitrary, Gen};
8use simba::scalar::SupersetOf;
9
10impl<T: Scalar> DualQuaternion<T> {
11    /// Creates a dual quaternion from its rotation and translation components.
12    ///
13    /// # Example
14    /// ```
15    /// # use nalgebra::{DualQuaternion, Quaternion};
16    /// let rot = Quaternion::new(1.0, 2.0, 3.0, 4.0);
17    /// let trans = Quaternion::new(5.0, 6.0, 7.0, 8.0);
18    ///
19    /// let dq = DualQuaternion::from_real_and_dual(rot, trans);
20    /// assert_eq!(dq.real.w, 1.0);
21    /// ```
22    #[inline]
23    pub fn from_real_and_dual(real: Quaternion<T>, dual: Quaternion<T>) -> Self {
24        Self { real, dual }
25    }
26
27    /// The dual quaternion multiplicative identity.
28    ///
29    /// # Example
30    /// ```
31    /// # use nalgebra::{DualQuaternion, Quaternion};
32    ///
33    /// let dq1 = DualQuaternion::identity();
34    /// let dq2 = DualQuaternion::from_real_and_dual(
35    ///     Quaternion::new(1.,2.,3.,4.),
36    ///     Quaternion::new(5.,6.,7.,8.)
37    /// );
38    ///
39    /// assert_eq!(dq1 * dq2, dq2);
40    /// assert_eq!(dq2 * dq1, dq2);
41    /// ```
42    #[inline]
43    pub fn identity() -> Self
44    where
45        T: SimdRealField,
46    {
47        Self::from_real_and_dual(
48            Quaternion::from_real(T::one()),
49            Quaternion::from_real(T::zero()),
50        )
51    }
52
53    /// Cast the components of `self` to another type.
54    ///
55    /// # Example
56    /// ```
57    /// # use nalgebra::{Quaternion, DualQuaternion};
58    /// let q = DualQuaternion::from_real(Quaternion::new(1.0f64, 2.0, 3.0, 4.0));
59    /// let q2 = q.cast::<f32>();
60    /// assert_eq!(q2, DualQuaternion::from_real(Quaternion::new(1.0f32, 2.0, 3.0, 4.0)));
61    /// ```
62    pub fn cast<To: Scalar>(self) -> DualQuaternion<To>
63    where
64        DualQuaternion<To>: SupersetOf<Self>,
65    {
66        crate::convert(self)
67    }
68}
69
70impl<T: SimdRealField> DualQuaternion<T>
71where
72    T::Element: SimdRealField,
73{
74    /// Creates a dual quaternion from only its real part, with no translation
75    /// component.
76    ///
77    /// # Example
78    /// ```
79    /// # use nalgebra::{DualQuaternion, Quaternion};
80    /// let rot = Quaternion::new(1.0, 2.0, 3.0, 4.0);
81    ///
82    /// let dq = DualQuaternion::from_real(rot);
83    /// assert_eq!(dq.real.w, 1.0);
84    /// assert_eq!(dq.dual.w, 0.0);
85    /// ```
86    #[inline]
87    pub fn from_real(real: Quaternion<T>) -> Self {
88        Self {
89            real,
90            dual: Quaternion::zero(),
91        }
92    }
93}
94
95impl<T: SimdRealField> One for DualQuaternion<T>
96where
97    T::Element: SimdRealField,
98{
99    #[inline]
100    fn one() -> Self {
101        Self::identity()
102    }
103}
104
105impl<T: SimdRealField> Zero for DualQuaternion<T>
106where
107    T::Element: SimdRealField,
108{
109    #[inline]
110    fn zero() -> Self {
111        DualQuaternion::from_real_and_dual(Quaternion::zero(), Quaternion::zero())
112    }
113
114    #[inline]
115    fn is_zero(&self) -> bool {
116        self.real.is_zero() && self.dual.is_zero()
117    }
118}
119
120#[cfg(feature = "arbitrary")]
121impl<T> Arbitrary for DualQuaternion<T>
122where
123    T: SimdRealField + Arbitrary + Send,
124    T::Element: SimdRealField,
125{
126    #[inline]
127    fn arbitrary(rng: &mut Gen) -> Self {
128        Self::from_real_and_dual(Arbitrary::arbitrary(rng), Arbitrary::arbitrary(rng))
129    }
130}
131
132impl<T: SimdRealField> UnitDualQuaternion<T> {
133    /// The unit dual quaternion multiplicative identity, which also represents
134    /// the identity transformation as an isometry.
135    ///
136    /// # Example
137    /// ```
138    /// # use nalgebra::{UnitDualQuaternion, UnitQuaternion, Vector3, Point3};
139    /// let ident = UnitDualQuaternion::identity();
140    /// let point = Point3::new(1.0, -4.3, 3.33);
141    ///
142    /// assert_eq!(ident * point, point);
143    /// assert_eq!(ident, ident.inverse());
144    /// ```
145    #[inline]
146    pub fn identity() -> Self {
147        Self::new_unchecked(DualQuaternion::identity())
148    }
149
150    /// Cast the components of `self` to another type.
151    ///
152    /// # Example
153    /// ```
154    /// # use nalgebra::UnitDualQuaternion;
155    /// let q = UnitDualQuaternion::<f64>::identity();
156    /// let q2 = q.cast::<f32>();
157    /// assert_eq!(q2, UnitDualQuaternion::<f32>::identity());
158    /// ```
159    pub fn cast<To: Scalar>(self) -> UnitDualQuaternion<To>
160    where
161        UnitDualQuaternion<To>: SupersetOf<Self>,
162    {
163        crate::convert(self)
164    }
165}
166
167impl<T: SimdRealField> UnitDualQuaternion<T>
168where
169    T::Element: SimdRealField,
170{
171    /// Return a dual quaternion representing the translation and orientation
172    /// given by the provided rotation quaternion and translation vector.
173    ///
174    /// # Example
175    /// ```
176    /// # #[macro_use] extern crate approx;
177    /// # use nalgebra::{UnitDualQuaternion, UnitQuaternion, Vector3, Point3};
178    /// let dq = UnitDualQuaternion::from_parts(
179    ///     Vector3::new(0.0, 3.0, 0.0).into(),
180    ///     UnitQuaternion::from_euler_angles(std::f32::consts::FRAC_PI_2, 0.0, 0.0)
181    /// );
182    /// let point = Point3::new(1.0, 2.0, 3.0);
183    ///
184    /// assert_relative_eq!(dq * point, Point3::new(1.0, 0.0, 2.0), epsilon = 1.0e-6);
185    /// ```
186    #[inline]
187    pub fn from_parts(translation: Translation3<T>, rotation: UnitQuaternion<T>) -> Self {
188        let half: T = crate::convert(0.5f64);
189        UnitDualQuaternion::new_unchecked(DualQuaternion {
190            real: rotation.clone().into_inner(),
191            dual: Quaternion::from_parts(T::zero(), translation.vector)
192                * rotation.into_inner()
193                * half,
194        })
195    }
196
197    /// Return a unit dual quaternion representing the translation and orientation
198    /// given by the provided isometry.
199    ///
200    /// # Example
201    /// ```
202    /// # #[macro_use] extern crate approx;
203    /// # use nalgebra::{Isometry3, UnitDualQuaternion, UnitQuaternion, Vector3, Point3};
204    /// let iso = Isometry3::from_parts(
205    ///     Vector3::new(0.0, 3.0, 0.0).into(),
206    ///     UnitQuaternion::from_euler_angles(std::f32::consts::FRAC_PI_2, 0.0, 0.0)
207    /// );
208    /// let dq = UnitDualQuaternion::from_isometry(&iso);
209    /// let point = Point3::new(1.0, 2.0, 3.0);
210    ///
211    /// assert_relative_eq!(dq * point, iso * point, epsilon = 1.0e-6);
212    /// ```
213    #[inline]
214    pub fn from_isometry(isometry: &Isometry3<T>) -> Self {
215        // TODO: take the isometry by-move instead of cloning it.
216        let isometry = isometry.clone();
217        UnitDualQuaternion::from_parts(isometry.translation, isometry.rotation)
218    }
219
220    /// Creates a dual quaternion from a unit quaternion rotation.
221    ///
222    /// # Example
223    /// ```
224    /// # #[macro_use] extern crate approx;
225    /// # use nalgebra::{UnitQuaternion, UnitDualQuaternion, Quaternion};
226    /// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
227    /// let rot = UnitQuaternion::new_normalize(q);
228    ///
229    /// let dq = UnitDualQuaternion::from_rotation(rot);
230    /// assert_relative_eq!(dq.as_ref().real.norm(), 1.0, epsilon = 1.0e-6);
231    /// assert_eq!(dq.as_ref().dual.norm(), 0.0);
232    /// ```
233    #[inline]
234    pub fn from_rotation(rotation: UnitQuaternion<T>) -> Self {
235        Self::new_unchecked(DualQuaternion::from_real(rotation.into_inner()))
236    }
237}
238
239impl<T: SimdRealField> One for UnitDualQuaternion<T>
240where
241    T::Element: SimdRealField,
242{
243    #[inline]
244    fn one() -> Self {
245        Self::identity()
246    }
247}
248
249#[cfg(feature = "arbitrary")]
250impl<T> Arbitrary for UnitDualQuaternion<T>
251where
252    T: SimdRealField + Arbitrary + Send,
253    T::Element: SimdRealField,
254{
255    #[inline]
256    fn arbitrary(rng: &mut Gen) -> Self {
257        Self::new_normalize(Arbitrary::arbitrary(rng))
258    }
259}