use crate::{vec2::Vec2, vec3::Vec3, vec4::Vec4};
fn try_unit_scale_from_len_sq(len_sq: f32) -> Option<f32> {
if !(len_sq > 0.0) || !len_sq.is_finite() {
return None;
}
let inv_len = 1.0 / crate::math::sqrt(len_sq);
if inv_len.is_finite() {
Some(inv_len)
} else {
None
}
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(transparent))]
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct UnitVec2<Unit: Copy = (), Space: Copy = ()>(Vec2<Unit, Space>);
impl<Unit: Copy, Space: Copy> UnitVec2<Unit, Space> {
pub const X: Self = Self(Vec2::new(1.0, 0.0));
pub const Y: Self = Self(Vec2::new(0.0, 1.0));
#[inline]
pub fn try_new(v: Vec2<Unit, Space>) -> Option<Self> {
let inv_len = try_unit_scale_from_len_sq(v.length_squared())?;
let n = v * inv_len;
if n.x.is_finite() && n.y.is_finite() {
Some(Self(n))
} else {
None
}
}
#[inline]
pub fn new_or_fallback(v: Vec2<Unit, Space>, fallback: Self) -> Self {
Self::try_new(v).unwrap_or(fallback)
}
#[inline]
pub const fn as_vec(self) -> Vec2<Unit, Space> {
self.0
}
#[inline]
pub const fn into_vec(self) -> Vec2<Unit, Space> {
self.0
}
#[inline]
pub const unsafe fn new_unchecked(v: Vec2<Unit, Space>) -> Self {
Self(v)
}
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(transparent))]
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct UnitVec3<Unit: Copy = (), Space: Copy = ()>(Vec3<Unit, Space>);
impl<Unit: Copy, Space: Copy> UnitVec3<Unit, Space> {
pub const X: Self = Self(Vec3::new(1.0, 0.0, 0.0));
pub const Y: Self = Self(Vec3::new(0.0, 1.0, 0.0));
pub const Z: Self = Self(Vec3::new(0.0, 0.0, 1.0));
#[inline]
pub fn try_new(v: Vec3<Unit, Space>) -> Option<Self> {
let inv_len = try_unit_scale_from_len_sq(v.length_squared())?;
let n = v * inv_len;
if n.x.is_finite() && n.y.is_finite() && n.z.is_finite() {
Some(Self(n))
} else {
None
}
}
#[inline]
pub fn new_or_fallback(v: Vec3<Unit, Space>, fallback: Self) -> Self {
Self::try_new(v).unwrap_or(fallback)
}
#[inline]
pub const fn as_vec(self) -> Vec3<Unit, Space> {
self.0
}
#[inline]
pub const fn into_vec(self) -> Vec3<Unit, Space> {
self.0
}
#[inline]
pub const unsafe fn new_unchecked(v: Vec3<Unit, Space>) -> Self {
Self(v)
}
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(transparent))]
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct UnitVec4<Unit: Copy = (), Space: Copy = ()>(Vec4<Unit, Space>);
impl<Unit: Copy, Space: Copy> UnitVec4<Unit, Space> {
pub const X: Self = Self(Vec4::new(1.0, 0.0, 0.0, 0.0));
pub const Y: Self = Self(Vec4::new(0.0, 1.0, 0.0, 0.0));
pub const Z: Self = Self(Vec4::new(0.0, 0.0, 1.0, 0.0));
pub const W: Self = Self(Vec4::new(0.0, 0.0, 0.0, 1.0));
#[inline]
pub fn try_new(v: Vec4<Unit, Space>) -> Option<Self> {
let inv_len = try_unit_scale_from_len_sq(v.length_squared())?;
let n = v * inv_len;
if n.x.is_finite() && n.y.is_finite() && n.z.is_finite() && n.w.is_finite() {
Some(Self(n))
} else {
None
}
}
#[inline]
pub fn new_or_fallback(v: Vec4<Unit, Space>, fallback: Self) -> Self {
Self::try_new(v).unwrap_or(fallback)
}
#[inline]
pub const fn as_vec(self) -> Vec4<Unit, Space> {
self.0
}
#[inline]
pub const fn into_vec(self) -> Vec4<Unit, Space> {
self.0
}
#[inline]
pub const unsafe fn new_unchecked(v: Vec4<Unit, Space>) -> Self {
Self(v)
}
}