ultraviolet/
transform.rs

1//! Dedicated transformation types as the combination of primitives.
2//!
3//! Note that you may want to us these types over the corresponding type of
4//! homogeneous transformation matrix because they are faster in most operations,
5//! especially composition and inverse.
6use crate::*;
7
8use std::ops::*;
9
10macro_rules! isometries {
11    ($($ison:ident => ($mt:ident, $rt:ident, $vt:ident, $t:ident)),+) => {
12        $(
13        /// An Isometry, aka a "rigid body transformation".
14        ///
15        /// Defined as the combination of a rotation *and then* a translation.
16        ///
17        /// You may want to us this type over the corresponding type of
18        /// homogeneous transformation matrix because it will be faster in most operations,
19        /// especially composition and inverse.
20        #[derive(Clone, Copy, Debug, PartialEq)]
21        #[repr(C)]
22        pub struct $ison {
23            pub translation: $vt,
24            pub rotation: $rt,
25        }
26
27        derive_default_identity!($ison);
28
29        impl $ison {
30            #[inline]
31            pub const fn new(translation: $vt, rotation: $rt) -> Self {
32                Self { translation, rotation }
33            }
34
35            #[inline]
36            pub fn identity() -> Self {
37                Self { rotation: $rt::identity(), translation: $vt::zero() }
38            }
39
40            /// Add a rotation *before* this isometry.
41            ///
42            /// This means the rotation will only affect the rotational
43            /// part of this isometry, not the translational part.
44            #[inline]
45            pub fn prepend_rotation(&mut self, rotor: $rt) {
46                self.rotation = rotor * self.rotation;
47            }
48
49            /// Add a rotation *after* this isometry.
50            ///
51            /// This means the rotation will affect both the rotational and
52            /// translational parts of this isometry, since it is being applied
53            /// 'after' this isometry's translational part.
54            pub fn append_rotation(&mut self, rotor: $rt) {
55                self.rotation = rotor * self.rotation;
56                self.translation = rotor * self.translation;
57            }
58
59            /// Add a translation *before* this isometry.
60            ///
61            /// Doing so will mean that the translation being added will get
62            /// transformed by this isometry's rotational part.
63            #[inline]
64            pub fn prepend_translation(&mut self, translation: $vt) {
65                self.translation += self.rotation * translation;
66            }
67
68            /// Add a translation *after* this isometry.
69            ///
70            /// Doing so will mean that the translation being added will *not*
71            /// transformed by this isometry's rotational part.
72            #[inline]
73            pub fn append_translation(&mut self, translation: $vt) {
74                self.translation += translation;
75            }
76
77            /// Prepend transformation by another isometry.
78            ///
79            /// This means that the transformation being applied will take place
80            /// *before* this isometry, i.e. both its translation and rotation will be
81            /// rotated by this isometry's rotational part.
82            #[inline]
83            pub fn prepend_isometry(&mut self, other: Self) {
84                *self = *self * other;
85            }
86
87            /// Append transformation by another isometry.
88            ///
89            /// This means that the transformation being applied will take place
90            /// *after* this isometry, i.e. *this isometry's* translation and rotation will be
91            /// rotated by the *other* isometry's rotational part.
92            #[inline]
93            pub fn append_isometry(&mut self, other: Self) {
94                *self = other * *self;
95            }
96
97            #[inline]
98            pub fn inverse(&mut self) {
99                self.rotation.reverse();
100                self.translation = self.rotation * (-self.translation);
101            }
102
103            #[inline]
104            pub fn inversed(mut self) -> Self {
105                self.inverse();
106                self
107            }
108
109            #[inline]
110            pub fn transform_vec(&self, mut vec: $vt) -> $vt {
111                vec = self.rotation * vec;
112                vec += self.translation;
113                vec
114            }
115
116            #[inline]
117            pub fn into_homogeneous_matrix(self) -> $mt {
118                $mt::from_translation(self.translation)
119                    * self.rotation.into_matrix().into_homogeneous()
120            }
121        }
122
123        impl Mul<$ison> for $rt {
124            type Output = $ison;
125            #[inline]
126            fn mul(self, mut iso: $ison) -> $ison {
127                iso.append_rotation(self);
128                iso
129            }
130        }
131
132        impl Mul<$rt> for $ison {
133            type Output = $ison;
134            #[inline]
135            fn mul(mut self, rotor: $rt) -> $ison {
136                self.prepend_rotation(rotor);
137                self
138            }
139        }
140
141        impl Mul<$t> for $ison {
142            type Output = Self;
143            #[inline]
144            fn mul(mut self, scalar: $t) -> $ison {
145                self.translation *= scalar;
146                self.rotation *= scalar;
147                self
148            }
149        }
150
151        impl Mul<$vt> for $ison {
152            type Output = $vt;
153            #[inline]
154            fn mul(self, vec: $vt) -> $vt {
155                self.transform_vec(vec)
156            }
157        }
158
159        impl Mul<$ison> for $ison {
160            type Output = Self;
161            #[inline]
162            fn mul(self, base: $ison) -> $ison {
163                let trans = self.transform_vec(base.translation);
164                let rot = self.rotation * base.rotation;
165                $ison::new(trans, rot)
166            }
167        }
168
169        impl Add<$ison> for $ison {
170            type Output = Self;
171            #[inline]
172            fn add(mut self, other: $ison) -> $ison {
173                self.translation += other.translation;
174                self.rotation += other.rotation;
175                self
176            }
177        }
178        )+
179    }
180}
181
182isometries!(
183    Isometry2 => (Mat3, Rotor2, Vec2, f32),
184    Isometry2x4 => (Mat3x4, Rotor2x4, Vec2x4, f32x4),
185    Isometry2x8 => (Mat3x8, Rotor2x8, Vec2x8, f32x8),
186
187    Isometry3 => (Mat4, Rotor3, Vec3, f32),
188    Isometry3x4 => (Mat4x4, Rotor3x4, Vec3x4, f32x4),
189    Isometry3x8 => (Mat4x8, Rotor3x8, Vec3x8, f32x8)
190);
191
192#[cfg(feature = "f64")]
193isometries!(
194    DIsometry2 => (DMat3, DRotor2, DVec2, f64),
195    DIsometry2x2 => (DMat3x2, DRotor2x2, DVec2x2, f64x2),
196    DIsometry2x4 => (DMat3x4, DRotor2x4, DVec2x4, f64x4),
197
198    DIsometry3 => (DMat4, DRotor3, DVec3, f64),
199    DIsometry3x2 => (DMat4x2, DRotor3x2, DVec3x2, f64x2),
200    DIsometry3x4 => (DMat4x4, DRotor3x4, DVec3x4, f64x4)
201);
202
203macro_rules! similarities {
204    ($($sn:ident => ($mt:ident, $rt:ident, $vt:ident, $t:ident)),+) => {
205        $(
206        /// A Similarity, i.e. an Isometry but with an added uniform scaling.
207        ///
208        /// Defined as a uniform scaling followed by a rotation followed by a translation.
209        ///
210        /// You may want to us this type over the corresponding type of
211        /// homogeneous transformation matrix because it will be faster in most operations,
212        /// especially composition and inverse.
213        #[derive(Clone, Copy, Debug, PartialEq)]
214        #[repr(C)]
215        pub struct $sn {
216            pub translation: $vt,
217            pub rotation: $rt,
218            pub scale: $t,
219        }
220
221        derive_default_identity!($sn);
222
223        impl $sn {
224            #[inline]
225            pub const fn new(translation: $vt, rotation: $rt, scale: $t) -> Self {
226                Self { translation, rotation, scale }
227            }
228
229            #[inline]
230            pub fn identity() -> Self {
231                Self { rotation: $rt::identity(), translation: $vt::zero(), scale: $t::splat(1.0) }
232            }
233
234            /// Add a scaling *before* this similarity.
235            ///
236            /// This means the scaling will only affect the scaling part
237            /// of this similarity, not the translational part.
238            #[inline]
239            pub fn prepend_scaling(&mut self, scaling: $t) {
240                self.scale *= scaling;
241            }
242
243            /// Add a scaling *after* this similarity.
244            ///
245            /// This means the scaling will affect both the scaling
246            /// and translational parts of this similairty, since it is being
247            /// applied *after* this similarity's translational part.
248            #[inline]
249            pub fn append_scaling(&mut self, scaling: $t) {
250                self.scale *= scaling;
251                self.translation *= scaling;
252            }
253
254            /// Add a rotation *before* this similarity.
255            ///
256            /// This means the rotation will only affect the rotational
257            /// part of this similarity, not the translational part.
258            #[inline]
259            pub fn prepend_rotation(&mut self, rotor: $rt) {
260                self.rotation = rotor * self.rotation;
261            }
262
263            /// Add a rotation *after* this similarity.
264            ///
265            /// This means the rotation will affect both the rotational and
266            /// translational parts of this similarity, since it is being applied
267            /// *after* this similarity's translational part.
268            pub fn append_rotation(&mut self, rotor: $rt) {
269                self.rotation = rotor * self.rotation;
270                self.translation = rotor * self.translation;
271            }
272
273            /// Add a translation *before* this similarity.
274            ///
275            /// Doing so will mean that the translation being added will get
276            /// transformed by this similarity's rotational and scaling parts.
277            #[inline]
278            pub fn prepend_translation(&mut self, translation: $vt) {
279                self.translation += self.scale * self.rotation * translation;
280            }
281
282            /// Add a translation *after* this similarity.
283            ///
284            /// Doing so will mean that the translation being added will *not*
285            /// transformed by this similarity's rotational or scaling parts.
286            #[inline]
287            pub fn append_translation(&mut self, translation: $vt) {
288                self.translation += translation;
289            }
290
291            /// Prepend transformation by another similarity.
292            ///
293            /// This means that the transformation being applied will take place
294            /// *before* this similarity, i.e. both its translation and rotation will be
295            /// rotated by the other similarity's rotational part, and its translation
296            /// will be scaled by the other similarity's scaling part.
297            #[inline]
298            pub fn prepend_similarity(&mut self, other: Self) {
299                *self = *self * other;
300            }
301
302            /// Append transformation by another similarity.
303            ///
304            /// This means that the transformation being applied will take place
305            /// *after* this similarity, i.e. *this similarity's* translation and rotation will be
306            /// rotated by the *other* similarity's rotational part, and *this similarity's* translation
307            /// will be scaled by the *other* similarity's scaling pat.
308            #[inline]
309            pub fn append_similarity(&mut self, other: Self) {
310                *self = other * *self;
311            }
312
313            #[inline]
314            pub fn inverse(&mut self) {
315                self.rotation.reverse();
316                self.scale = $t::splat(1.0) / self.scale;
317                self.translation = self.rotation * (-self.translation) * self.scale;
318            }
319
320            #[inline]
321            pub fn inversed(mut self) -> Self {
322                self.inverse();
323                self
324            }
325
326            #[inline]
327            pub fn transform_vec(&self, mut vec: $vt) -> $vt {
328                vec = self.rotation * vec;
329                vec = self.scale * vec;
330                vec += self.translation;
331                vec
332            }
333
334            #[inline]
335            pub fn into_homogeneous_matrix(self) -> $mt {
336                $mt::from_translation(self.translation)
337                    * self.rotation.into_matrix().into_homogeneous()
338                    * $mt::from_scale(self.scale)
339            }
340        }
341
342        impl Mul<$sn> for $rt {
343            type Output = $sn;
344            #[inline]
345            fn mul(self, mut iso: $sn) -> $sn {
346                iso.append_rotation(self);
347                iso
348            }
349        }
350
351        impl Mul<$rt> for $sn {
352            type Output = $sn;
353            #[inline]
354            fn mul(mut self, rotor: $rt) -> $sn {
355                self.prepend_rotation(rotor);
356                self
357            }
358        }
359
360        impl Mul<$t> for $sn {
361            type Output = Self;
362            #[inline]
363            fn mul(mut self, scalar: $t) -> $sn {
364                self.translation *= scalar;
365                self.rotation *= scalar;
366                self.scale *= scalar;
367                self
368            }
369        }
370
371        impl Mul<$vt> for $sn {
372            type Output = $vt;
373            #[inline]
374            fn mul(self, vec: $vt) -> $vt {
375                self.transform_vec(vec)
376            }
377        }
378
379        impl Mul<$sn> for $sn {
380            type Output = Self;
381            #[inline]
382            fn mul(self, base: $sn) -> $sn {
383                let trans = self.transform_vec(base.translation);
384                let rot = self.rotation * base.rotation;
385                let scale = self.scale * base.scale;
386                $sn::new(trans, rot, scale)
387            }
388        }
389
390        impl Add<$sn> for $sn {
391            type Output = Self;
392            #[inline]
393            fn add(mut self, other: $sn) -> $sn {
394                self.translation += other.translation;
395                self.rotation += other.rotation;
396                self.scale += other.scale;
397                self
398            }
399        }
400        )+
401    }
402}
403
404similarities!(
405    Similarity2 => (Mat3, Rotor2, Vec2, f32),
406    Similarity2x4 => (Mat3x4, Rotor2x4, Vec2x4, f32x4),
407    Similarity2x8 => (Mat3x8, Rotor2x8, Vec2x8, f32x8),
408
409    Similarity3 => (Mat4, Rotor3, Vec3, f32),
410    Similarity3x4 => (Mat4x4, Rotor3x4, Vec3x4, f32x4),
411    Similarity3x8 => (Mat4x8, Rotor3x8, Vec3x8, f32x8)
412);
413
414#[cfg(feature = "f64")]
415similarities!(
416    DSimilarity2 => (DMat3, DRotor2, DVec2, f64),
417    DSimilarity2x2 => (DMat3x2, DRotor2x2, DVec2x2, f64x2),
418    DSimilarity2x4 => (DMat3x4, DRotor2x4, DVec2x4, f64x4),
419
420    DSimilarity3 => (DMat4, DRotor3, DVec3, f64),
421    DSimilarity3x2 => (DMat4x2, DRotor3x2, DVec3x2, f64x2),
422    DSimilarity3x4 => (DMat4x4, DRotor3x4, DVec3x4, f64x4)
423);