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}