Skip to main content

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