glam/f64/
daffine3.rs

1// Generated from affine.rs.tera template. Edit the template, not the generated file.
2
3use crate::{DMat3, DMat4, DQuat, DVec3};
4use core::ops::{Deref, DerefMut, Mul, MulAssign};
5
6/// A 3D affine transform, which can represent translation, rotation, scaling and shear.
7#[derive(Copy, Clone)]
8#[repr(C)]
9pub struct DAffine3 {
10    pub matrix3: DMat3,
11    pub translation: DVec3,
12}
13
14impl DAffine3 {
15    /// The degenerate zero transform.
16    ///
17    /// This transforms any finite vector and point to zero.
18    /// The zero transform is non-invertible.
19    pub const ZERO: Self = Self {
20        matrix3: DMat3::ZERO,
21        translation: DVec3::ZERO,
22    };
23
24    /// The identity transform.
25    ///
26    /// Multiplying a vector with this returns the same vector.
27    pub const IDENTITY: Self = Self {
28        matrix3: DMat3::IDENTITY,
29        translation: DVec3::ZERO,
30    };
31
32    /// All NAN:s.
33    pub const NAN: Self = Self {
34        matrix3: DMat3::NAN,
35        translation: DVec3::NAN,
36    };
37
38    /// Creates an affine transform from three column vectors.
39    #[inline(always)]
40    #[must_use]
41    pub const fn from_cols(x_axis: DVec3, y_axis: DVec3, z_axis: DVec3, w_axis: DVec3) -> Self {
42        Self {
43            matrix3: DMat3::from_cols(x_axis, y_axis, z_axis),
44            translation: w_axis,
45        }
46    }
47
48    /// Creates an affine transform from a `[f64; 12]` array stored in column major order.
49    #[inline]
50    #[must_use]
51    pub fn from_cols_array(m: &[f64; 12]) -> Self {
52        Self {
53            matrix3: DMat3::from_cols_slice(&m[0..9]),
54            translation: DVec3::from_slice(&m[9..12]),
55        }
56    }
57
58    /// Creates a `[f64; 12]` array storing data in column major order.
59    #[inline]
60    #[must_use]
61    pub fn to_cols_array(&self) -> [f64; 12] {
62        let x = &self.matrix3.x_axis;
63        let y = &self.matrix3.y_axis;
64        let z = &self.matrix3.z_axis;
65        let w = &self.translation;
66        [x.x, x.y, x.z, y.x, y.y, y.z, z.x, z.y, z.z, w.x, w.y, w.z]
67    }
68
69    /// Creates an affine transform from a `[[f64; 3]; 4]`
70    /// 3D array stored in column major order.
71    /// If your data is in row major order you will need to `transpose` the returned
72    /// matrix.
73    #[inline]
74    #[must_use]
75    pub fn from_cols_array_2d(m: &[[f64; 3]; 4]) -> Self {
76        Self {
77            matrix3: DMat3::from_cols(m[0].into(), m[1].into(), m[2].into()),
78            translation: m[3].into(),
79        }
80    }
81
82    /// Creates a `[[f64; 3]; 4]` 3D array storing data in
83    /// column major order.
84    /// If you require data in row major order `transpose` the matrix first.
85    #[inline]
86    #[must_use]
87    pub fn to_cols_array_2d(&self) -> [[f64; 3]; 4] {
88        [
89            self.matrix3.x_axis.into(),
90            self.matrix3.y_axis.into(),
91            self.matrix3.z_axis.into(),
92            self.translation.into(),
93        ]
94    }
95
96    /// Creates an affine transform from the first 12 values in `slice`.
97    ///
98    /// # Panics
99    ///
100    /// Panics if `slice` is less than 12 elements long.
101    #[inline]
102    #[must_use]
103    pub fn from_cols_slice(slice: &[f64]) -> Self {
104        Self {
105            matrix3: DMat3::from_cols_slice(&slice[0..9]),
106            translation: DVec3::from_slice(&slice[9..12]),
107        }
108    }
109
110    /// Writes the columns of `self` to the first 12 elements in `slice`.
111    ///
112    /// # Panics
113    ///
114    /// Panics if `slice` is less than 12 elements long.
115    #[inline]
116    pub fn write_cols_to_slice(self, slice: &mut [f64]) {
117        self.matrix3.write_cols_to_slice(&mut slice[0..9]);
118        self.translation.write_to_slice(&mut slice[9..12]);
119    }
120
121    /// Creates an affine transform that changes scale.
122    /// Note that if any scale is zero the transform will be non-invertible.
123    #[inline]
124    #[must_use]
125    pub fn from_scale(scale: DVec3) -> Self {
126        Self {
127            matrix3: DMat3::from_diagonal(scale),
128            translation: DVec3::ZERO,
129        }
130    }
131    /// Creates an affine transform from the given `rotation` quaternion.
132    #[inline]
133    #[must_use]
134    pub fn from_quat(rotation: DQuat) -> Self {
135        Self {
136            matrix3: DMat3::from_quat(rotation),
137            translation: DVec3::ZERO,
138        }
139    }
140
141    /// Creates an affine transform containing a 3D rotation around a normalized
142    /// rotation `axis` of `angle` (in radians).
143    #[inline]
144    #[must_use]
145    pub fn from_axis_angle(axis: DVec3, angle: f64) -> Self {
146        Self {
147            matrix3: DMat3::from_axis_angle(axis, angle),
148            translation: DVec3::ZERO,
149        }
150    }
151
152    /// Creates an affine transform containing a 3D rotation around the x axis of
153    /// `angle` (in radians).
154    #[inline]
155    #[must_use]
156    pub fn from_rotation_x(angle: f64) -> Self {
157        Self {
158            matrix3: DMat3::from_rotation_x(angle),
159            translation: DVec3::ZERO,
160        }
161    }
162
163    /// Creates an affine transform containing a 3D rotation around the y axis of
164    /// `angle` (in radians).
165    #[inline]
166    #[must_use]
167    pub fn from_rotation_y(angle: f64) -> Self {
168        Self {
169            matrix3: DMat3::from_rotation_y(angle),
170            translation: DVec3::ZERO,
171        }
172    }
173
174    /// Creates an affine transform containing a 3D rotation around the z axis of
175    /// `angle` (in radians).
176    #[inline]
177    #[must_use]
178    pub fn from_rotation_z(angle: f64) -> Self {
179        Self {
180            matrix3: DMat3::from_rotation_z(angle),
181            translation: DVec3::ZERO,
182        }
183    }
184
185    /// Creates an affine transformation from the given 3D `translation`.
186    #[inline]
187    #[must_use]
188    pub fn from_translation(translation: DVec3) -> Self {
189        #[allow(clippy::useless_conversion)]
190        Self {
191            matrix3: DMat3::IDENTITY,
192            translation: translation.into(),
193        }
194    }
195
196    /// Creates an affine transform from a 3x3 matrix (expressing scale, shear and
197    /// rotation)
198    #[inline]
199    #[must_use]
200    pub fn from_mat3(mat3: DMat3) -> Self {
201        #[allow(clippy::useless_conversion)]
202        Self {
203            matrix3: mat3.into(),
204            translation: DVec3::ZERO,
205        }
206    }
207
208    /// Creates an affine transform from a 3x3 matrix (expressing scale, shear and rotation)
209    /// and a translation vector.
210    ///
211    /// Equivalent to `DAffine3::from_translation(translation) * DAffine3::from_mat3(mat3)`
212    #[inline]
213    #[must_use]
214    pub fn from_mat3_translation(mat3: DMat3, translation: DVec3) -> Self {
215        #[allow(clippy::useless_conversion)]
216        Self {
217            matrix3: mat3.into(),
218            translation: translation.into(),
219        }
220    }
221
222    /// Creates an affine transform from the given 3D `scale`, `rotation` and
223    /// `translation`.
224    ///
225    /// Equivalent to `DAffine3::from_translation(translation) *
226    /// DAffine3::from_quat(rotation) * DAffine3::from_scale(scale)`
227    #[inline]
228    #[must_use]
229    pub fn from_scale_rotation_translation(
230        scale: DVec3,
231        rotation: DQuat,
232        translation: DVec3,
233    ) -> Self {
234        let rotation = DMat3::from_quat(rotation);
235        #[allow(clippy::useless_conversion)]
236        Self {
237            matrix3: DMat3::from_cols(
238                rotation.x_axis * scale.x,
239                rotation.y_axis * scale.y,
240                rotation.z_axis * scale.z,
241            ),
242            translation: translation.into(),
243        }
244    }
245
246    /// Creates an affine transform from the given 3D `rotation` and `translation`.
247    ///
248    /// Equivalent to `DAffine3::from_translation(translation) * DAffine3::from_quat(rotation)`
249    #[inline]
250    #[must_use]
251    pub fn from_rotation_translation(rotation: DQuat, translation: DVec3) -> Self {
252        #[allow(clippy::useless_conversion)]
253        Self {
254            matrix3: DMat3::from_quat(rotation),
255            translation: translation.into(),
256        }
257    }
258
259    /// The given `DMat4` must be an affine transform,
260    /// i.e. contain no perspective transform.
261    #[inline]
262    #[must_use]
263    pub fn from_mat4(m: DMat4) -> Self {
264        Self {
265            matrix3: DMat3::from_cols(
266                DVec3::from_vec4(m.x_axis),
267                DVec3::from_vec4(m.y_axis),
268                DVec3::from_vec4(m.z_axis),
269            ),
270            translation: DVec3::from_vec4(m.w_axis),
271        }
272    }
273
274    /// Extracts `scale`, `rotation` and `translation` from `self`.
275    ///
276    /// The transform is expected to be non-degenerate and without shearing, or the output
277    /// will be invalid.
278    ///
279    /// # Panics
280    ///
281    /// Will panic if the determinant `self.matrix3` is zero or if the resulting scale
282    /// vector contains any zero elements when `glam_assert` is enabled.
283    #[inline]
284    #[must_use]
285    pub fn to_scale_rotation_translation(&self) -> (DVec3, DQuat, DVec3) {
286        use crate::f64::math;
287        let det = self.matrix3.determinant();
288        glam_assert!(det != 0.0);
289
290        let scale = DVec3::new(
291            self.matrix3.x_axis.length() * math::signum(det),
292            self.matrix3.y_axis.length(),
293            self.matrix3.z_axis.length(),
294        );
295
296        glam_assert!(scale.cmpne(DVec3::ZERO).all());
297
298        let inv_scale = scale.recip();
299
300        #[allow(clippy::useless_conversion)]
301        let rotation = DQuat::from_mat3(&DMat3::from_cols(
302            (self.matrix3.x_axis * inv_scale.x).into(),
303            (self.matrix3.y_axis * inv_scale.y).into(),
304            (self.matrix3.z_axis * inv_scale.z).into(),
305        ));
306
307        #[allow(clippy::useless_conversion)]
308        (scale, rotation, self.translation.into())
309    }
310
311    /// Creates a left-handed view transform using a camera position, an up direction, and a facing
312    /// direction.
313    ///
314    /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=forward`.
315    #[inline]
316    #[must_use]
317    pub fn look_to_lh(eye: DVec3, dir: DVec3, up: DVec3) -> Self {
318        Self::look_to_rh(eye, -dir, up)
319    }
320
321    /// Creates a right-handed view transform using a camera position, an up direction, and a facing
322    /// direction.
323    ///
324    /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=back`.
325    #[inline]
326    #[must_use]
327    pub fn look_to_rh(eye: DVec3, dir: DVec3, up: DVec3) -> Self {
328        let f = dir.normalize();
329        let s = f.cross(up).normalize();
330        let u = s.cross(f);
331
332        Self {
333            matrix3: DMat3::from_cols(
334                DVec3::new(s.x, u.x, -f.x),
335                DVec3::new(s.y, u.y, -f.y),
336                DVec3::new(s.z, u.z, -f.z),
337            ),
338            translation: DVec3::new(-eye.dot(s), -eye.dot(u), eye.dot(f)),
339        }
340    }
341
342    /// Creates a left-handed view transform using a camera position, an up direction, and a focal
343    /// point.
344    /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=forward`.
345    ///
346    /// # Panics
347    ///
348    /// Will panic if `up` is not normalized when `glam_assert` is enabled.
349    #[inline]
350    #[must_use]
351    pub fn look_at_lh(eye: DVec3, center: DVec3, up: DVec3) -> Self {
352        glam_assert!(up.is_normalized());
353        Self::look_to_lh(eye, center - eye, up)
354    }
355
356    /// Creates a right-handed view transform using a camera position, an up direction, and a focal
357    /// point.
358    /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=back`.
359    ///
360    /// # Panics
361    ///
362    /// Will panic if `up` is not normalized when `glam_assert` is enabled.
363    #[inline]
364    #[must_use]
365    pub fn look_at_rh(eye: DVec3, center: DVec3, up: DVec3) -> Self {
366        glam_assert!(up.is_normalized());
367        Self::look_to_rh(eye, center - eye, up)
368    }
369
370    /// Transforms the given 3D points, applying shear, scale, rotation and translation.
371    #[inline]
372    pub fn transform_point3(&self, rhs: DVec3) -> DVec3 {
373        #[allow(clippy::useless_conversion)]
374        ((self.matrix3.x_axis * rhs.x)
375            + (self.matrix3.y_axis * rhs.y)
376            + (self.matrix3.z_axis * rhs.z)
377            + self.translation)
378            .into()
379    }
380
381    /// Transforms the given 3D vector, applying shear, scale and rotation (but NOT
382    /// translation).
383    ///
384    /// To also apply translation, use [`Self::transform_point3()`] instead.
385    #[inline]
386    #[must_use]
387    pub fn transform_vector3(&self, rhs: DVec3) -> DVec3 {
388        #[allow(clippy::useless_conversion)]
389        ((self.matrix3.x_axis * rhs.x)
390            + (self.matrix3.y_axis * rhs.y)
391            + (self.matrix3.z_axis * rhs.z))
392            .into()
393    }
394
395    /// Returns `true` if, and only if, all elements are finite.
396    ///
397    /// If any element is either `NaN`, positive or negative infinity, this will return
398    /// `false`.
399    #[inline]
400    #[must_use]
401    pub fn is_finite(&self) -> bool {
402        self.matrix3.is_finite() && self.translation.is_finite()
403    }
404
405    /// Returns `true` if any elements are `NaN`.
406    #[inline]
407    #[must_use]
408    pub fn is_nan(&self) -> bool {
409        self.matrix3.is_nan() || self.translation.is_nan()
410    }
411
412    /// Returns true if the absolute difference of all elements between `self` and `rhs`
413    /// is less than or equal to `max_abs_diff`.
414    ///
415    /// This can be used to compare if two 3x4 matrices contain similar elements. It works
416    /// best when comparing with a known value. The `max_abs_diff` that should be used used
417    /// depends on the values being compared against.
418    ///
419    /// For more see
420    /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/).
421    #[inline]
422    #[must_use]
423    pub fn abs_diff_eq(&self, rhs: Self, max_abs_diff: f64) -> bool {
424        self.matrix3.abs_diff_eq(rhs.matrix3, max_abs_diff)
425            && self.translation.abs_diff_eq(rhs.translation, max_abs_diff)
426    }
427
428    /// Return the inverse of this transform.
429    ///
430    /// Note that if the transform is not invertible the result will be invalid.
431    #[inline]
432    #[must_use]
433    pub fn inverse(&self) -> Self {
434        let matrix3 = self.matrix3.inverse();
435        // transform negative translation by the matrix inverse:
436        let translation = -(matrix3 * self.translation);
437
438        Self {
439            matrix3,
440            translation,
441        }
442    }
443}
444
445impl Default for DAffine3 {
446    #[inline(always)]
447    fn default() -> Self {
448        Self::IDENTITY
449    }
450}
451
452impl Deref for DAffine3 {
453    type Target = crate::deref::Cols4<DVec3>;
454    #[inline(always)]
455    fn deref(&self) -> &Self::Target {
456        unsafe { &*(self as *const Self as *const Self::Target) }
457    }
458}
459
460impl DerefMut for DAffine3 {
461    #[inline(always)]
462    fn deref_mut(&mut self) -> &mut Self::Target {
463        unsafe { &mut *(self as *mut Self as *mut Self::Target) }
464    }
465}
466
467impl PartialEq for DAffine3 {
468    #[inline]
469    fn eq(&self, rhs: &Self) -> bool {
470        self.matrix3.eq(&rhs.matrix3) && self.translation.eq(&rhs.translation)
471    }
472}
473
474#[cfg(not(target_arch = "spirv"))]
475impl core::fmt::Debug for DAffine3 {
476    fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
477        fmt.debug_struct(stringify!(DAffine3))
478            .field("matrix3", &self.matrix3)
479            .field("translation", &self.translation)
480            .finish()
481    }
482}
483
484#[cfg(not(target_arch = "spirv"))]
485impl core::fmt::Display for DAffine3 {
486    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
487        write!(
488            f,
489            "[{}, {}, {}, {}]",
490            self.matrix3.x_axis, self.matrix3.y_axis, self.matrix3.z_axis, self.translation
491        )
492    }
493}
494
495impl<'a> core::iter::Product<&'a Self> for DAffine3 {
496    fn product<I>(iter: I) -> Self
497    where
498        I: Iterator<Item = &'a Self>,
499    {
500        iter.fold(Self::IDENTITY, |a, &b| a * b)
501    }
502}
503
504impl Mul for DAffine3 {
505    type Output = DAffine3;
506
507    #[inline]
508    fn mul(self, rhs: DAffine3) -> Self::Output {
509        Self {
510            matrix3: self.matrix3 * rhs.matrix3,
511            translation: self.matrix3 * rhs.translation + self.translation,
512        }
513    }
514}
515
516impl MulAssign for DAffine3 {
517    #[inline]
518    fn mul_assign(&mut self, rhs: DAffine3) {
519        *self = self.mul(rhs);
520    }
521}
522
523impl From<DAffine3> for DMat4 {
524    #[inline]
525    fn from(m: DAffine3) -> DMat4 {
526        DMat4::from_cols(
527            m.matrix3.x_axis.extend(0.0),
528            m.matrix3.y_axis.extend(0.0),
529            m.matrix3.z_axis.extend(0.0),
530            m.translation.extend(1.0),
531        )
532    }
533}
534
535impl Mul<DMat4> for DAffine3 {
536    type Output = DMat4;
537
538    #[inline]
539    fn mul(self, rhs: DMat4) -> Self::Output {
540        DMat4::from(self) * rhs
541    }
542}
543
544impl Mul<DAffine3> for DMat4 {
545    type Output = DMat4;
546
547    #[inline]
548    fn mul(self, rhs: DAffine3) -> Self::Output {
549        self * DMat4::from(rhs)
550    }
551}