use crate::{Scalar, Vec3};
use core::ops::Deref;
#[derive(Clone, Copy, Debug)]
#[repr(transparent)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Dir3<S> {
inner: Vec3<S>,
}
impl<S: Scalar> Dir3<S> {
#[inline]
pub fn new(v: Vec3<S>) -> Self {
Self {
inner: v.normalize(),
}
}
#[inline]
pub fn new_normalize(v: Vec3<S>) -> Self {
Self::new(v)
}
#[inline]
pub fn try_new(v: Vec3<S>) -> Option<Self> {
v.try_normalize().map(|inner| Self { inner })
}
#[inline]
pub fn new_unchecked(v: Vec3<S>) -> Self {
Self { inner: v }
}
#[inline]
pub fn as_vec(&self) -> &Vec3<S> {
&self.inner
}
#[inline]
pub fn into_inner(self) -> Vec3<S> {
self.inner
}
#[inline]
pub fn x() -> Self {
Self { inner: Vec3::x() }
}
#[inline]
pub fn y() -> Self {
Self { inner: Vec3::y() }
}
#[inline]
pub fn z() -> Self {
Self { inner: Vec3::z() }
}
#[inline]
pub fn neg(self) -> Self {
Self { inner: -self.inner }
}
#[inline]
pub fn dot(self, other: Dir3<S>) -> S {
self.inner.dot(other.inner)
}
#[inline]
pub fn cross(self, other: Dir3<S>) -> Vec3<S> {
self.inner.cross(other.inner)
}
}
impl<S: Scalar> core::ops::Neg for Dir3<S> {
type Output = Self;
#[inline]
fn neg(self) -> Self {
Self { inner: -self.inner }
}
}
impl<S: Scalar> Deref for Dir3<S> {
type Target = Vec3<S>;
#[inline]
fn deref(&self) -> &Vec3<S> {
&self.inner
}
}
impl<S: Scalar> AsRef<Vec3<S>> for Dir3<S> {
#[inline]
fn as_ref(&self) -> &Vec3<S> {
&self.inner
}
}
impl<S: Scalar> From<Dir3<S>> for Vec3<S> {
#[inline]
fn from(d: Dir3<S>) -> Vec3<S> {
d.inner
}
}
impl<S: Scalar> From<&Dir3<S>> for Vec3<S> {
#[inline]
fn from(d: &Dir3<S>) -> Vec3<S> {
d.inner
}
}
impl<S: Scalar> PartialEq for Dir3<S> {
fn eq(&self, other: &Self) -> bool {
self.inner == other.inner
}
}
impl<S: Scalar> core::fmt::Display for Dir3<S> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "Dir3{}", self.inner)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn deref_to_vec3() {
let d = Dir3::new(Vec3::new(3.0, 0.0, 0.0));
assert!((d.x - 1.0).abs() < 1e-10);
assert!((d.y).abs() < 1e-10);
assert!((d.norm() - 1.0).abs() < 1e-10);
}
#[test]
fn normalize_on_construct() {
let d = Dir3::new(Vec3::new(1.0, 1.0, 1.0));
assert!((d.norm() - 1.0).abs() < 1e-10);
}
#[test]
fn axis_constructors() {
assert_eq!(Dir3::<f64>::x().into_inner(), Vec3::x());
assert_eq!(Dir3::<f64>::y().into_inner(), Vec3::y());
assert_eq!(Dir3::<f64>::z().into_inner(), Vec3::z());
}
}