Skip to main content

glam/f32/neon/
mat3a.rs

1// Generated from mat.rs.tera template. Edit the template, not the generated file.
2
3#[cfg(feature = "f64")]
4use crate::DMat3;
5
6use crate::{
7    euler::{FromEuler, ToEuler},
8    f32::math,
9    swizzles::*,
10    EulerRot, Mat2, Mat3, Mat4, Quat, Vec2, Vec3, Vec3A,
11};
12use core::fmt;
13use core::iter::{Product, Sum};
14use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
15
16use core::arch::aarch64::*;
17
18#[cfg(feature = "zerocopy")]
19use zerocopy_derive::*;
20
21/// Creates a 3x3 matrix from three column vectors.
22#[inline(always)]
23#[must_use]
24pub const fn mat3a(x_axis: Vec3A, y_axis: Vec3A, z_axis: Vec3A) -> Mat3A {
25    Mat3A::from_cols(x_axis, y_axis, z_axis)
26}
27
28/// A 3x3 column major matrix.
29///
30/// This 3x3 matrix type features convenience methods for creating and using linear and
31/// affine transformations. If you are primarily dealing with 2D affine transformations the
32/// [`Affine2`](crate::Affine2) type is much faster and more space efficient than
33/// using a 3x3 matrix.
34///
35/// Linear transformations including 3D rotation and scale can be created using methods
36/// such as [`Self::from_diagonal()`], [`Self::from_quat()`], [`Self::from_axis_angle()`],
37/// [`Self::from_rotation_x()`], [`Self::from_rotation_y()`], or
38/// [`Self::from_rotation_z()`].
39///
40/// The resulting matrices can be use to transform 3D vectors using regular vector
41/// multiplication.
42///
43/// Affine transformations including 2D translation, rotation and scale can be created
44/// using methods such as [`Self::from_translation()`], [`Self::from_angle()`],
45/// [`Self::from_scale()`] and [`Self::from_scale_angle_translation()`].
46///
47/// The [`Self::transform_point2()`] and [`Self::transform_vector2()`] convenience methods
48/// are provided for performing affine transforms on 2D vectors and points. These multiply
49/// 2D inputs as 3D vectors with an implicit `z` value of `1` for points and `0` for
50/// vectors respectively. These methods assume that `Self` contains a valid affine
51/// transform.
52#[derive(Clone, Copy)]
53#[cfg_attr(feature = "bytemuck", derive(bytemuck::Pod, bytemuck::Zeroable))]
54#[cfg_attr(
55    feature = "zerocopy",
56    derive(FromBytes, Immutable, IntoBytes, KnownLayout)
57)]
58#[repr(C)]
59pub struct Mat3A {
60    pub x_axis: Vec3A,
61    pub y_axis: Vec3A,
62    pub z_axis: Vec3A,
63}
64
65impl Mat3A {
66    /// A 3x3 matrix with all elements set to `0.0`.
67    pub const ZERO: Self = Self::from_cols(Vec3A::ZERO, Vec3A::ZERO, Vec3A::ZERO);
68
69    /// A 3x3 identity matrix, where all diagonal elements are `1`, and all off-diagonal elements are `0`.
70    pub const IDENTITY: Self = Self::from_cols(Vec3A::X, Vec3A::Y, Vec3A::Z);
71
72    /// All NAN:s.
73    pub const NAN: Self = Self::from_cols(Vec3A::NAN, Vec3A::NAN, Vec3A::NAN);
74
75    #[allow(clippy::too_many_arguments)]
76    #[inline(always)]
77    #[must_use]
78    const fn new(
79        m00: f32,
80        m01: f32,
81        m02: f32,
82        m10: f32,
83        m11: f32,
84        m12: f32,
85        m20: f32,
86        m21: f32,
87        m22: f32,
88    ) -> Self {
89        Self {
90            x_axis: Vec3A::new(m00, m01, m02),
91            y_axis: Vec3A::new(m10, m11, m12),
92            z_axis: Vec3A::new(m20, m21, m22),
93        }
94    }
95
96    /// Creates a 3x3 matrix from three column vectors.
97    #[inline(always)]
98    #[must_use]
99    pub const fn from_cols(x_axis: Vec3A, y_axis: Vec3A, z_axis: Vec3A) -> Self {
100        Self {
101            x_axis,
102            y_axis,
103            z_axis,
104        }
105    }
106
107    /// Creates a 3x3 matrix from a `[f32; 9]` array stored in column major order.
108    /// If your data is stored in row major you will need to `transpose` the returned
109    /// matrix.
110    #[inline]
111    #[must_use]
112    pub const fn from_cols_array(m: &[f32; 9]) -> Self {
113        Self::new(m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8])
114    }
115
116    /// Creates a `[f32; 9]` array storing data in column major order.
117    /// If you require data in row major order `transpose` the matrix first.
118    #[inline]
119    #[must_use]
120    pub const fn to_cols_array(&self) -> [f32; 9] {
121        let [x_axis_x, x_axis_y, x_axis_z] = self.x_axis.to_array();
122        let [y_axis_x, y_axis_y, y_axis_z] = self.y_axis.to_array();
123        let [z_axis_x, z_axis_y, z_axis_z] = self.z_axis.to_array();
124
125        [
126            x_axis_x, x_axis_y, x_axis_z, y_axis_x, y_axis_y, y_axis_z, z_axis_x, z_axis_y,
127            z_axis_z,
128        ]
129    }
130
131    /// Creates a 3x3 matrix from a `[[f32; 3]; 3]` 3D array stored in column major order.
132    /// If your data is in row major order you will need to `transpose` the returned
133    /// matrix.
134    #[inline]
135    #[must_use]
136    pub const fn from_cols_array_2d(m: &[[f32; 3]; 3]) -> Self {
137        Self::from_cols(
138            Vec3A::from_array(m[0]),
139            Vec3A::from_array(m[1]),
140            Vec3A::from_array(m[2]),
141        )
142    }
143
144    /// Creates a `[[f32; 3]; 3]` 3D array storing data in column major order.
145    /// If you require data in row major order `transpose` the matrix first.
146    #[inline]
147    #[must_use]
148    pub const fn to_cols_array_2d(&self) -> [[f32; 3]; 3] {
149        [
150            self.x_axis.to_array(),
151            self.y_axis.to_array(),
152            self.z_axis.to_array(),
153        ]
154    }
155
156    /// Creates a 3x3 matrix with its diagonal set to `diagonal` and all other entries set to 0.
157    #[doc(alias = "scale")]
158    #[inline]
159    #[must_use]
160    pub const fn from_diagonal(diagonal: Vec3) -> Self {
161        Self::new(
162            diagonal.x, 0.0, 0.0, 0.0, diagonal.y, 0.0, 0.0, 0.0, diagonal.z,
163        )
164    }
165
166    /// Creates a 3x3 matrix from a 4x4 matrix, discarding the 4th row and column.
167    #[inline]
168    #[must_use]
169    pub fn from_mat4(m: Mat4) -> Self {
170        Self::from_cols(
171            Vec3A::from_vec4(m.x_axis),
172            Vec3A::from_vec4(m.y_axis),
173            Vec3A::from_vec4(m.z_axis),
174        )
175    }
176
177    /// Creates a 3x3 matrix from the minor of the given 4x4 matrix, discarding the `i`th column
178    /// and `j`th row.
179    ///
180    /// # Panics
181    ///
182    /// Panics if `i` or `j` is greater than 3.
183    #[inline]
184    #[must_use]
185    pub fn from_mat4_minor(m: Mat4, i: usize, j: usize) -> Self {
186        match (i, j) {
187            (0, 0) => Self::from_cols(
188                Vec3A::from_vec4(m.y_axis.yzww()),
189                Vec3A::from_vec4(m.z_axis.yzww()),
190                Vec3A::from_vec4(m.w_axis.yzww()),
191            ),
192            (0, 1) => Self::from_cols(
193                Vec3A::from_vec4(m.y_axis.xzww()),
194                Vec3A::from_vec4(m.z_axis.xzww()),
195                Vec3A::from_vec4(m.w_axis.xzww()),
196            ),
197            (0, 2) => Self::from_cols(
198                Vec3A::from_vec4(m.y_axis.xyww()),
199                Vec3A::from_vec4(m.z_axis.xyww()),
200                Vec3A::from_vec4(m.w_axis.xyww()),
201            ),
202            (0, 3) => Self::from_cols(
203                Vec3A::from_vec4(m.y_axis.xyzw()),
204                Vec3A::from_vec4(m.z_axis.xyzw()),
205                Vec3A::from_vec4(m.w_axis.xyzw()),
206            ),
207            (1, 0) => Self::from_cols(
208                Vec3A::from_vec4(m.x_axis.yzww()),
209                Vec3A::from_vec4(m.z_axis.yzww()),
210                Vec3A::from_vec4(m.w_axis.yzww()),
211            ),
212            (1, 1) => Self::from_cols(
213                Vec3A::from_vec4(m.x_axis.xzww()),
214                Vec3A::from_vec4(m.z_axis.xzww()),
215                Vec3A::from_vec4(m.w_axis.xzww()),
216            ),
217            (1, 2) => Self::from_cols(
218                Vec3A::from_vec4(m.x_axis.xyww()),
219                Vec3A::from_vec4(m.z_axis.xyww()),
220                Vec3A::from_vec4(m.w_axis.xyww()),
221            ),
222            (1, 3) => Self::from_cols(
223                Vec3A::from_vec4(m.x_axis.xyzw()),
224                Vec3A::from_vec4(m.z_axis.xyzw()),
225                Vec3A::from_vec4(m.w_axis.xyzw()),
226            ),
227            (2, 0) => Self::from_cols(
228                Vec3A::from_vec4(m.x_axis.yzww()),
229                Vec3A::from_vec4(m.y_axis.yzww()),
230                Vec3A::from_vec4(m.w_axis.yzww()),
231            ),
232            (2, 1) => Self::from_cols(
233                Vec3A::from_vec4(m.x_axis.xzww()),
234                Vec3A::from_vec4(m.y_axis.xzww()),
235                Vec3A::from_vec4(m.w_axis.xzww()),
236            ),
237            (2, 2) => Self::from_cols(
238                Vec3A::from_vec4(m.x_axis.xyww()),
239                Vec3A::from_vec4(m.y_axis.xyww()),
240                Vec3A::from_vec4(m.w_axis.xyww()),
241            ),
242            (2, 3) => Self::from_cols(
243                Vec3A::from_vec4(m.x_axis.xyzw()),
244                Vec3A::from_vec4(m.y_axis.xyzw()),
245                Vec3A::from_vec4(m.w_axis.xyzw()),
246            ),
247            (3, 0) => Self::from_cols(
248                Vec3A::from_vec4(m.x_axis.yzww()),
249                Vec3A::from_vec4(m.y_axis.yzww()),
250                Vec3A::from_vec4(m.z_axis.yzww()),
251            ),
252            (3, 1) => Self::from_cols(
253                Vec3A::from_vec4(m.x_axis.xzww()),
254                Vec3A::from_vec4(m.y_axis.xzww()),
255                Vec3A::from_vec4(m.z_axis.xzww()),
256            ),
257            (3, 2) => Self::from_cols(
258                Vec3A::from_vec4(m.x_axis.xyww()),
259                Vec3A::from_vec4(m.y_axis.xyww()),
260                Vec3A::from_vec4(m.z_axis.xyww()),
261            ),
262            (3, 3) => Self::from_cols(
263                Vec3A::from_vec4(m.x_axis.xyzw()),
264                Vec3A::from_vec4(m.y_axis.xyzw()),
265                Vec3A::from_vec4(m.z_axis.xyzw()),
266            ),
267            _ => panic!("index out of bounds"),
268        }
269    }
270
271    /// Creates a 3D rotation matrix from the given quaternion.
272    ///
273    /// # Panics
274    ///
275    /// Will panic if `rotation` is not normalized when `glam_assert` is enabled.
276    #[inline]
277    #[must_use]
278    pub fn from_quat(rotation: Quat) -> Self {
279        glam_assert!(rotation.is_normalized());
280
281        let x2 = rotation.x + rotation.x;
282        let y2 = rotation.y + rotation.y;
283        let z2 = rotation.z + rotation.z;
284        let xx = rotation.x * x2;
285        let xy = rotation.x * y2;
286        let xz = rotation.x * z2;
287        let yy = rotation.y * y2;
288        let yz = rotation.y * z2;
289        let zz = rotation.z * z2;
290        let wx = rotation.w * x2;
291        let wy = rotation.w * y2;
292        let wz = rotation.w * z2;
293
294        Self::from_cols(
295            Vec3A::new(1.0 - (yy + zz), xy + wz, xz - wy),
296            Vec3A::new(xy - wz, 1.0 - (xx + zz), yz + wx),
297            Vec3A::new(xz + wy, yz - wx, 1.0 - (xx + yy)),
298        )
299    }
300
301    /// Creates a 3D rotation matrix from a normalized rotation `axis` and `angle` (in
302    /// radians).
303    ///
304    /// # Panics
305    ///
306    /// Will panic if `axis` is not normalized when `glam_assert` is enabled.
307    #[inline]
308    #[must_use]
309    pub fn from_axis_angle(axis: Vec3, angle: f32) -> Self {
310        glam_assert!(axis.is_normalized());
311
312        let (sin, cos) = math::sin_cos(angle);
313        let (xsin, ysin, zsin) = axis.mul(sin).into();
314        let (x, y, z) = axis.into();
315        let (x2, y2, z2) = axis.mul(axis).into();
316        let omc = 1.0 - cos;
317        let xyomc = x * y * omc;
318        let xzomc = x * z * omc;
319        let yzomc = y * z * omc;
320        Self::from_cols(
321            Vec3A::new(x2 * omc + cos, xyomc + zsin, xzomc - ysin),
322            Vec3A::new(xyomc - zsin, y2 * omc + cos, yzomc + xsin),
323            Vec3A::new(xzomc + ysin, yzomc - xsin, z2 * omc + cos),
324        )
325    }
326
327    /// Creates a 3D rotation matrix from the given euler rotation sequence and the angles (in
328    /// radians).
329    #[inline]
330    #[must_use]
331    pub fn from_euler(order: EulerRot, a: f32, b: f32, c: f32) -> Self {
332        Self::from_euler_angles(order, a, b, c)
333    }
334
335    /// Extract Euler angles with the given Euler rotation order.
336    ///
337    /// Note if the input matrix contains scales, shears, or other non-rotation transformations then
338    /// the resulting Euler angles will be ill-defined.
339    ///
340    /// # Panics
341    ///
342    /// Will panic if any input matrix column is not normalized when `glam_assert` is enabled.
343    #[inline]
344    #[must_use]
345    pub fn to_euler(&self, order: EulerRot) -> (f32, f32, f32) {
346        glam_assert!(
347            self.x_axis.is_normalized()
348                && self.y_axis.is_normalized()
349                && self.z_axis.is_normalized()
350        );
351        self.to_euler_angles(order)
352    }
353
354    /// Creates a 3D rotation matrix from `angle` (in radians) around the x axis.
355    #[inline]
356    #[must_use]
357    pub fn from_rotation_x(angle: f32) -> Self {
358        let (sina, cosa) = math::sin_cos(angle);
359        Self::from_cols(
360            Vec3A::X,
361            Vec3A::new(0.0, cosa, sina),
362            Vec3A::new(0.0, -sina, cosa),
363        )
364    }
365
366    /// Creates a 3D rotation matrix from `angle` (in radians) around the y axis.
367    #[inline]
368    #[must_use]
369    pub fn from_rotation_y(angle: f32) -> Self {
370        let (sina, cosa) = math::sin_cos(angle);
371        Self::from_cols(
372            Vec3A::new(cosa, 0.0, -sina),
373            Vec3A::Y,
374            Vec3A::new(sina, 0.0, cosa),
375        )
376    }
377
378    /// Creates a 3D rotation matrix from `angle` (in radians) around the z axis.
379    #[inline]
380    #[must_use]
381    pub fn from_rotation_z(angle: f32) -> Self {
382        let (sina, cosa) = math::sin_cos(angle);
383        Self::from_cols(
384            Vec3A::new(cosa, sina, 0.0),
385            Vec3A::new(-sina, cosa, 0.0),
386            Vec3A::Z,
387        )
388    }
389
390    /// Creates an affine transformation matrix from the given 2D `translation`.
391    ///
392    /// The resulting matrix can be used to transform 2D points and vectors. See
393    /// [`Self::transform_point2()`] and [`Self::transform_vector2()`].
394    #[inline]
395    #[must_use]
396    pub fn from_translation(translation: Vec2) -> Self {
397        Self::from_cols(
398            Vec3A::X,
399            Vec3A::Y,
400            Vec3A::new(translation.x, translation.y, 1.0),
401        )
402    }
403
404    /// Creates an affine transformation matrix from the given 2D rotation `angle` (in
405    /// radians).
406    ///
407    /// The resulting matrix can be used to transform 2D points and vectors. See
408    /// [`Self::transform_point2()`] and [`Self::transform_vector2()`].
409    #[inline]
410    #[must_use]
411    pub fn from_angle(angle: f32) -> Self {
412        let (sin, cos) = math::sin_cos(angle);
413        Self::from_cols(
414            Vec3A::new(cos, sin, 0.0),
415            Vec3A::new(-sin, cos, 0.0),
416            Vec3A::Z,
417        )
418    }
419
420    /// Creates an affine transformation matrix from the given 2D `scale`, rotation `angle` (in
421    /// radians) and `translation`.
422    ///
423    /// The resulting matrix can be used to transform 2D points and vectors. See
424    /// [`Self::transform_point2()`] and [`Self::transform_vector2()`].
425    #[inline]
426    #[must_use]
427    pub fn from_scale_angle_translation(scale: Vec2, angle: f32, translation: Vec2) -> Self {
428        let (sin, cos) = math::sin_cos(angle);
429        Self::from_cols(
430            Vec3A::new(cos * scale.x, sin * scale.x, 0.0),
431            Vec3A::new(-sin * scale.y, cos * scale.y, 0.0),
432            Vec3A::new(translation.x, translation.y, 1.0),
433        )
434    }
435
436    /// Creates an affine transformation matrix from the given non-uniform 2D `scale`.
437    ///
438    /// The resulting matrix can be used to transform 2D points and vectors. See
439    /// [`Self::transform_point2()`] and [`Self::transform_vector2()`].
440    ///
441    /// # Panics
442    ///
443    /// Will panic if all elements of `scale` are zero when `glam_assert` is enabled.
444    #[inline]
445    #[must_use]
446    pub fn from_scale(scale: Vec2) -> Self {
447        // Do not panic as long as any component is non-zero
448        glam_assert!(scale.cmpne(Vec2::ZERO).any());
449
450        Self::from_cols(
451            Vec3A::new(scale.x, 0.0, 0.0),
452            Vec3A::new(0.0, scale.y, 0.0),
453            Vec3A::Z,
454        )
455    }
456
457    /// Creates an affine transformation matrix from the given 2x2 matrix.
458    ///
459    /// The resulting matrix can be used to transform 2D points and vectors. See
460    /// [`Self::transform_point2()`] and [`Self::transform_vector2()`].
461    #[inline]
462    pub fn from_mat2(m: Mat2) -> Self {
463        Self::from_cols((m.x_axis, 0.0).into(), (m.y_axis, 0.0).into(), Vec3A::Z)
464    }
465
466    /// Creates a 3x3 matrix from the first 9 values in `slice`.
467    ///
468    /// # Panics
469    ///
470    /// Panics if `slice` is less than 9 elements long.
471    #[inline]
472    #[must_use]
473    pub const fn from_cols_slice(slice: &[f32]) -> Self {
474        Self::new(
475            slice[0], slice[1], slice[2], slice[3], slice[4], slice[5], slice[6], slice[7],
476            slice[8],
477        )
478    }
479
480    /// Writes the columns of `self` to the first 9 elements in `slice`.
481    ///
482    /// # Panics
483    ///
484    /// Panics if `slice` is less than 9 elements long.
485    #[inline]
486    pub fn write_cols_to_slice(&self, slice: &mut [f32]) {
487        slice[0] = self.x_axis.x;
488        slice[1] = self.x_axis.y;
489        slice[2] = self.x_axis.z;
490        slice[3] = self.y_axis.x;
491        slice[4] = self.y_axis.y;
492        slice[5] = self.y_axis.z;
493        slice[6] = self.z_axis.x;
494        slice[7] = self.z_axis.y;
495        slice[8] = self.z_axis.z;
496    }
497
498    /// Returns the matrix column for the given `index`.
499    ///
500    /// # Panics
501    ///
502    /// Panics if `index` is greater than 2.
503    #[inline]
504    #[must_use]
505    pub fn col(&self, index: usize) -> Vec3A {
506        match index {
507            0 => self.x_axis,
508            1 => self.y_axis,
509            2 => self.z_axis,
510            _ => panic!("index out of bounds"),
511        }
512    }
513
514    /// Returns a mutable reference to the matrix column for the given `index`.
515    ///
516    /// # Panics
517    ///
518    /// Panics if `index` is greater than 2.
519    #[inline]
520    pub fn col_mut(&mut self, index: usize) -> &mut Vec3A {
521        match index {
522            0 => &mut self.x_axis,
523            1 => &mut self.y_axis,
524            2 => &mut self.z_axis,
525            _ => panic!("index out of bounds"),
526        }
527    }
528
529    /// Returns the matrix row for the given `index`.
530    ///
531    /// # Panics
532    ///
533    /// Panics if `index` is greater than 2.
534    #[inline]
535    #[must_use]
536    pub fn row(&self, index: usize) -> Vec3A {
537        match index {
538            0 => Vec3A::new(self.x_axis.x, self.y_axis.x, self.z_axis.x),
539            1 => Vec3A::new(self.x_axis.y, self.y_axis.y, self.z_axis.y),
540            2 => Vec3A::new(self.x_axis.z, self.y_axis.z, self.z_axis.z),
541            _ => panic!("index out of bounds"),
542        }
543    }
544
545    /// Returns `true` if, and only if, all elements are finite.
546    /// If any element is either `NaN`, positive or negative infinity, this will return `false`.
547    #[inline]
548    #[must_use]
549    pub fn is_finite(&self) -> bool {
550        self.x_axis.is_finite() && self.y_axis.is_finite() && self.z_axis.is_finite()
551    }
552
553    /// Returns `true` if any elements are `NaN`.
554    #[inline]
555    #[must_use]
556    pub fn is_nan(&self) -> bool {
557        self.x_axis.is_nan() || self.y_axis.is_nan() || self.z_axis.is_nan()
558    }
559
560    /// Returns the transpose of `self`.
561    #[inline]
562    #[must_use]
563    pub fn transpose(&self) -> Self {
564        let x = self.x_axis.0;
565        let y = self.y_axis.0;
566        let z = self.z_axis.0;
567        unsafe {
568            let tmp0 = vreinterpretq_f32_u64(vsetq_lane_u64(
569                vgetq_lane_u64(vreinterpretq_u64_f32(y), 0),
570                vreinterpretq_u64_f32(x),
571                1,
572            ));
573            let tmp1 = vreinterpretq_f32_u64(vzip2q_u64(
574                vreinterpretq_u64_f32(x),
575                vreinterpretq_u64_f32(y),
576            ));
577            Mat3A::from_cols(
578                Vec3A::from(vsetq_lane_f32(vgetq_lane_f32(z, 0), vuzp1q_f32(tmp0, z), 3)),
579                Vec3A::from(vuzp2q_f32(tmp0, vdupq_laneq_f32(z, 1))),
580                Vec3A::from(vsetq_lane_f32(vgetq_lane_f32(z, 2), vuzp1q_f32(tmp1, z), 2)),
581            )
582        }
583    }
584
585    /// Returns the diagonal of `self`.
586    #[inline]
587    #[must_use]
588    pub fn diagonal(&self) -> Vec3A {
589        Vec3A::new(self.x_axis.x, self.y_axis.y, self.z_axis.z)
590    }
591
592    /// Returns the determinant of `self`.
593    #[inline]
594    #[must_use]
595    pub fn determinant(&self) -> f32 {
596        self.z_axis.dot(self.x_axis.cross(self.y_axis))
597    }
598
599    /// If `CHECKED` is true then if the determinant is zero this function will return a tuple
600    /// containing a zero matrix and false. If the determinant is non zero a tuple containing the
601    /// inverted matrix and true is returned.
602    ///
603    /// If `CHECKED` is false then the determinant is not checked and if it is zero the resulting
604    /// inverted matrix will be invalid. Will panic if the determinant of `self` is zero when
605    /// `glam_assert` is enabled.
606    ///
607    /// A tuple containing the inverted matrix and a bool is used instead of an option here as
608    /// regular Rust enums put the discriminant first which can result in a lot of padding if the
609    /// matrix is aligned.
610    #[inline(always)]
611    #[must_use]
612    fn inverse_checked<const CHECKED: bool>(&self) -> (Self, bool) {
613        let tmp0 = self.y_axis.cross(self.z_axis);
614        let tmp1 = self.z_axis.cross(self.x_axis);
615        let tmp2 = self.x_axis.cross(self.y_axis);
616        let det = self.z_axis.dot(tmp2);
617        if CHECKED {
618            if det == 0.0 {
619                return (Self::ZERO, false);
620            }
621        } else {
622            glam_assert!(det != 0.0);
623        }
624        let inv_det = Vec3A::splat(det.recip());
625        (
626            Self::from_cols(tmp0.mul(inv_det), tmp1.mul(inv_det), tmp2.mul(inv_det)).transpose(),
627            true,
628        )
629    }
630
631    /// Returns the inverse of `self`.
632    ///
633    /// If the matrix is not invertible the returned matrix will be invalid.
634    ///
635    /// # Panics
636    ///
637    /// Will panic if the determinant of `self` is zero when `glam_assert` is enabled.
638    #[inline]
639    #[must_use]
640    pub fn inverse(&self) -> Self {
641        self.inverse_checked::<false>().0
642    }
643
644    /// Returns the inverse of `self` or `None` if the matrix is not invertible.
645    #[inline]
646    #[must_use]
647    pub fn try_inverse(&self) -> Option<Self> {
648        let (m, is_valid) = self.inverse_checked::<true>();
649        if is_valid {
650            Some(m)
651        } else {
652            None
653        }
654    }
655
656    /// Returns the inverse of `self` or `Mat3A::ZERO` if the matrix is not invertible.
657    #[inline]
658    #[must_use]
659    pub fn inverse_or_zero(&self) -> Self {
660        self.inverse_checked::<true>().0
661    }
662
663    /// Transforms the given 2D vector as a point.
664    ///
665    /// This is the equivalent of multiplying `rhs` as a 3D vector where `z` is `1`.
666    ///
667    /// This method assumes that `self` contains a valid affine transform.
668    ///
669    /// # Panics
670    ///
671    /// Will panic if the 2nd row of `self` is not `(0, 0, 1)` when `glam_assert` is enabled.
672    #[inline]
673    #[must_use]
674    pub fn transform_point2(&self, rhs: Vec2) -> Vec2 {
675        glam_assert!(self.row(2).abs_diff_eq(Vec3A::Z, 1e-6));
676        Mat2::from_cols(self.x_axis.xy(), self.y_axis.xy()) * rhs + self.z_axis.xy()
677    }
678
679    /// Rotates the given 2D vector.
680    ///
681    /// This is the equivalent of multiplying `rhs` as a 3D vector where `z` is `0`.
682    ///
683    /// This method assumes that `self` contains a valid affine transform.
684    ///
685    /// # Panics
686    ///
687    /// Will panic if the 2nd row of `self` is not `(0, 0, 1)` when `glam_assert` is enabled.
688    #[inline]
689    #[must_use]
690    pub fn transform_vector2(&self, rhs: Vec2) -> Vec2 {
691        glam_assert!(self.row(2).abs_diff_eq(Vec3A::Z, 1e-6));
692        Mat2::from_cols(self.x_axis.xy(), self.y_axis.xy()) * rhs
693    }
694
695    /// Creates a left-handed view matrix using a facing direction and an up direction.
696    ///
697    /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=forward`.
698    ///
699    /// # Panics
700    ///
701    /// Will panic if `dir` or `up` are not normalized when `glam_assert` is enabled.
702    #[deprecated(
703        since = "0.33.1",
704        note = "use the `glam::camera::lh::view::look_to_mat3` function instead"
705    )]
706    #[inline]
707    #[must_use]
708    pub fn look_to_lh(dir: Vec3, up: Vec3) -> Self {
709        #[allow(deprecated)]
710        Self::look_to_rh(-dir, up)
711    }
712
713    /// Creates a right-handed view matrix using a facing direction and an up direction.
714    ///
715    /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=back`.
716    ///
717    /// # Panics
718    ///
719    /// Will panic if `dir` or `up` are not normalized when `glam_assert` is enabled.
720    #[deprecated(
721        since = "0.33.1",
722        note = "use the `glam::camera::rh::view::look_to_mat3` function instead"
723    )]
724    #[inline]
725    #[must_use]
726    pub fn look_to_rh(dir: Vec3, up: Vec3) -> Self {
727        glam_assert!(dir.is_normalized());
728        glam_assert!(up.is_normalized());
729        let f = dir;
730        let s = f.cross(up).normalize();
731        let u = s.cross(f);
732
733        Self::from_cols(
734            Vec3A::new(s.x, u.x, -f.x),
735            Vec3A::new(s.y, u.y, -f.y),
736            Vec3A::new(s.z, u.z, -f.z),
737        )
738    }
739
740    /// Creates a left-handed view matrix using a camera position, a focal point and an up
741    /// direction.
742    ///
743    /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=forward`.
744    ///
745    /// # Panics
746    ///
747    /// Will panic if `up` is not normalized when `glam_assert` is enabled.
748    #[deprecated(
749        since = "0.33.1",
750        note = "use the `glam::camera::lh::view::look_at_mat3` function instead"
751    )]
752    #[inline]
753    #[must_use]
754    pub fn look_at_lh(eye: Vec3, center: Vec3, up: Vec3) -> Self {
755        #[allow(deprecated)]
756        Self::look_to_lh(center.sub(eye).normalize(), up)
757    }
758
759    /// Creates a right-handed view matrix using a camera position, a focal point and an up
760    /// direction.
761    ///
762    /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=back`.
763    ///
764    /// # Panics
765    ///
766    /// Will panic if `up` is not normalized when `glam_assert` is enabled.
767    #[deprecated(
768        since = "0.33.1",
769        note = "use the `glam::camera::rh::view::look_at_mat3` function instead"
770    )]
771    #[inline]
772    pub fn look_at_rh(eye: Vec3, center: Vec3, up: Vec3) -> Self {
773        #[allow(deprecated)]
774        Self::look_to_rh(center.sub(eye).normalize(), up)
775    }
776
777    /// Transforms a 3D vector.
778    #[inline]
779    #[must_use]
780    pub fn mul_vec3(&self, rhs: Vec3) -> Vec3 {
781        self.mul_vec3a(rhs.into()).into()
782    }
783
784    /// Transforms a [`Vec3A`].
785    #[inline]
786    #[must_use]
787    pub fn mul_vec3a(&self, rhs: Vec3A) -> Vec3A {
788        let mut res = self.x_axis.mul(rhs.xxx());
789        res = res.add(self.y_axis.mul(rhs.yyy()));
790        res = res.add(self.z_axis.mul(rhs.zzz()));
791        res
792    }
793
794    /// Transforms a 3D vector by the transpose of `self`.
795    #[inline]
796    #[must_use]
797    pub fn mul_transpose_vec3(&self, rhs: Vec3) -> Vec3 {
798        self.mul_transpose_vec3a(rhs.into()).into()
799    }
800
801    /// Transforms a [`Vec3A`] by the transpose of `self`.
802    #[inline]
803    #[must_use]
804    pub fn mul_transpose_vec3a(&self, rhs: Vec3A) -> Vec3A {
805        Vec3A::new(
806            self.x_axis.dot(rhs),
807            self.y_axis.dot(rhs),
808            self.z_axis.dot(rhs),
809        )
810    }
811
812    /// Multiplies two 3x3 matrices.
813    #[inline]
814    #[must_use]
815    pub fn mul_mat3(&self, rhs: &Self) -> Self {
816        self.mul(rhs)
817    }
818
819    /// Adds two 3x3 matrices.
820    #[inline]
821    #[must_use]
822    pub fn add_mat3(&self, rhs: &Self) -> Self {
823        self.add(rhs)
824    }
825
826    /// Subtracts two 3x3 matrices.
827    #[inline]
828    #[must_use]
829    pub fn sub_mat3(&self, rhs: &Self) -> Self {
830        self.sub(rhs)
831    }
832
833    /// Multiplies a 3x3 matrix by a scalar.
834    #[inline]
835    #[must_use]
836    pub fn mul_scalar(&self, rhs: f32) -> Self {
837        Self::from_cols(
838            self.x_axis.mul(rhs),
839            self.y_axis.mul(rhs),
840            self.z_axis.mul(rhs),
841        )
842    }
843
844    /// Multiply `self` by a scaling vector `scale`.
845    /// This is faster than creating a whole diagonal scaling matrix and then multiplying that.
846    /// This operation is commutative.
847    #[inline]
848    #[must_use]
849    pub fn mul_diagonal_scale(&self, scale: Vec3) -> Self {
850        Self::from_cols(
851            self.x_axis * scale.x,
852            self.y_axis * scale.y,
853            self.z_axis * scale.z,
854        )
855    }
856
857    /// Divides a 3x3 matrix by a scalar.
858    #[inline]
859    #[must_use]
860    pub fn div_scalar(&self, rhs: f32) -> Self {
861        let rhs = Vec3A::splat(rhs);
862        Self::from_cols(
863            self.x_axis.div(rhs),
864            self.y_axis.div(rhs),
865            self.z_axis.div(rhs),
866        )
867    }
868
869    /// Returns a matrix containing the reciprocal `1.0/n` of each element of `self`.
870    #[inline]
871    #[must_use]
872    pub fn recip(&self) -> Self {
873        Self::from_cols(
874            self.x_axis.recip(),
875            self.y_axis.recip(),
876            self.z_axis.recip(),
877        )
878    }
879
880    /// Returns true if the absolute difference of all elements between `self` and `rhs`
881    /// is less than or equal to `max_abs_diff`.
882    ///
883    /// This can be used to compare if two matrices contain similar elements. It works best
884    /// when comparing with a known value. The `max_abs_diff` that should be used used
885    /// depends on the values being compared against.
886    ///
887    /// For more see
888    /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/).
889    #[inline]
890    #[must_use]
891    pub fn abs_diff_eq(&self, rhs: Self, max_abs_diff: f32) -> bool {
892        self.x_axis.abs_diff_eq(rhs.x_axis, max_abs_diff)
893            && self.y_axis.abs_diff_eq(rhs.y_axis, max_abs_diff)
894            && self.z_axis.abs_diff_eq(rhs.z_axis, max_abs_diff)
895    }
896
897    /// Takes the absolute value of each element in `self`
898    #[inline]
899    #[must_use]
900    pub fn abs(&self) -> Self {
901        Self::from_cols(self.x_axis.abs(), self.y_axis.abs(), self.z_axis.abs())
902    }
903
904    #[cfg(feature = "f64")]
905    #[inline]
906    #[must_use]
907    pub fn as_dmat3(&self) -> DMat3 {
908        DMat3::from_cols(
909            self.x_axis.as_dvec3(),
910            self.y_axis.as_dvec3(),
911            self.z_axis.as_dvec3(),
912        )
913    }
914}
915
916impl Default for Mat3A {
917    #[inline]
918    fn default() -> Self {
919        Self::IDENTITY
920    }
921}
922
923impl Add for Mat3A {
924    type Output = Self;
925    #[inline]
926    fn add(self, rhs: Self) -> Self {
927        Self::from_cols(
928            self.x_axis.add(rhs.x_axis),
929            self.y_axis.add(rhs.y_axis),
930            self.z_axis.add(rhs.z_axis),
931        )
932    }
933}
934
935impl Add<&Self> for Mat3A {
936    type Output = Self;
937    #[inline]
938    fn add(self, rhs: &Self) -> Self {
939        self.add(*rhs)
940    }
941}
942
943impl Add<&Mat3A> for &Mat3A {
944    type Output = Mat3A;
945    #[inline]
946    fn add(self, rhs: &Mat3A) -> Mat3A {
947        (*self).add(*rhs)
948    }
949}
950
951impl Add<Mat3A> for &Mat3A {
952    type Output = Mat3A;
953    #[inline]
954    fn add(self, rhs: Mat3A) -> Mat3A {
955        (*self).add(rhs)
956    }
957}
958
959impl AddAssign for Mat3A {
960    #[inline]
961    fn add_assign(&mut self, rhs: Self) {
962        *self = self.add(rhs);
963    }
964}
965
966impl AddAssign<&Self> for Mat3A {
967    #[inline]
968    fn add_assign(&mut self, rhs: &Self) {
969        self.add_assign(*rhs);
970    }
971}
972
973impl Sub for Mat3A {
974    type Output = Self;
975    #[inline]
976    fn sub(self, rhs: Self) -> Self {
977        Self::from_cols(
978            self.x_axis.sub(rhs.x_axis),
979            self.y_axis.sub(rhs.y_axis),
980            self.z_axis.sub(rhs.z_axis),
981        )
982    }
983}
984
985impl Sub<&Self> for Mat3A {
986    type Output = Self;
987    #[inline]
988    fn sub(self, rhs: &Self) -> Self {
989        self.sub(*rhs)
990    }
991}
992
993impl Sub<&Mat3A> for &Mat3A {
994    type Output = Mat3A;
995    #[inline]
996    fn sub(self, rhs: &Mat3A) -> Mat3A {
997        (*self).sub(*rhs)
998    }
999}
1000
1001impl Sub<Mat3A> for &Mat3A {
1002    type Output = Mat3A;
1003    #[inline]
1004    fn sub(self, rhs: Mat3A) -> Mat3A {
1005        (*self).sub(rhs)
1006    }
1007}
1008
1009impl SubAssign for Mat3A {
1010    #[inline]
1011    fn sub_assign(&mut self, rhs: Self) {
1012        *self = self.sub(rhs);
1013    }
1014}
1015
1016impl SubAssign<&Self> for Mat3A {
1017    #[inline]
1018    fn sub_assign(&mut self, rhs: &Self) {
1019        self.sub_assign(*rhs);
1020    }
1021}
1022
1023impl Neg for Mat3A {
1024    type Output = Self;
1025    #[inline]
1026    fn neg(self) -> Self::Output {
1027        Self::from_cols(self.x_axis.neg(), self.y_axis.neg(), self.z_axis.neg())
1028    }
1029}
1030
1031impl Neg for &Mat3A {
1032    type Output = Mat3A;
1033    #[inline]
1034    fn neg(self) -> Mat3A {
1035        (*self).neg()
1036    }
1037}
1038
1039impl Mul for Mat3A {
1040    type Output = Self;
1041    #[inline]
1042    fn mul(self, rhs: Self) -> Self {
1043        Self::from_cols(
1044            self.mul(rhs.x_axis),
1045            self.mul(rhs.y_axis),
1046            self.mul(rhs.z_axis),
1047        )
1048    }
1049}
1050
1051impl Mul<&Self> for Mat3A {
1052    type Output = Self;
1053    #[inline]
1054    fn mul(self, rhs: &Self) -> Self {
1055        self.mul(*rhs)
1056    }
1057}
1058
1059impl Mul<&Mat3A> for &Mat3A {
1060    type Output = Mat3A;
1061    #[inline]
1062    fn mul(self, rhs: &Mat3A) -> Mat3A {
1063        (*self).mul(*rhs)
1064    }
1065}
1066
1067impl Mul<Mat3A> for &Mat3A {
1068    type Output = Mat3A;
1069    #[inline]
1070    fn mul(self, rhs: Mat3A) -> Mat3A {
1071        (*self).mul(rhs)
1072    }
1073}
1074
1075impl MulAssign for Mat3A {
1076    #[inline]
1077    fn mul_assign(&mut self, rhs: Self) {
1078        *self = self.mul(rhs);
1079    }
1080}
1081
1082impl MulAssign<&Self> for Mat3A {
1083    #[inline]
1084    fn mul_assign(&mut self, rhs: &Self) {
1085        self.mul_assign(*rhs);
1086    }
1087}
1088
1089impl Mul<Vec3A> for Mat3A {
1090    type Output = Vec3A;
1091    #[inline]
1092    fn mul(self, rhs: Vec3A) -> Self::Output {
1093        self.mul_vec3a(rhs)
1094    }
1095}
1096
1097impl Mul<&Vec3A> for Mat3A {
1098    type Output = Vec3A;
1099    #[inline]
1100    fn mul(self, rhs: &Vec3A) -> Vec3A {
1101        self.mul(*rhs)
1102    }
1103}
1104
1105impl Mul<&Vec3A> for &Mat3A {
1106    type Output = Vec3A;
1107    #[inline]
1108    fn mul(self, rhs: &Vec3A) -> Vec3A {
1109        (*self).mul(*rhs)
1110    }
1111}
1112
1113impl Mul<Vec3A> for &Mat3A {
1114    type Output = Vec3A;
1115    #[inline]
1116    fn mul(self, rhs: Vec3A) -> Vec3A {
1117        (*self).mul(rhs)
1118    }
1119}
1120
1121impl Mul<Mat3A> for f32 {
1122    type Output = Mat3A;
1123    #[inline]
1124    fn mul(self, rhs: Mat3A) -> Self::Output {
1125        rhs.mul_scalar(self)
1126    }
1127}
1128
1129impl Mul<&Mat3A> for f32 {
1130    type Output = Mat3A;
1131    #[inline]
1132    fn mul(self, rhs: &Mat3A) -> Mat3A {
1133        self.mul(*rhs)
1134    }
1135}
1136
1137impl Mul<&Mat3A> for &f32 {
1138    type Output = Mat3A;
1139    #[inline]
1140    fn mul(self, rhs: &Mat3A) -> Mat3A {
1141        (*self).mul(*rhs)
1142    }
1143}
1144
1145impl Mul<Mat3A> for &f32 {
1146    type Output = Mat3A;
1147    #[inline]
1148    fn mul(self, rhs: Mat3A) -> Mat3A {
1149        (*self).mul(rhs)
1150    }
1151}
1152
1153impl Mul<f32> for Mat3A {
1154    type Output = Self;
1155    #[inline]
1156    fn mul(self, rhs: f32) -> Self {
1157        self.mul_scalar(rhs)
1158    }
1159}
1160
1161impl Mul<&f32> for Mat3A {
1162    type Output = Self;
1163    #[inline]
1164    fn mul(self, rhs: &f32) -> Self {
1165        self.mul(*rhs)
1166    }
1167}
1168
1169impl Mul<&f32> for &Mat3A {
1170    type Output = Mat3A;
1171    #[inline]
1172    fn mul(self, rhs: &f32) -> Mat3A {
1173        (*self).mul(*rhs)
1174    }
1175}
1176
1177impl Mul<f32> for &Mat3A {
1178    type Output = Mat3A;
1179    #[inline]
1180    fn mul(self, rhs: f32) -> Mat3A {
1181        (*self).mul(rhs)
1182    }
1183}
1184
1185impl MulAssign<f32> for Mat3A {
1186    #[inline]
1187    fn mul_assign(&mut self, rhs: f32) {
1188        *self = self.mul(rhs);
1189    }
1190}
1191
1192impl MulAssign<&f32> for Mat3A {
1193    #[inline]
1194    fn mul_assign(&mut self, rhs: &f32) {
1195        self.mul_assign(*rhs);
1196    }
1197}
1198
1199impl Div<Mat3A> for f32 {
1200    type Output = Mat3A;
1201    #[inline]
1202    fn div(self, rhs: Mat3A) -> Self::Output {
1203        Mat3A::from_cols(
1204            self.div(rhs.x_axis),
1205            self.div(rhs.y_axis),
1206            self.div(rhs.z_axis),
1207        )
1208    }
1209}
1210
1211impl Div<&Mat3A> for f32 {
1212    type Output = Mat3A;
1213    #[inline]
1214    fn div(self, rhs: &Mat3A) -> Mat3A {
1215        self.div(*rhs)
1216    }
1217}
1218
1219impl Div<&Mat3A> for &f32 {
1220    type Output = Mat3A;
1221    #[inline]
1222    fn div(self, rhs: &Mat3A) -> Mat3A {
1223        (*self).div(*rhs)
1224    }
1225}
1226
1227impl Div<Mat3A> for &f32 {
1228    type Output = Mat3A;
1229    #[inline]
1230    fn div(self, rhs: Mat3A) -> Mat3A {
1231        (*self).div(rhs)
1232    }
1233}
1234
1235impl Div<f32> for Mat3A {
1236    type Output = Self;
1237    #[inline]
1238    fn div(self, rhs: f32) -> Self {
1239        self.div_scalar(rhs)
1240    }
1241}
1242
1243impl Div<&f32> for Mat3A {
1244    type Output = Self;
1245    #[inline]
1246    fn div(self, rhs: &f32) -> Self {
1247        self.div(*rhs)
1248    }
1249}
1250
1251impl Div<&f32> for &Mat3A {
1252    type Output = Mat3A;
1253    #[inline]
1254    fn div(self, rhs: &f32) -> Mat3A {
1255        (*self).div(*rhs)
1256    }
1257}
1258
1259impl Div<f32> for &Mat3A {
1260    type Output = Mat3A;
1261    #[inline]
1262    fn div(self, rhs: f32) -> Mat3A {
1263        (*self).div(rhs)
1264    }
1265}
1266
1267impl DivAssign<f32> for Mat3A {
1268    #[inline]
1269    fn div_assign(&mut self, rhs: f32) {
1270        *self = self.div(rhs);
1271    }
1272}
1273
1274impl DivAssign<&f32> for Mat3A {
1275    #[inline]
1276    fn div_assign(&mut self, rhs: &f32) {
1277        self.div_assign(*rhs);
1278    }
1279}
1280
1281impl Mul<Vec3> for Mat3A {
1282    type Output = Vec3;
1283    #[inline]
1284    fn mul(self, rhs: Vec3) -> Vec3 {
1285        self.mul_vec3a(rhs.into()).into()
1286    }
1287}
1288
1289impl Mul<&Vec3> for Mat3A {
1290    type Output = Vec3;
1291    #[inline]
1292    fn mul(self, rhs: &Vec3) -> Vec3 {
1293        self.mul(*rhs)
1294    }
1295}
1296
1297impl Mul<&Vec3> for &Mat3A {
1298    type Output = Vec3;
1299    #[inline]
1300    fn mul(self, rhs: &Vec3) -> Vec3 {
1301        (*self).mul(*rhs)
1302    }
1303}
1304
1305impl Mul<Vec3> for &Mat3A {
1306    type Output = Vec3;
1307    #[inline]
1308    fn mul(self, rhs: Vec3) -> Vec3 {
1309        (*self).mul(rhs)
1310    }
1311}
1312
1313impl From<Mat3> for Mat3A {
1314    #[inline]
1315    fn from(m: Mat3) -> Self {
1316        Self {
1317            x_axis: m.x_axis.into(),
1318            y_axis: m.y_axis.into(),
1319            z_axis: m.z_axis.into(),
1320        }
1321    }
1322}
1323
1324impl Sum<Self> for Mat3A {
1325    fn sum<I>(iter: I) -> Self
1326    where
1327        I: Iterator<Item = Self>,
1328    {
1329        iter.fold(Self::ZERO, Self::add)
1330    }
1331}
1332
1333impl<'a> Sum<&'a Self> for Mat3A {
1334    fn sum<I>(iter: I) -> Self
1335    where
1336        I: Iterator<Item = &'a Self>,
1337    {
1338        iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
1339    }
1340}
1341
1342impl Product for Mat3A {
1343    fn product<I>(iter: I) -> Self
1344    where
1345        I: Iterator<Item = Self>,
1346    {
1347        iter.fold(Self::IDENTITY, Self::mul)
1348    }
1349}
1350
1351impl<'a> Product<&'a Self> for Mat3A {
1352    fn product<I>(iter: I) -> Self
1353    where
1354        I: Iterator<Item = &'a Self>,
1355    {
1356        iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b))
1357    }
1358}
1359
1360impl PartialEq for Mat3A {
1361    #[inline]
1362    fn eq(&self, rhs: &Self) -> bool {
1363        self.x_axis.eq(&rhs.x_axis) && self.y_axis.eq(&rhs.y_axis) && self.z_axis.eq(&rhs.z_axis)
1364    }
1365}
1366
1367impl fmt::Debug for Mat3A {
1368    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
1369        fmt.debug_struct(stringify!(Mat3A))
1370            .field("x_axis", &self.x_axis)
1371            .field("y_axis", &self.y_axis)
1372            .field("z_axis", &self.z_axis)
1373            .finish()
1374    }
1375}
1376
1377impl fmt::Display for Mat3A {
1378    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1379        if let Some(p) = f.precision() {
1380            write!(
1381                f,
1382                "[{:.*}, {:.*}, {:.*}]",
1383                p, self.x_axis, p, self.y_axis, p, self.z_axis
1384            )
1385        } else {
1386            write!(f, "[{}, {}, {}]", self.x_axis, self.y_axis, self.z_axis)
1387        }
1388    }
1389}