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.

use crate::nums::{Float, Signed};
use crate::{Cross, Dot, Vec3};

/// Dot trait for Vec3Dim1 and Vec3Dim2
pub trait DotExternal {
    fn dot_ext(&self, other: Vec3) -> f32;
}

/// Cross trait for Vec3Dim1 and Vec3Dim2
/// Output is Vec3 for Vec3Dim2 or Vec3OnlyXy, Vec3OnlyXz, Vec3OnlyYz
/// Output is Vec3Dim2 for Vec3Dim1
/// so we let Output be a associated type
pub trait CrossExternal {
    type Output: DotExternal + CrossExternal + AbsExternal;

    fn cross_ext(&self, other: Vec3) -> Self::Output;
}
/// let the 'normalize_and_length' to be a trait
/// so we can impl it for Vec3Dim1 and Vec3Dim2
/// and then can get a better performance
pub trait NormalizeAndLengthExternal {
    fn normalize_and_length_ext(&self) -> (Self, f32)
    where
        Self: Sized;
}

/// let the 'abs' to be a trait
/// so we can impl it for Vec3Dim1 and Vec3Dim2
/// and then can get a better performance
pub trait AbsExternal {
    fn abs_ext(&self) -> Self;
}

impl AbsExternal for Vec3 {
    #[inline]
    fn abs_ext(&self) -> Self {
        Vec3::abs(*self)
    }
}
impl DotExternal for Vec3 {
    #[inline]
    fn dot_ext(&self, other: Vec3) -> f32 {
        Dot::dot(*self, other)
    }
}
impl CrossExternal for Vec3 {
    type Output = Vec3;

    #[inline]
    fn cross_ext(&self, other: Vec3) -> Vec3 {
        Cross::cross(*self, other)
    }
}

impl NormalizeAndLengthExternal for Vec3 {
    #[inline]
    fn normalize_and_length_ext(&self) -> (Self, f32) {
        let (normalized, length) = Vec3::normalize_and_length(*self);
        (normalized, length)
    }
}

pub struct Vec3Dim1<const AXIS: usize> {
    v: f32,
}

impl<const AXIS: usize> DotExternal for Vec3Dim1<AXIS> {
    #[inline]
    fn dot_ext(&self, other: Vec3) -> f32 {
        self.v * other[AXIS]
    }
}

impl<const AXIS: usize> AbsExternal for Vec3Dim1<AXIS> {
    #[inline]
    fn abs_ext(&self) -> Self {
        Self { v: self.v.absf() }
    }
}
impl<const AXIS: usize> NormalizeAndLengthExternal for Vec3Dim1<AXIS> {
    #[inline]
    fn normalize_and_length_ext(&self) -> (Self, f32) {
        let length = self.v.absf();
        let inv_length = length.recip();
        (Self::new(self.v * inv_length), length)
    }
}

impl<const AXIS: usize> Vec3Dim1<AXIS> {
    #[inline]
    pub fn new(v: f32) -> Self {
        Self { v }
    }
}
/// Vec3OnlyX is a Vec3Dim1 with AXIS = 0,that means it only has x value
/// and the 'dot' , 'cross' ,'abs','normalize_and_length' operation is only related to x value
/// so we can get a better performance
pub type Vec3OnlyX = Vec3Dim1<0>;

impl Vec3OnlyX {
    #[inline]
    pub fn x(&self) -> f32 {
        self.v
    }
}
impl CrossExternal for Vec3OnlyX {
    type Output = Vec3OnlyYZ;

    #[inline]
    fn cross_ext(&self, other: Vec3) -> Vec3OnlyYZ {
        Vec3OnlyYZ::new(-self.v * other.z, self.v * other.y)
    }
}

/// Vec3OnlyY is a Vec3Dim1 with AXIS = 1,that means it only has y value
/// and the 'dot' , 'cross' ,'abs','normalize_and_length' operation is only related to y value
/// so we can get a better performance
pub type Vec3OnlyY = Vec3Dim1<1>;

impl Vec3OnlyY {
    #[inline]
    pub fn y(&self) -> f32 {
        self.v
    }
}

impl CrossExternal for Vec3OnlyY {
    type Output = Vec3OnlyXZ;

    #[inline]
    fn cross_ext(&self, other: Vec3) -> Vec3OnlyXZ {
        Vec3OnlyXZ::new(self.v * other.z, -self.v * other.x)
    }
}

/// Vec3OnlyZ is a Vec3Dim1 with AXIS = 2,that means it only has z value
/// and the 'dot' , 'cross' ,'abs','normalize_and_length' operation is only related to z value
/// so we can get a better performance
pub type Vec3OnlyZ = Vec3Dim1<2>;

impl Vec3OnlyZ {
    #[inline]
    pub fn z(&self) -> f32 {
        self.v
    }
}

impl CrossExternal for Vec3OnlyZ {
    type Output = Vec3OnlyXY;

    #[inline]
    fn cross_ext(&self, other: Vec3) -> Vec3OnlyXY {
        Vec3OnlyXY::new(-self.v * other.y, self.v * other.x)
    }
}

pub struct Vec3Dim2<const AXIS0: usize, const AXIS1: usize> {
    value: [f32; 2],
}

impl<const AXIS0: usize, const AXIS1: usize> AbsExternal for Vec3Dim2<AXIS0, AXIS1> {
    #[inline]
    fn abs_ext(&self) -> Self {
        let v0 = self.value[0].absf();
        let v1 = self.value[1].absf();
        Self { value: [v0, v1] }
    }
}

impl<const AXIS0: usize, const AXIS1: usize> DotExternal for Vec3Dim2<AXIS0, AXIS1> {
    #[inline]
    fn dot_ext(&self, other: Vec3) -> f32 {
        self.value[0] * other[AXIS0] + self.value[1] * other[AXIS1]
    }
}
/// Vec3OnlyXy is a Vec3Dim2 with AXIS0 and AXIS1,that means it only has x and y value
/// and the 'dot' , 'cross' ,'abs','normalize_and_length' operation is only related to x and y value
/// so we can get a better performance
pub type Vec3OnlyXY = Vec3Dim2<0, 1>;

impl Vec3OnlyXY {
    #[inline]
    pub fn x(&self) -> f32 {
        self.value[0]
    }

    #[inline]
    pub fn y(&self) -> f32 {
        self.value[1]
    }
}
impl CrossExternal for Vec3OnlyXY {
    type Output = Vec3;

    #[inline]
    fn cross_ext(&self, other: Vec3) -> Vec3 {
        Vec3::new(
            self.value[1] * other.z,
            -self.value[0] * other.z,
            self.value[0] * other.y - self.value[1] * other.x,
        )
    }
}

impl<const AXIS0: usize, const AXIS1: usize> NormalizeAndLengthExternal for Vec3Dim2<AXIS0, AXIS1> {
    #[inline]
    fn normalize_and_length_ext(&self) -> (Self, f32)
    where
        Self: Sized,
    {
        let length = (self.value[0] * self.value[0] + self.value[1] * self.value[1]).sqrtf();
        let inv_length = length.recip();
        (
            Self::new(self.value[0] * inv_length, self.value[1] * inv_length),
            length,
        )
    }
}

impl<const AXIS0: usize, const AXIS1: usize> Vec3Dim2<AXIS0, AXIS1> {
    #[inline]
    pub fn new(v0: f32, v1: f32) -> Self {
        Self { value: [v0, v1] }
    }
}

/// Vec3OnlyXz is a Vec3Dim2 with AXIS0 = 0, AXIS1 = 2,that means it only has x and z value
/// and the 'dot' , 'cross' ,'abs','normalize_and_length' operation is only related to x and z value
/// so we can get a better performance
pub type Vec3OnlyXZ = Vec3Dim2<0, 2>;

impl Vec3OnlyXZ {
    #[inline]
    pub fn x(&self) -> f32 {
        self.value[0]
    }

    #[inline]
    pub fn z(&self) -> f32 {
        self.value[1]
    }
}

impl CrossExternal for Vec3OnlyXZ {
    type Output = Vec3;

    #[inline]
    fn cross_ext(&self, other: Vec3) -> Vec3 {
        Vec3::new(
            -self.value[1] * other.y,
            self.value[1] * other.x - self.value[0] * other.z,
            self.value[0] * other.y,
        )
    }
}

/// Vec3OnlyYz is a Vec3Dim2 with AXIS0 = 1, AXIS1 = 2,that means it only has y and z value
/// and the 'dot' , 'cross' ,'abs','normalize_and_length' operation is only related to y and z value
/// so we can get a better performance
pub type Vec3OnlyYZ = Vec3Dim2<1, 2>;

impl Vec3OnlyYZ {
    #[inline]
    pub fn y(&self) -> f32 {
        self.value[0]
    }

    #[inline]
    pub fn z(&self) -> f32 {
        self.value[1]
    }
}

impl CrossExternal for Vec3OnlyYZ {
    type Output = Vec3;

    #[inline]
    fn cross_ext(&self, other: Vec3) -> Vec3 {
        Vec3::new(
            self.value[0] * other.z - self.value[1] * other.y,
            self.value[1] * other.x,
            -self.value[0] * other.x,
        )
    }
}