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);