glam_det 2.0.0

A simple and fast 3D math library for games and graphics.
Documentation
// Copyright (C) 2020-2025 glam-det authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Generated from affine.rs.tera template. Edit the template, not the generated file.

use crate::{Affine3A, Mat4, Point3, Point3A, UnitQuat, UnitVec3, Vec3, Vec3A};
use auto_ops_det::impl_op_ex;
use core::ops;

/// A 3D isometry transform, which can represent translation, rotation.
#[derive(Copy, Clone)]
#[repr(C)]
#[repr(align(16))]
pub struct Isometry3 {
    pub rotation: UnitQuat,
    pub translation: Vec3,
}

impl Isometry3 {
    /// The identity transform.
    ///
    /// Multiplying a vector with this returns the same vector.
    pub const IDENTITY: Self = Self {
        rotation: UnitQuat::IDENTITY,
        translation: Vec3::ZERO,
    };

    /// Creates an isomtry transform from a `[f32; 7]` array stored in column major order.
    #[inline]
    pub fn from_array_unchecked(m: &[f32; 7]) -> Self {
        Self {
            rotation: UnitQuat::from_slice_unchecked(&m[0..4]),
            translation: Vec3::from_slice(&m[4..7]),
        }
    }

    /// Creates a `[f32; 7]` array storing data in column major order.
    #[inline]
    pub fn to_array(&self) -> [f32; 7] {
        [
            self.rotation.x,
            self.rotation.y,
            self.rotation.z,
            self.rotation.w,
            self.translation.x,
            self.translation.y,
            self.translation.z,
        ]
    }

    /// Creates an isometry transform from the first 7 values in `slice`.
    ///
    /// # Panics
    ///
    /// Panics if `slice` is less than 7 elements long.
    #[inline]
    pub fn from_slice_unchecked(slice: &[f32]) -> Self {
        Self {
            rotation: UnitQuat::from_slice_unchecked(&slice[0..4]),
            translation: Vec3::from_slice(&slice[4..7]),
        }
    }

    /// Writes the columns of `self` to the first 7 elements in `slice`.
    ///
    /// # Panics
    ///
    /// Panics if `slice` is less than 7 elements long.
    #[inline]
    pub fn write_to_slice(self, slice: &mut [f32]) {
        self.rotation.write_to_slice(&mut slice[0..4]);
        self.translation.write_to_slice(&mut slice[4..7]);
    }

    /// Creates an isometry transform from the given `rotation` quaternion.
    #[inline]
    pub fn from_quat(rotation: UnitQuat) -> Self {
        Self {
            rotation,
            translation: Vec3::ZERO,
        }
    }

    /// Creates an isometry transform containing a 3D rotation around a normalized
    /// rotation `axis` of `angle` (in radians).
    #[inline]
    pub fn from_axis_angle(axis: UnitVec3, angle: f32) -> Self {
        Self {
            rotation: UnitQuat::from_axis_angle(axis, angle),
            translation: Vec3::ZERO,
        }
    }

    /// Creates an isometry transform containing a 3D rotation around the x axis of
    /// `angle` (in radians).
    #[inline]
    pub fn from_rotation_x(angle: f32) -> Self {
        Self {
            rotation: UnitQuat::from_rotation_x(angle),
            translation: Vec3::ZERO,
        }
    }

    /// Creates an isometry transform containing a 3D rotation around the y axis of
    /// `angle` (in radians).
    #[inline]
    pub fn from_rotation_y(angle: f32) -> Self {
        Self {
            rotation: UnitQuat::from_rotation_y(angle),
            translation: Vec3::ZERO,
        }
    }

    /// Creates an isometry transform containing a 3D rotation around the z axis of
    /// `angle` (in radians).
    #[inline]
    pub fn from_rotation_z(angle: f32) -> Self {
        Self {
            rotation: UnitQuat::from_rotation_z(angle),

            translation: Vec3::ZERO,
        }
    }

    /// Creates an affine transformation from the given 3D `translation`.
    #[inline]
    pub fn from_translation(translation: Vec3) -> Self {
        #[allow(clippy::useless_conversion)]
        Self {
            rotation: UnitQuat::IDENTITY,
            translation: translation.into(),
        }
    }

    /// Creates an isometry transform from the given 3D `rotation` and `translation`.
    ///
    /// Equivalent to `Isometry3::from_translation(translation) * Isometry3::from_quat(rotation)`
    #[inline]
    pub fn from_rotation_translation(rotation: UnitQuat, translation: Vec3) -> Self {
        #[allow(clippy::useless_conversion)]
        Self {
            rotation,
            translation: translation.into(),
        }
    }

    /// Extracts `rotation` and `translation` from `self`.
    #[inline]
    pub fn to_rotation_translation(&self) -> (UnitQuat, Vec3) {
        (self.rotation, self.translation)
    }

    /// Transforms the given 3D points, applying rotation and translation.
    #[inline]
    pub fn transform_point3(&self, rhs: Point3) -> Point3 {
        Point3(self.rotation.mul_vec3(rhs.0) + self.translation)
    }

    /// Transform the given point by the inverse of this isometry. This may be
    /// less expensive than computing the entire isometry inverse and then
    /// transforming the point.
    pub fn inverse_transform_point3(&self, rhs: Point3) -> Point3 {
        Point3(self.rotation.inverse() * (rhs.0 - self.translation))
    }

    /// Transforms the given 3D vector, applying rotation (but NOT translation).
    #[inline]
    pub fn transform_vector3(&self, rhs: Vec3) -> Vec3 {
        self.rotation.mul_vec3(rhs)
    }

    /// Transforms the given `Point3A`, applying rotation and translation.
    #[inline]
    pub fn transform_point3a(&self, rhs: Point3A) -> Point3A {
        Point3A(self.rotation.mul_vec3a(rhs.0) + Vec3A::from(self.translation))
    }

    /// Transform the given point by the inverse of this isometry. This may be
    /// less expensive than computing the entire isometry inverse and then
    /// transforming the point.
    pub fn inverse_transform_point3a(&self, rhs: Point3A) -> Point3A {
        Point3A(self.rotation.inverse() * (rhs.0 - Vec3A::from(self.translation)))
    }

    /// Transforms the given `Vec3A`, applying rotation (but NOT translation).
    #[inline]
    pub fn transform_vector3a(&self, rhs: Vec3A) -> Vec3A {
        self.rotation.mul_vec3a(rhs)
    }

    /// Returns `true` if, and only if, all elements are finite.
    ///
    /// If any element is either `NaN`, positive or negative infinity, this will return
    /// `false`.
    #[inline]
    pub fn is_finite(&self) -> bool {
        self.translation.is_finite()
    }

    /// Returns `true` if any elements are `NaN`.
    #[inline]
    pub fn is_nan(&self) -> bool {
        self.translation.is_nan()
    }

    /// Returns true if the absolute difference of all elements between `self` and `rhs`
    /// is less than or equal to `max_abs_diff`.
    ///
    /// The `max_abs_diff` that should be used depends on the values being compared against.
    ///
    /// For more see
    /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/).
    #[inline]
    pub fn abs_diff_eq(&self, rhs: Self, max_abs_diff: f32) -> bool {
        self.rotation.abs_diff_eq(rhs.rotation, max_abs_diff)
            && self.translation.abs_diff_eq(rhs.translation, max_abs_diff)
    }

    /// Return the inverse of this transform.
    #[must_use]
    #[inline]
    pub fn inverse(&self) -> Self {
        let rotation = self.rotation.inverse();
        // transform negative translation by the matrix inverse:
        let translation = -(rotation * self.translation);

        Self {
            rotation,
            translation,
        }
    }
}

impl Default for Isometry3 {
    #[inline]
    fn default() -> Self {
        Self::IDENTITY
    }
}

impl PartialEq for Isometry3 {
    #[inline]
    fn eq(&self, rhs: &Self) -> bool {
        self.rotation.eq(&rhs.rotation) && self.translation.eq(&rhs.translation)
    }
}

#[cfg(not(target_arch = "spirv"))]
impl core::fmt::Debug for Isometry3 {
    fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        fmt.debug_struct(stringify!(Isometry3))
            .field("UnitQuat", &self.rotation)
            .field("translation", &self.translation)
            .finish()
    }
}

#[cfg(not(target_arch = "spirv"))]
impl core::fmt::Display for Isometry3 {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        write!(f, "[{}, {}]", self.rotation, self.translation)
    }
}

impl<'a> core::iter::Product<&'a Self> for Isometry3 {
    fn product<I>(iter: I) -> Self
    where
        I: Iterator<Item = &'a Self>,
    {
        iter.fold(Self::IDENTITY, |a, &b| a * b)
    }
}

impl_op_ex!(*|a: &Isometry3, b: &Isometry3| -> Isometry3 {
    Isometry3 {
        rotation: a.rotation * b.rotation,
        translation: a.rotation * b.translation + a.translation,
    }
});

impl From<Isometry3> for Affine3A {
    #[inline]
    fn from(iso: Isometry3) -> Affine3A {
        Affine3A::from_scale_rotation_translation(Vec3::ONE, iso.rotation, iso.translation)
    }
}

impl From<&Isometry3> for Affine3A {
    #[inline]
    fn from(iso: &Isometry3) -> Affine3A {
        Affine3A::from_scale_rotation_translation(Vec3::ONE, iso.rotation, iso.translation)
    }
}

impl From<Isometry3> for Mat4 {
    #[inline]
    fn from(iso: Isometry3) -> Mat4 {
        Mat4::from(Affine3A::from(iso))
    }
}

impl From<&Isometry3> for Mat4 {
    #[inline]
    fn from(iso: &Isometry3) -> Mat4 {
        Mat4::from(Affine3A::from(iso))
    }
}

impl_op_ex!(*|a: &Isometry3, b: &Affine3A| -> Affine3A { Affine3A::from(a) * b });
impl_op_ex!(*|a: &Affine3A, b: &Isometry3| -> Affine3A { a * Affine3A::from(b) });
impl_op_ex!(*|a: &Isometry3, b: &Vec3| -> Vec3 { a.rotation * b });
impl_op_ex!(*|a: &Isometry3, b: &UnitVec3| -> UnitVec3 { a.rotation * b });
impl_op_ex!(*|a: &Isometry3, b: &Point3| -> Point3 { a.transform_point3(*b) });

impl_op_ex!(*|a: &Isometry3, b: &Mat4| -> Mat4 { Mat4::from(a) * b });
impl_op_ex!(*|a: &Mat4, b: &Isometry3| -> Mat4 { a * Mat4::from(b) });

impl_op_ex!(*|a: &Isometry3, b: &Vec3A| -> Vec3A { a.rotation * b });
impl_op_ex!(*|a: &Isometry3, b: &Point3A| -> Point3A { a.transform_point3a(*b) });