use crate::nums::{Float, Signed};
use crate::{Cross, Dot, Vec3};
pub trait DotExternal {
fn dot_ext(&self, other: Vec3) -> f32;
}
pub trait CrossExternal {
type Output: DotExternal + CrossExternal + AbsExternal;
fn cross_ext(&self, other: Vec3) -> Self::Output;
}
pub trait NormalizeAndLengthExternal {
fn normalize_and_length_ext(&self) -> (Self, f32)
where
Self: Sized;
}
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 }
}
}
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)
}
}
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)
}
}
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]
}
}
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] }
}
}
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,
)
}
}
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,
)
}
}