revier_glam/f64/
dmat4.rs

1// Generated from mat.rs.tera template. Edit the template, not the generated file.
2
3use crate::{f64::math, swizzles::*, DMat3, DQuat, DVec3, DVec4, EulerRot, Mat4};
4#[cfg(not(target_arch = "spirv"))]
5use core::fmt;
6use core::iter::{Product, Sum};
7use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
8
9/// Creates a 4x4 matrix from four column vectors.
10#[inline(always)]
11pub const fn dmat4(x_axis: DVec4, y_axis: DVec4, z_axis: DVec4, w_axis: DVec4) -> DMat4 {
12    DMat4::from_cols(x_axis, y_axis, z_axis, w_axis)
13}
14
15/// A 4x4 column major matrix.
16///
17/// This 4x4 matrix type features convenience methods for creating and using affine transforms and
18/// perspective projections. If you are primarily dealing with 3D affine transformations
19/// considering using [`DAffine3`](crate::DAffine3) which is faster than a 4x4 matrix
20/// for some affine operations.
21///
22/// Affine transformations including 3D translation, rotation and scale can be created
23/// using methods such as [`Self::from_translation()`], [`Self::from_quat()`],
24/// [`Self::from_scale()`] and [`Self::from_scale_rotation_translation()`].
25///
26/// Orthographic projections can be created using the methods [`Self::orthographic_lh()`] for
27/// left-handed coordinate systems and [`Self::orthographic_rh()`] for right-handed
28/// systems. The resulting matrix is also an affine transformation.
29///
30/// The [`Self::transform_point3()`] and [`Self::transform_vector3()`] convenience methods
31/// are provided for performing affine transformations on 3D vectors and points. These
32/// multiply 3D inputs as 4D vectors with an implicit `w` value of `1` for points and `0`
33/// for vectors respectively. These methods assume that `Self` contains a valid affine
34/// transform.
35///
36/// Perspective projections can be created using methods such as
37/// [`Self::perspective_lh()`], [`Self::perspective_infinite_lh()`] and
38/// [`Self::perspective_infinite_reverse_lh()`] for left-handed co-ordinate systems and
39/// [`Self::perspective_rh()`], [`Self::perspective_infinite_rh()`] and
40/// [`Self::perspective_infinite_reverse_rh()`] for right-handed co-ordinate systems.
41///
42/// The resulting perspective project can be use to transform 3D vectors as points with
43/// perspective correction using the [`Self::project_point3()`] convenience method.
44#[derive(Clone, Copy)]
45#[cfg_attr(feature = "cuda", repr(align(16)))]
46#[repr(C)]
47pub struct DMat4 {
48    pub x_axis: DVec4,
49    pub y_axis: DVec4,
50    pub z_axis: DVec4,
51    pub w_axis: DVec4,
52}
53
54impl DMat4 {
55    /// A 4x4 matrix with all elements set to `0.0`.
56    pub const ZERO: Self = Self::from_cols(DVec4::ZERO, DVec4::ZERO, DVec4::ZERO, DVec4::ZERO);
57
58    /// A 4x4 identity matrix, where all diagonal elements are `1`, and all off-diagonal elements are `0`.
59    pub const IDENTITY: Self = Self::from_cols(DVec4::X, DVec4::Y, DVec4::Z, DVec4::W);
60
61    /// All NAN:s.
62    pub const NAN: Self = Self::from_cols(DVec4::NAN, DVec4::NAN, DVec4::NAN, DVec4::NAN);
63
64    #[allow(clippy::too_many_arguments)]
65    #[inline(always)]
66    const fn new(
67        m00: f64,
68        m01: f64,
69        m02: f64,
70        m03: f64,
71        m10: f64,
72        m11: f64,
73        m12: f64,
74        m13: f64,
75        m20: f64,
76        m21: f64,
77        m22: f64,
78        m23: f64,
79        m30: f64,
80        m31: f64,
81        m32: f64,
82        m33: f64,
83    ) -> Self {
84        Self {
85            x_axis: DVec4::new(m00, m01, m02, m03),
86            y_axis: DVec4::new(m10, m11, m12, m13),
87            z_axis: DVec4::new(m20, m21, m22, m23),
88            w_axis: DVec4::new(m30, m31, m32, m33),
89        }
90    }
91
92    /// Creates a 4x4 matrix from four column vectors.
93    #[inline(always)]
94    pub const fn from_cols(x_axis: DVec4, y_axis: DVec4, z_axis: DVec4, w_axis: DVec4) -> Self {
95        Self {
96            x_axis,
97            y_axis,
98            z_axis,
99            w_axis,
100        }
101    }
102
103    /// Creates a 4x4 matrix from a `[f64; 16]` array stored in column major order.
104    /// If your data is stored in row major you will need to `transpose` the returned
105    /// matrix.
106    #[inline]
107    pub const fn from_cols_array(m: &[f64; 16]) -> Self {
108        Self::new(
109            m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9], m[10], m[11], m[12], m[13],
110            m[14], m[15],
111        )
112    }
113
114    /// Creates a `[f64; 16]` array storing data in column major order.
115    /// If you require data in row major order `transpose` the matrix first.
116    #[inline]
117    pub const fn to_cols_array(&self) -> [f64; 16] {
118        [
119            self.x_axis.x,
120            self.x_axis.y,
121            self.x_axis.z,
122            self.x_axis.w,
123            self.y_axis.x,
124            self.y_axis.y,
125            self.y_axis.z,
126            self.y_axis.w,
127            self.z_axis.x,
128            self.z_axis.y,
129            self.z_axis.z,
130            self.z_axis.w,
131            self.w_axis.x,
132            self.w_axis.y,
133            self.w_axis.z,
134            self.w_axis.w,
135        ]
136    }
137
138    /// Creates a 4x4 matrix from a `[[f64; 4]; 4]` 4D array stored in column major order.
139    /// If your data is in row major order you will need to `transpose` the returned
140    /// matrix.
141    #[inline]
142    pub const fn from_cols_array_2d(m: &[[f64; 4]; 4]) -> Self {
143        Self::from_cols(
144            DVec4::from_array(m[0]),
145            DVec4::from_array(m[1]),
146            DVec4::from_array(m[2]),
147            DVec4::from_array(m[3]),
148        )
149    }
150
151    /// Creates a `[[f64; 4]; 4]` 4D array storing data in column major order.
152    /// If you require data in row major order `transpose` the matrix first.
153    #[inline]
154    pub const fn to_cols_array_2d(&self) -> [[f64; 4]; 4] {
155        [
156            self.x_axis.to_array(),
157            self.y_axis.to_array(),
158            self.z_axis.to_array(),
159            self.w_axis.to_array(),
160        ]
161    }
162
163    /// Creates a 4x4 matrix with its diagonal set to `diagonal` and all other entries set to 0.
164    #[doc(alias = "scale")]
165    #[inline]
166    pub const fn from_diagonal(diagonal: DVec4) -> Self {
167        Self::new(
168            diagonal.x, 0.0, 0.0, 0.0, 0.0, diagonal.y, 0.0, 0.0, 0.0, 0.0, diagonal.z, 0.0, 0.0,
169            0.0, 0.0, diagonal.w,
170        )
171    }
172
173    #[inline]
174    fn quat_to_axes(rotation: DQuat) -> (DVec4, DVec4, DVec4) {
175        glam_assert!(rotation.is_normalized());
176
177        let (x, y, z, w) = rotation.into();
178        let x2 = x + x;
179        let y2 = y + y;
180        let z2 = z + z;
181        let xx = x * x2;
182        let xy = x * y2;
183        let xz = x * z2;
184        let yy = y * y2;
185        let yz = y * z2;
186        let zz = z * z2;
187        let wx = w * x2;
188        let wy = w * y2;
189        let wz = w * z2;
190
191        let x_axis = DVec4::new(1.0 - (yy + zz), xy + wz, xz - wy, 0.0);
192        let y_axis = DVec4::new(xy - wz, 1.0 - (xx + zz), yz + wx, 0.0);
193        let z_axis = DVec4::new(xz + wy, yz - wx, 1.0 - (xx + yy), 0.0);
194        (x_axis, y_axis, z_axis)
195    }
196
197    /// Creates an affine transformation matrix from the given 3D `scale`, `rotation` and
198    /// `translation`.
199    ///
200    /// The resulting matrix can be used to transform 3D points and vectors. See
201    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
202    ///
203    /// # Panics
204    ///
205    /// Will panic if `rotation` is not normalized when `glam_assert` is enabled.
206    #[inline]
207    pub fn from_scale_rotation_translation(
208        scale: DVec3,
209        rotation: DQuat,
210        translation: DVec3,
211    ) -> Self {
212        let (x_axis, y_axis, z_axis) = Self::quat_to_axes(rotation);
213        Self::from_cols(
214            x_axis.mul(scale.x),
215            y_axis.mul(scale.y),
216            z_axis.mul(scale.z),
217            DVec4::from((translation, 1.0)),
218        )
219    }
220
221    /// Creates an affine transformation matrix from the given 3D `translation`.
222    ///
223    /// The resulting matrix can be used to transform 3D points and vectors. See
224    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
225    ///
226    /// # Panics
227    ///
228    /// Will panic if `rotation` is not normalized when `glam_assert` is enabled.
229    #[inline]
230    pub fn from_rotation_translation(rotation: DQuat, translation: DVec3) -> Self {
231        let (x_axis, y_axis, z_axis) = Self::quat_to_axes(rotation);
232        Self::from_cols(x_axis, y_axis, z_axis, DVec4::from((translation, 1.0)))
233    }
234
235    /// Extracts `scale`, `rotation` and `translation` from `self`. The input matrix is
236    /// expected to be a 3D affine transformation matrix otherwise the output will be invalid.
237    ///
238    /// # Panics
239    ///
240    /// Will panic if the determinant of `self` is zero or if the resulting scale vector
241    /// contains any zero elements when `glam_assert` is enabled.
242    #[inline]
243    pub fn to_scale_rotation_translation(&self) -> (DVec3, DQuat, DVec3) {
244        let det = self.determinant();
245        glam_assert!(det != 0.0);
246
247        let scale = DVec3::new(
248            self.x_axis.length() * math::signum(det),
249            self.y_axis.length(),
250            self.z_axis.length(),
251        );
252
253        glam_assert!(scale.cmpne(DVec3::ZERO).all());
254
255        let inv_scale = scale.recip();
256
257        let rotation = DQuat::from_rotation_axes(
258            self.x_axis.mul(inv_scale.x).xyz(),
259            self.y_axis.mul(inv_scale.y).xyz(),
260            self.z_axis.mul(inv_scale.z).xyz(),
261        );
262
263        let translation = self.w_axis.xyz();
264
265        (scale, rotation, translation)
266    }
267
268    /// Creates an affine transformation matrix from the given `rotation` quaternion.
269    ///
270    /// The resulting matrix can be used to transform 3D points and vectors. See
271    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
272    ///
273    /// # Panics
274    ///
275    /// Will panic if `rotation` is not normalized when `glam_assert` is enabled.
276    #[inline]
277    pub fn from_quat(rotation: DQuat) -> Self {
278        let (x_axis, y_axis, z_axis) = Self::quat_to_axes(rotation);
279        Self::from_cols(x_axis, y_axis, z_axis, DVec4::W)
280    }
281
282    /// Creates an affine transformation matrix from the given 3x3 linear transformation
283    /// matrix.
284    ///
285    /// The resulting matrix can be used to transform 3D points and vectors. See
286    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
287    #[inline]
288    pub fn from_mat3(m: DMat3) -> Self {
289        Self::from_cols(
290            DVec4::from((m.x_axis, 0.0)),
291            DVec4::from((m.y_axis, 0.0)),
292            DVec4::from((m.z_axis, 0.0)),
293            DVec4::W,
294        )
295    }
296
297    /// Creates an affine transformation matrix from the given 3D `translation`.
298    ///
299    /// The resulting matrix can be used to transform 3D points and vectors. See
300    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
301    #[inline]
302    pub fn from_translation(translation: DVec3) -> Self {
303        Self::from_cols(
304            DVec4::X,
305            DVec4::Y,
306            DVec4::Z,
307            DVec4::new(translation.x, translation.y, translation.z, 1.0),
308        )
309    }
310
311    /// Creates an affine transformation matrix containing a 3D rotation around a normalized
312    /// rotation `axis` of `angle` (in radians).
313    ///
314    /// The resulting matrix can be used to transform 3D points and vectors. See
315    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
316    ///
317    /// # Panics
318    ///
319    /// Will panic if `axis` is not normalized when `glam_assert` is enabled.
320    #[inline]
321    pub fn from_axis_angle(axis: DVec3, angle: f64) -> Self {
322        glam_assert!(axis.is_normalized());
323
324        let (sin, cos) = math::sin_cos(angle);
325        let axis_sin = axis.mul(sin);
326        let axis_sq = axis.mul(axis);
327        let omc = 1.0 - cos;
328        let xyomc = axis.x * axis.y * omc;
329        let xzomc = axis.x * axis.z * omc;
330        let yzomc = axis.y * axis.z * omc;
331        Self::from_cols(
332            DVec4::new(
333                axis_sq.x * omc + cos,
334                xyomc + axis_sin.z,
335                xzomc - axis_sin.y,
336                0.0,
337            ),
338            DVec4::new(
339                xyomc - axis_sin.z,
340                axis_sq.y * omc + cos,
341                yzomc + axis_sin.x,
342                0.0,
343            ),
344            DVec4::new(
345                xzomc + axis_sin.y,
346                yzomc - axis_sin.x,
347                axis_sq.z * omc + cos,
348                0.0,
349            ),
350            DVec4::W,
351        )
352    }
353
354    #[inline]
355    /// Creates a affine transformation matrix containing a rotation from the given euler
356    /// rotation sequence and angles (in radians).
357    ///
358    /// The resulting matrix can be used to transform 3D points and vectors. See
359    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
360    pub fn from_euler(order: EulerRot, a: f64, b: f64, c: f64) -> Self {
361        let quat = DQuat::from_euler(order, a, b, c);
362        Self::from_quat(quat)
363    }
364
365    /// Creates an affine transformation matrix containing a 3D rotation around the x axis of
366    /// `angle` (in radians).
367    ///
368    /// The resulting matrix can be used to transform 3D points and vectors. See
369    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
370    #[inline]
371    pub fn from_rotation_x(angle: f64) -> Self {
372        let (sina, cosa) = math::sin_cos(angle);
373        Self::from_cols(
374            DVec4::X,
375            DVec4::new(0.0, cosa, sina, 0.0),
376            DVec4::new(0.0, -sina, cosa, 0.0),
377            DVec4::W,
378        )
379    }
380
381    /// Creates an affine transformation matrix containing a 3D rotation around the y axis of
382    /// `angle` (in radians).
383    ///
384    /// The resulting matrix can be used to transform 3D points and vectors. See
385    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
386    #[inline]
387    pub fn from_rotation_y(angle: f64) -> Self {
388        let (sina, cosa) = math::sin_cos(angle);
389        Self::from_cols(
390            DVec4::new(cosa, 0.0, -sina, 0.0),
391            DVec4::Y,
392            DVec4::new(sina, 0.0, cosa, 0.0),
393            DVec4::W,
394        )
395    }
396
397    /// Creates an affine transformation matrix containing a 3D rotation around the z axis of
398    /// `angle` (in radians).
399    ///
400    /// The resulting matrix can be used to transform 3D points and vectors. See
401    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
402    #[inline]
403    pub fn from_rotation_z(angle: f64) -> Self {
404        let (sina, cosa) = math::sin_cos(angle);
405        Self::from_cols(
406            DVec4::new(cosa, sina, 0.0, 0.0),
407            DVec4::new(-sina, cosa, 0.0, 0.0),
408            DVec4::Z,
409            DVec4::W,
410        )
411    }
412
413    /// Creates an affine transformation matrix containing the given 3D non-uniform `scale`.
414    ///
415    /// The resulting matrix can be used to transform 3D points and vectors. See
416    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
417    ///
418    /// # Panics
419    ///
420    /// Will panic if all elements of `scale` are zero when `glam_assert` is enabled.
421    #[inline]
422    pub fn from_scale(scale: DVec3) -> Self {
423        // Do not panic as long as any component is non-zero
424        glam_assert!(scale.cmpne(DVec3::ZERO).any());
425
426        Self::from_cols(
427            DVec4::new(scale.x, 0.0, 0.0, 0.0),
428            DVec4::new(0.0, scale.y, 0.0, 0.0),
429            DVec4::new(0.0, 0.0, scale.z, 0.0),
430            DVec4::W,
431        )
432    }
433
434    /// Creates a 4x4 matrix from the first 16 values in `slice`.
435    ///
436    /// # Panics
437    ///
438    /// Panics if `slice` is less than 16 elements long.
439    #[inline]
440    pub const fn from_cols_slice(slice: &[f64]) -> Self {
441        Self::new(
442            slice[0], slice[1], slice[2], slice[3], slice[4], slice[5], slice[6], slice[7],
443            slice[8], slice[9], slice[10], slice[11], slice[12], slice[13], slice[14], slice[15],
444        )
445    }
446
447    /// Writes the columns of `self` to the first 16 elements in `slice`.
448    ///
449    /// # Panics
450    ///
451    /// Panics if `slice` is less than 16 elements long.
452    #[inline]
453    pub fn write_cols_to_slice(self, slice: &mut [f64]) {
454        slice[0] = self.x_axis.x;
455        slice[1] = self.x_axis.y;
456        slice[2] = self.x_axis.z;
457        slice[3] = self.x_axis.w;
458        slice[4] = self.y_axis.x;
459        slice[5] = self.y_axis.y;
460        slice[6] = self.y_axis.z;
461        slice[7] = self.y_axis.w;
462        slice[8] = self.z_axis.x;
463        slice[9] = self.z_axis.y;
464        slice[10] = self.z_axis.z;
465        slice[11] = self.z_axis.w;
466        slice[12] = self.w_axis.x;
467        slice[13] = self.w_axis.y;
468        slice[14] = self.w_axis.z;
469        slice[15] = self.w_axis.w;
470    }
471
472    /// Returns the matrix column for the given `index`.
473    ///
474    /// # Panics
475    ///
476    /// Panics if `index` is greater than 3.
477    #[inline]
478    pub fn col(&self, index: usize) -> DVec4 {
479        match index {
480            0 => self.x_axis,
481            1 => self.y_axis,
482            2 => self.z_axis,
483            3 => self.w_axis,
484            _ => panic!("index out of bounds"),
485        }
486    }
487
488    /// Returns a mutable reference to the matrix column for the given `index`.
489    ///
490    /// # Panics
491    ///
492    /// Panics if `index` is greater than 3.
493    #[inline]
494    pub fn col_mut(&mut self, index: usize) -> &mut DVec4 {
495        match index {
496            0 => &mut self.x_axis,
497            1 => &mut self.y_axis,
498            2 => &mut self.z_axis,
499            3 => &mut self.w_axis,
500            _ => panic!("index out of bounds"),
501        }
502    }
503
504    /// Returns the matrix row for the given `index`.
505    ///
506    /// # Panics
507    ///
508    /// Panics if `index` is greater than 3.
509    #[inline]
510    pub fn row(&self, index: usize) -> DVec4 {
511        match index {
512            0 => DVec4::new(self.x_axis.x, self.y_axis.x, self.z_axis.x, self.w_axis.x),
513            1 => DVec4::new(self.x_axis.y, self.y_axis.y, self.z_axis.y, self.w_axis.y),
514            2 => DVec4::new(self.x_axis.z, self.y_axis.z, self.z_axis.z, self.w_axis.z),
515            3 => DVec4::new(self.x_axis.w, self.y_axis.w, self.z_axis.w, self.w_axis.w),
516            _ => panic!("index out of bounds"),
517        }
518    }
519
520    /// Returns `true` if, and only if, all elements are finite.
521    /// If any element is either `NaN`, positive or negative infinity, this will return `false`.
522    #[inline]
523    pub fn is_finite(&self) -> bool {
524        self.x_axis.is_finite()
525            && self.y_axis.is_finite()
526            && self.z_axis.is_finite()
527            && self.w_axis.is_finite()
528    }
529
530    /// Returns `true` if any elements are `NaN`.
531    #[inline]
532    pub fn is_nan(&self) -> bool {
533        self.x_axis.is_nan() || self.y_axis.is_nan() || self.z_axis.is_nan() || self.w_axis.is_nan()
534    }
535
536    /// Returns the transpose of `self`.
537    #[must_use]
538    #[inline]
539    pub fn transpose(&self) -> Self {
540        Self {
541            x_axis: DVec4::new(self.x_axis.x, self.y_axis.x, self.z_axis.x, self.w_axis.x),
542            y_axis: DVec4::new(self.x_axis.y, self.y_axis.y, self.z_axis.y, self.w_axis.y),
543            z_axis: DVec4::new(self.x_axis.z, self.y_axis.z, self.z_axis.z, self.w_axis.z),
544            w_axis: DVec4::new(self.x_axis.w, self.y_axis.w, self.z_axis.w, self.w_axis.w),
545        }
546    }
547
548    /// Returns the determinant of `self`.
549    pub fn determinant(&self) -> f64 {
550        let (m00, m01, m02, m03) = self.x_axis.into();
551        let (m10, m11, m12, m13) = self.y_axis.into();
552        let (m20, m21, m22, m23) = self.z_axis.into();
553        let (m30, m31, m32, m33) = self.w_axis.into();
554
555        let a2323 = m22 * m33 - m23 * m32;
556        let a1323 = m21 * m33 - m23 * m31;
557        let a1223 = m21 * m32 - m22 * m31;
558        let a0323 = m20 * m33 - m23 * m30;
559        let a0223 = m20 * m32 - m22 * m30;
560        let a0123 = m20 * m31 - m21 * m30;
561
562        m00 * (m11 * a2323 - m12 * a1323 + m13 * a1223)
563            - m01 * (m10 * a2323 - m12 * a0323 + m13 * a0223)
564            + m02 * (m10 * a1323 - m11 * a0323 + m13 * a0123)
565            - m03 * (m10 * a1223 - m11 * a0223 + m12 * a0123)
566    }
567
568    /// Returns the inverse of `self`.
569    ///
570    /// If the matrix is not invertible the returned matrix will be invalid.
571    ///
572    /// # Panics
573    ///
574    /// Will panic if the determinant of `self` is zero when `glam_assert` is enabled.
575    #[must_use]
576    pub fn inverse(&self) -> Self {
577        let (m00, m01, m02, m03) = self.x_axis.into();
578        let (m10, m11, m12, m13) = self.y_axis.into();
579        let (m20, m21, m22, m23) = self.z_axis.into();
580        let (m30, m31, m32, m33) = self.w_axis.into();
581
582        let coef00 = m22 * m33 - m32 * m23;
583        let coef02 = m12 * m33 - m32 * m13;
584        let coef03 = m12 * m23 - m22 * m13;
585
586        let coef04 = m21 * m33 - m31 * m23;
587        let coef06 = m11 * m33 - m31 * m13;
588        let coef07 = m11 * m23 - m21 * m13;
589
590        let coef08 = m21 * m32 - m31 * m22;
591        let coef10 = m11 * m32 - m31 * m12;
592        let coef11 = m11 * m22 - m21 * m12;
593
594        let coef12 = m20 * m33 - m30 * m23;
595        let coef14 = m10 * m33 - m30 * m13;
596        let coef15 = m10 * m23 - m20 * m13;
597
598        let coef16 = m20 * m32 - m30 * m22;
599        let coef18 = m10 * m32 - m30 * m12;
600        let coef19 = m10 * m22 - m20 * m12;
601
602        let coef20 = m20 * m31 - m30 * m21;
603        let coef22 = m10 * m31 - m30 * m11;
604        let coef23 = m10 * m21 - m20 * m11;
605
606        let fac0 = DVec4::new(coef00, coef00, coef02, coef03);
607        let fac1 = DVec4::new(coef04, coef04, coef06, coef07);
608        let fac2 = DVec4::new(coef08, coef08, coef10, coef11);
609        let fac3 = DVec4::new(coef12, coef12, coef14, coef15);
610        let fac4 = DVec4::new(coef16, coef16, coef18, coef19);
611        let fac5 = DVec4::new(coef20, coef20, coef22, coef23);
612
613        let vec0 = DVec4::new(m10, m00, m00, m00);
614        let vec1 = DVec4::new(m11, m01, m01, m01);
615        let vec2 = DVec4::new(m12, m02, m02, m02);
616        let vec3 = DVec4::new(m13, m03, m03, m03);
617
618        let inv0 = vec1.mul(fac0).sub(vec2.mul(fac1)).add(vec3.mul(fac2));
619        let inv1 = vec0.mul(fac0).sub(vec2.mul(fac3)).add(vec3.mul(fac4));
620        let inv2 = vec0.mul(fac1).sub(vec1.mul(fac3)).add(vec3.mul(fac5));
621        let inv3 = vec0.mul(fac2).sub(vec1.mul(fac4)).add(vec2.mul(fac5));
622
623        let sign_a = DVec4::new(1.0, -1.0, 1.0, -1.0);
624        let sign_b = DVec4::new(-1.0, 1.0, -1.0, 1.0);
625
626        let inverse = Self::from_cols(
627            inv0.mul(sign_a),
628            inv1.mul(sign_b),
629            inv2.mul(sign_a),
630            inv3.mul(sign_b),
631        );
632
633        let col0 = DVec4::new(
634            inverse.x_axis.x,
635            inverse.y_axis.x,
636            inverse.z_axis.x,
637            inverse.w_axis.x,
638        );
639
640        let dot0 = self.x_axis.mul(col0);
641        let dot1 = dot0.x + dot0.y + dot0.z + dot0.w;
642
643        glam_assert!(dot1 != 0.0);
644
645        let rcp_det = dot1.recip();
646        inverse.mul(rcp_det)
647    }
648
649    /// Creates a left-handed view matrix using a camera position, an up direction, and a facing
650    /// direction.
651    ///
652    /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=forward`.
653    #[inline]
654    pub fn look_to_lh(eye: DVec3, dir: DVec3, up: DVec3) -> Self {
655        Self::look_to_rh(eye, -dir, up)
656    }
657
658    /// Creates a right-handed view matrix using a camera position, an up direction, and a facing
659    /// direction.
660    ///
661    /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=back`.
662    #[inline]
663    pub fn look_to_rh(eye: DVec3, dir: DVec3, up: DVec3) -> Self {
664        let f = dir.normalize();
665        let s = f.cross(up).normalize();
666        let u = s.cross(f);
667
668        Self::from_cols(
669            DVec4::new(s.x, u.x, -f.x, 0.0),
670            DVec4::new(s.y, u.y, -f.y, 0.0),
671            DVec4::new(s.z, u.z, -f.z, 0.0),
672            DVec4::new(-eye.dot(s), -eye.dot(u), eye.dot(f), 1.0),
673        )
674    }
675
676    /// Creates a left-handed view matrix using a camera position, an up direction, and a focal
677    /// point.
678    /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=forward`.
679    ///
680    /// # Panics
681    ///
682    /// Will panic if `up` is not normalized when `glam_assert` is enabled.
683    #[inline]
684    pub fn look_at_lh(eye: DVec3, center: DVec3, up: DVec3) -> Self {
685        glam_assert!(up.is_normalized());
686        Self::look_to_lh(eye, center.sub(eye), up)
687    }
688
689    /// Creates a right-handed view matrix using a camera position, an up direction, and a focal
690    /// point.
691    /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=back`.
692    ///
693    /// # Panics
694    ///
695    /// Will panic if `up` is not normalized when `glam_assert` is enabled.
696    #[inline]
697    pub fn look_at_rh(eye: DVec3, center: DVec3, up: DVec3) -> Self {
698        glam_assert!(up.is_normalized());
699        Self::look_to_rh(eye, center.sub(eye), up)
700    }
701
702    /// Creates a right-handed perspective projection matrix with [-1,1] depth range.
703    /// This is the same as the OpenGL `gluPerspective` function.
704    /// See <https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml>
705    #[inline]
706    pub fn perspective_rh_gl(
707        fov_y_radians: f64,
708        aspect_ratio: f64,
709        z_near: f64,
710        z_far: f64,
711    ) -> Self {
712        let inv_length = 1.0 / (z_near - z_far);
713        let f = 1.0 / math::tan(0.5 * fov_y_radians);
714        let a = f / aspect_ratio;
715        let b = (z_near + z_far) * inv_length;
716        let c = (2.0 * z_near * z_far) * inv_length;
717        Self::from_cols(
718            DVec4::new(a, 0.0, 0.0, 0.0),
719            DVec4::new(0.0, f, 0.0, 0.0),
720            DVec4::new(0.0, 0.0, b, -1.0),
721            DVec4::new(0.0, 0.0, c, 0.0),
722        )
723    }
724
725    /// Creates a left-handed perspective projection matrix with `[0,1]` depth range.
726    ///
727    /// # Panics
728    ///
729    /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
730    /// enabled.
731    #[inline]
732    pub fn perspective_lh(fov_y_radians: f64, aspect_ratio: f64, z_near: f64, z_far: f64) -> Self {
733        glam_assert!(z_near > 0.0 && z_far > 0.0);
734        let (sin_fov, cos_fov) = math::sin_cos(0.5 * fov_y_radians);
735        let h = cos_fov / sin_fov;
736        let w = h / aspect_ratio;
737        let r = z_far / (z_far - z_near);
738        Self::from_cols(
739            DVec4::new(w, 0.0, 0.0, 0.0),
740            DVec4::new(0.0, h, 0.0, 0.0),
741            DVec4::new(0.0, 0.0, r, 1.0),
742            DVec4::new(0.0, 0.0, -r * z_near, 0.0),
743        )
744    }
745
746    /// Creates a right-handed perspective projection matrix with `[0,1]` depth range.
747    ///
748    /// # Panics
749    ///
750    /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
751    /// enabled.
752    #[inline]
753    pub fn perspective_rh(fov_y_radians: f64, aspect_ratio: f64, z_near: f64, z_far: f64) -> Self {
754        glam_assert!(z_near > 0.0 && z_far > 0.0);
755        let (sin_fov, cos_fov) = math::sin_cos(0.5 * fov_y_radians);
756        let h = cos_fov / sin_fov;
757        let w = h / aspect_ratio;
758        let r = z_far / (z_near - z_far);
759        Self::from_cols(
760            DVec4::new(w, 0.0, 0.0, 0.0),
761            DVec4::new(0.0, h, 0.0, 0.0),
762            DVec4::new(0.0, 0.0, r, -1.0),
763            DVec4::new(0.0, 0.0, r * z_near, 0.0),
764        )
765    }
766
767    /// Creates an infinite left-handed perspective projection matrix with `[0,1]` depth range.
768    ///
769    /// # Panics
770    ///
771    /// Will panic if `z_near` is less than or equal to zero when `glam_assert` is enabled.
772    #[inline]
773    pub fn perspective_infinite_lh(fov_y_radians: f64, aspect_ratio: f64, z_near: f64) -> Self {
774        glam_assert!(z_near > 0.0);
775        let (sin_fov, cos_fov) = math::sin_cos(0.5 * fov_y_radians);
776        let h = cos_fov / sin_fov;
777        let w = h / aspect_ratio;
778        Self::from_cols(
779            DVec4::new(w, 0.0, 0.0, 0.0),
780            DVec4::new(0.0, h, 0.0, 0.0),
781            DVec4::new(0.0, 0.0, 1.0, 1.0),
782            DVec4::new(0.0, 0.0, -z_near, 0.0),
783        )
784    }
785
786    /// Creates an infinite left-handed perspective projection matrix with `[0,1]` depth range.
787    ///
788    /// # Panics
789    ///
790    /// Will panic if `z_near` is less than or equal to zero when `glam_assert` is enabled.
791    #[inline]
792    pub fn perspective_infinite_reverse_lh(
793        fov_y_radians: f64,
794        aspect_ratio: f64,
795        z_near: f64,
796    ) -> Self {
797        glam_assert!(z_near > 0.0);
798        let (sin_fov, cos_fov) = math::sin_cos(0.5 * fov_y_radians);
799        let h = cos_fov / sin_fov;
800        let w = h / aspect_ratio;
801        Self::from_cols(
802            DVec4::new(w, 0.0, 0.0, 0.0),
803            DVec4::new(0.0, h, 0.0, 0.0),
804            DVec4::new(0.0, 0.0, 0.0, 1.0),
805            DVec4::new(0.0, 0.0, z_near, 0.0),
806        )
807    }
808
809    /// Creates an infinite right-handed perspective projection matrix with
810    /// `[0,1]` depth range.
811    #[inline]
812    pub fn perspective_infinite_rh(fov_y_radians: f64, aspect_ratio: f64, z_near: f64) -> Self {
813        glam_assert!(z_near > 0.0);
814        let f = 1.0 / math::tan(0.5 * fov_y_radians);
815        Self::from_cols(
816            DVec4::new(f / aspect_ratio, 0.0, 0.0, 0.0),
817            DVec4::new(0.0, f, 0.0, 0.0),
818            DVec4::new(0.0, 0.0, -1.0, -1.0),
819            DVec4::new(0.0, 0.0, -z_near, 0.0),
820        )
821    }
822
823    /// Creates an infinite reverse right-handed perspective projection matrix
824    /// with `[0,1]` depth range.
825    #[inline]
826    pub fn perspective_infinite_reverse_rh(
827        fov_y_radians: f64,
828        aspect_ratio: f64,
829        z_near: f64,
830    ) -> Self {
831        glam_assert!(z_near > 0.0);
832        let f = 1.0 / math::tan(0.5 * fov_y_radians);
833        Self::from_cols(
834            DVec4::new(f / aspect_ratio, 0.0, 0.0, 0.0),
835            DVec4::new(0.0, f, 0.0, 0.0),
836            DVec4::new(0.0, 0.0, 0.0, -1.0),
837            DVec4::new(0.0, 0.0, z_near, 0.0),
838        )
839    }
840
841    /// Creates a right-handed orthographic projection matrix with `[-1,1]` depth
842    /// range.  This is the same as the OpenGL `glOrtho` function in OpenGL.
843    /// See
844    /// <https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glOrtho.xml>
845    #[inline]
846    pub fn orthographic_rh_gl(
847        left: f64,
848        right: f64,
849        bottom: f64,
850        top: f64,
851        near: f64,
852        far: f64,
853    ) -> Self {
854        let a = 2.0 / (right - left);
855        let b = 2.0 / (top - bottom);
856        let c = -2.0 / (far - near);
857        let tx = -(right + left) / (right - left);
858        let ty = -(top + bottom) / (top - bottom);
859        let tz = -(far + near) / (far - near);
860
861        Self::from_cols(
862            DVec4::new(a, 0.0, 0.0, 0.0),
863            DVec4::new(0.0, b, 0.0, 0.0),
864            DVec4::new(0.0, 0.0, c, 0.0),
865            DVec4::new(tx, ty, tz, 1.0),
866        )
867    }
868
869    /// Creates a left-handed orthographic projection matrix with `[0,1]` depth range.
870    #[inline]
871    pub fn orthographic_lh(
872        left: f64,
873        right: f64,
874        bottom: f64,
875        top: f64,
876        near: f64,
877        far: f64,
878    ) -> Self {
879        let rcp_width = 1.0 / (right - left);
880        let rcp_height = 1.0 / (top - bottom);
881        let r = 1.0 / (far - near);
882        Self::from_cols(
883            DVec4::new(rcp_width + rcp_width, 0.0, 0.0, 0.0),
884            DVec4::new(0.0, rcp_height + rcp_height, 0.0, 0.0),
885            DVec4::new(0.0, 0.0, r, 0.0),
886            DVec4::new(
887                -(left + right) * rcp_width,
888                -(top + bottom) * rcp_height,
889                -r * near,
890                1.0,
891            ),
892        )
893    }
894
895    /// Creates a right-handed orthographic projection matrix with `[0,1]` depth range.
896    #[inline]
897    pub fn orthographic_rh(
898        left: f64,
899        right: f64,
900        bottom: f64,
901        top: f64,
902        near: f64,
903        far: f64,
904    ) -> Self {
905        let rcp_width = 1.0 / (right - left);
906        let rcp_height = 1.0 / (top - bottom);
907        let r = 1.0 / (near - far);
908        Self::from_cols(
909            DVec4::new(rcp_width + rcp_width, 0.0, 0.0, 0.0),
910            DVec4::new(0.0, rcp_height + rcp_height, 0.0, 0.0),
911            DVec4::new(0.0, 0.0, r, 0.0),
912            DVec4::new(
913                -(left + right) * rcp_width,
914                -(top + bottom) * rcp_height,
915                r * near,
916                1.0,
917            ),
918        )
919    }
920
921    /// Transforms the given 3D vector as a point, applying perspective correction.
922    ///
923    /// This is the equivalent of multiplying the 3D vector as a 4D vector where `w` is `1.0`.
924    /// The perspective divide is performed meaning the resulting 3D vector is divided by `w`.
925    ///
926    /// This method assumes that `self` contains a projective transform.
927    #[inline]
928    pub fn project_point3(&self, rhs: DVec3) -> DVec3 {
929        let mut res = self.x_axis.mul(rhs.x);
930        res = self.y_axis.mul(rhs.y).add(res);
931        res = self.z_axis.mul(rhs.z).add(res);
932        res = self.w_axis.add(res);
933        res = res.mul(res.wwww().recip());
934        res.xyz()
935    }
936
937    /// Transforms the given 3D vector as a point.
938    ///
939    /// This is the equivalent of multiplying the 3D vector as a 4D vector where `w` is
940    /// `1.0`.
941    ///
942    /// This method assumes that `self` contains a valid affine transform. It does not perform
943    /// a persective divide, if `self` contains a perspective transform, or if you are unsure,
944    /// the [`Self::project_point3()`] method should be used instead.
945    ///
946    /// # Panics
947    ///
948    /// Will panic if the 3rd row of `self` is not `(0, 0, 0, 1)` when `glam_assert` is enabled.
949    #[inline]
950    pub fn transform_point3(&self, rhs: DVec3) -> DVec3 {
951        glam_assert!(self.row(3).abs_diff_eq(DVec4::W, 1e-6));
952        let mut res = self.x_axis.mul(rhs.x);
953        res = self.y_axis.mul(rhs.y).add(res);
954        res = self.z_axis.mul(rhs.z).add(res);
955        res = self.w_axis.add(res);
956        res.xyz()
957    }
958
959    /// Transforms the give 3D vector as a direction.
960    ///
961    /// This is the equivalent of multiplying the 3D vector as a 4D vector where `w` is
962    /// `0.0`.
963    ///
964    /// This method assumes that `self` contains a valid affine transform.
965    ///
966    /// # Panics
967    ///
968    /// Will panic if the 3rd row of `self` is not `(0, 0, 0, 1)` when `glam_assert` is enabled.
969    #[inline]
970    pub fn transform_vector3(&self, rhs: DVec3) -> DVec3 {
971        glam_assert!(self.row(3).abs_diff_eq(DVec4::W, 1e-6));
972        let mut res = self.x_axis.mul(rhs.x);
973        res = self.y_axis.mul(rhs.y).add(res);
974        res = self.z_axis.mul(rhs.z).add(res);
975        res.xyz()
976    }
977
978    /// Transforms a 4D vector.
979    #[inline]
980    pub fn mul_vec4(&self, rhs: DVec4) -> DVec4 {
981        let mut res = self.x_axis.mul(rhs.x);
982        res = res.add(self.y_axis.mul(rhs.y));
983        res = res.add(self.z_axis.mul(rhs.z));
984        res = res.add(self.w_axis.mul(rhs.w));
985        res
986    }
987
988    /// Multiplies two 4x4 matrices.
989    #[inline]
990    pub fn mul_mat4(&self, rhs: &Self) -> Self {
991        Self::from_cols(
992            self.mul(rhs.x_axis),
993            self.mul(rhs.y_axis),
994            self.mul(rhs.z_axis),
995            self.mul(rhs.w_axis),
996        )
997    }
998
999    /// Adds two 4x4 matrices.
1000    #[inline]
1001    pub fn add_mat4(&self, rhs: &Self) -> Self {
1002        Self::from_cols(
1003            self.x_axis.add(rhs.x_axis),
1004            self.y_axis.add(rhs.y_axis),
1005            self.z_axis.add(rhs.z_axis),
1006            self.w_axis.add(rhs.w_axis),
1007        )
1008    }
1009
1010    /// Subtracts two 4x4 matrices.
1011    #[inline]
1012    pub fn sub_mat4(&self, rhs: &Self) -> Self {
1013        Self::from_cols(
1014            self.x_axis.sub(rhs.x_axis),
1015            self.y_axis.sub(rhs.y_axis),
1016            self.z_axis.sub(rhs.z_axis),
1017            self.w_axis.sub(rhs.w_axis),
1018        )
1019    }
1020
1021    /// Multiplies a 4x4 matrix by a scalar.
1022    #[inline]
1023    pub fn mul_scalar(&self, rhs: f64) -> Self {
1024        Self::from_cols(
1025            self.x_axis.mul(rhs),
1026            self.y_axis.mul(rhs),
1027            self.z_axis.mul(rhs),
1028            self.w_axis.mul(rhs),
1029        )
1030    }
1031
1032    /// Returns true if the absolute difference of all elements between `self` and `rhs`
1033    /// is less than or equal to `max_abs_diff`.
1034    ///
1035    /// This can be used to compare if two matrices contain similar elements. It works best
1036    /// when comparing with a known value. The `max_abs_diff` that should be used used
1037    /// depends on the values being compared against.
1038    ///
1039    /// For more see
1040    /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/).
1041    #[inline]
1042    pub fn abs_diff_eq(&self, rhs: Self, max_abs_diff: f64) -> bool {
1043        self.x_axis.abs_diff_eq(rhs.x_axis, max_abs_diff)
1044            && self.y_axis.abs_diff_eq(rhs.y_axis, max_abs_diff)
1045            && self.z_axis.abs_diff_eq(rhs.z_axis, max_abs_diff)
1046            && self.w_axis.abs_diff_eq(rhs.w_axis, max_abs_diff)
1047    }
1048
1049    #[inline]
1050    pub fn as_mat4(&self) -> Mat4 {
1051        Mat4::from_cols(
1052            self.x_axis.as_vec4(),
1053            self.y_axis.as_vec4(),
1054            self.z_axis.as_vec4(),
1055            self.w_axis.as_vec4(),
1056        )
1057    }
1058}
1059
1060impl Default for DMat4 {
1061    #[inline]
1062    fn default() -> Self {
1063        Self::IDENTITY
1064    }
1065}
1066
1067impl Add<DMat4> for DMat4 {
1068    type Output = Self;
1069    #[inline]
1070    fn add(self, rhs: Self) -> Self::Output {
1071        self.add_mat4(&rhs)
1072    }
1073}
1074
1075impl AddAssign<DMat4> for DMat4 {
1076    #[inline]
1077    fn add_assign(&mut self, rhs: Self) {
1078        *self = self.add_mat4(&rhs);
1079    }
1080}
1081
1082impl Sub<DMat4> for DMat4 {
1083    type Output = Self;
1084    #[inline]
1085    fn sub(self, rhs: Self) -> Self::Output {
1086        self.sub_mat4(&rhs)
1087    }
1088}
1089
1090impl SubAssign<DMat4> for DMat4 {
1091    #[inline]
1092    fn sub_assign(&mut self, rhs: Self) {
1093        *self = self.sub_mat4(&rhs);
1094    }
1095}
1096
1097impl Neg for DMat4 {
1098    type Output = Self;
1099    #[inline]
1100    fn neg(self) -> Self::Output {
1101        Self::from_cols(
1102            self.x_axis.neg(),
1103            self.y_axis.neg(),
1104            self.z_axis.neg(),
1105            self.w_axis.neg(),
1106        )
1107    }
1108}
1109
1110impl Mul<DMat4> for DMat4 {
1111    type Output = Self;
1112    #[inline]
1113    fn mul(self, rhs: Self) -> Self::Output {
1114        self.mul_mat4(&rhs)
1115    }
1116}
1117
1118impl MulAssign<DMat4> for DMat4 {
1119    #[inline]
1120    fn mul_assign(&mut self, rhs: Self) {
1121        *self = self.mul_mat4(&rhs);
1122    }
1123}
1124
1125impl Mul<DVec4> for DMat4 {
1126    type Output = DVec4;
1127    #[inline]
1128    fn mul(self, rhs: DVec4) -> Self::Output {
1129        self.mul_vec4(rhs)
1130    }
1131}
1132
1133impl Mul<DMat4> for f64 {
1134    type Output = DMat4;
1135    #[inline]
1136    fn mul(self, rhs: DMat4) -> Self::Output {
1137        rhs.mul_scalar(self)
1138    }
1139}
1140
1141impl Mul<f64> for DMat4 {
1142    type Output = Self;
1143    #[inline]
1144    fn mul(self, rhs: f64) -> Self::Output {
1145        self.mul_scalar(rhs)
1146    }
1147}
1148
1149impl MulAssign<f64> for DMat4 {
1150    #[inline]
1151    fn mul_assign(&mut self, rhs: f64) {
1152        *self = self.mul_scalar(rhs);
1153    }
1154}
1155
1156impl Sum<Self> for DMat4 {
1157    fn sum<I>(iter: I) -> Self
1158    where
1159        I: Iterator<Item = Self>,
1160    {
1161        iter.fold(Self::ZERO, Self::add)
1162    }
1163}
1164
1165impl<'a> Sum<&'a Self> for DMat4 {
1166    fn sum<I>(iter: I) -> Self
1167    where
1168        I: Iterator<Item = &'a Self>,
1169    {
1170        iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
1171    }
1172}
1173
1174impl Product for DMat4 {
1175    fn product<I>(iter: I) -> Self
1176    where
1177        I: Iterator<Item = Self>,
1178    {
1179        iter.fold(Self::IDENTITY, Self::mul)
1180    }
1181}
1182
1183impl<'a> Product<&'a Self> for DMat4 {
1184    fn product<I>(iter: I) -> Self
1185    where
1186        I: Iterator<Item = &'a Self>,
1187    {
1188        iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b))
1189    }
1190}
1191
1192impl PartialEq for DMat4 {
1193    #[inline]
1194    fn eq(&self, rhs: &Self) -> bool {
1195        self.x_axis.eq(&rhs.x_axis)
1196            && self.y_axis.eq(&rhs.y_axis)
1197            && self.z_axis.eq(&rhs.z_axis)
1198            && self.w_axis.eq(&rhs.w_axis)
1199    }
1200}
1201
1202#[cfg(not(target_arch = "spirv"))]
1203impl AsRef<[f64; 16]> for DMat4 {
1204    #[inline]
1205    fn as_ref(&self) -> &[f64; 16] {
1206        unsafe { &*(self as *const Self as *const [f64; 16]) }
1207    }
1208}
1209
1210#[cfg(not(target_arch = "spirv"))]
1211impl AsMut<[f64; 16]> for DMat4 {
1212    #[inline]
1213    fn as_mut(&mut self) -> &mut [f64; 16] {
1214        unsafe { &mut *(self as *mut Self as *mut [f64; 16]) }
1215    }
1216}
1217
1218#[cfg(not(target_arch = "spirv"))]
1219impl fmt::Debug for DMat4 {
1220    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
1221        fmt.debug_struct(stringify!(DMat4))
1222            .field("x_axis", &self.x_axis)
1223            .field("y_axis", &self.y_axis)
1224            .field("z_axis", &self.z_axis)
1225            .field("w_axis", &self.w_axis)
1226            .finish()
1227    }
1228}
1229
1230#[cfg(not(target_arch = "spirv"))]
1231impl fmt::Display for DMat4 {
1232    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1233        write!(
1234            f,
1235            "[{}, {}, {}, {}]",
1236            self.x_axis, self.y_axis, self.z_axis, self.w_axis
1237        )
1238    }
1239}