use crate::{BVec2, DVec2};
#[cfg(not(target_arch = "spirv"))]
use core::fmt;
use core::ops::*;
use crate::nums::*;
use auto_ops_det::{impl_op_ex, impl_op_ex_commutative};
use core::ops;
union VecUnionCast {
v: DVec2,
uv: UnitDVec2,
}
impl DVec2 {
#[inline]
pub fn as_unit_dvec2_unchecked(self) -> UnitDVec2 {
unsafe { VecUnionCast { v: self }.uv }
}
}
impl UnitDVec2 {
#[inline]
pub fn as_dvec2(self) -> DVec2 {
unsafe { VecUnionCast { uv: self }.v }
}
}
#[derive(Clone, Copy, PartialEq)]
#[cfg_attr(feature = "cuda", repr(align(16)))]
#[cfg_attr(not(target_arch = "spirv"), repr(C))]
#[cfg_attr(target_arch = "spirv", repr(simd))]
pub struct UnitDVec2 {
pub x: f64,
pub y: f64,
}
impl UnitDVec2 {
pub const X: Self = Self::new_unchecked(1.0_f64, 0.0_f64);
pub const Y: Self = Self::new_unchecked(0.0_f64, 1.0_f64);
pub const NEG_X: Self = Self::new_unchecked(-1.0_f64, 0.0_f64);
pub const NEG_Y: Self = Self::new_unchecked(0.0_f64, -1.0_f64);
pub const AXES: [Self; 2] = [Self::X, Self::Y];
#[inline]
pub const fn new_unchecked(x: f64, y: f64) -> Self {
Self { x, y }
}
#[inline]
pub fn new_normalized(x: f64, y: f64) -> Self {
DVec2::new(x, y).normalize().as_unit_dvec2_unchecked()
}
#[inline]
pub fn select(mask: BVec2, if_true: Self, if_false: Self) -> DVec2 {
DVec2::select(mask, if_true.as_dvec2(), if_false.as_dvec2())
}
#[inline]
pub const fn from_array_unchecked(a: [f64; 2]) -> Self {
Self::new_unchecked(a[0], a[1])
}
#[inline]
pub const fn to_array(&self) -> [f64; 2] {
[self.x, self.y]
}
#[inline]
pub const fn from_slice_unchecked(slice: &[f64]) -> Self {
Self::new_unchecked(slice[0], slice[1])
}
#[inline]
pub fn write_to_slice(self, slice: &mut [f64]) {
slice[0] = self.x;
slice[1] = self.y;
}
#[inline]
pub(crate) fn dot(self, rhs: Self) -> f64 {
self.as_dvec2().dot(rhs.as_dvec2())
}
#[inline]
pub fn min_element(self) -> f64 {
self.as_dvec2().min_element()
}
#[inline]
pub fn max_element(self) -> f64 {
self.as_dvec2().max_element()
}
#[inline]
pub fn cmpeq(self, rhs: Self) -> BVec2 {
self.as_dvec2().cmpeq(rhs.as_dvec2())
}
#[inline]
pub fn cmpne(self, rhs: Self) -> BVec2 {
self.as_dvec2().cmpne(rhs.as_dvec2())
}
#[inline]
pub fn cmpge(self, rhs: Self) -> BVec2 {
self.as_dvec2().cmpge(rhs.as_dvec2())
}
#[inline]
pub fn cmpgt(self, rhs: Self) -> BVec2 {
self.as_dvec2().cmpgt(rhs.as_dvec2())
}
#[inline]
pub fn cmple(self, rhs: Self) -> BVec2 {
self.as_dvec2().cmple(rhs.as_dvec2())
}
#[inline]
pub fn cmplt(self, rhs: Self) -> BVec2 {
self.as_dvec2().cmple(rhs.as_dvec2())
}
#[inline]
pub fn abs(self) -> Self {
self.as_dvec2().abs().as_unit_dvec2_unchecked()
}
#[inline]
pub fn signum(self) -> DVec2 {
self.as_dvec2().signum()
}
#[inline]
pub fn distance(self, rhs: Self) -> f64 {
self.as_dvec2().distance(rhs.as_dvec2())
}
#[inline]
pub fn distance_squared(self, rhs: Self) -> f64 {
self.as_dvec2().distance_squared(rhs.as_dvec2())
}
#[must_use]
#[inline]
pub fn project_onto(self, rhs: Self) -> DVec2 {
rhs.as_dvec2() * self.dot(rhs)
}
#[must_use]
#[inline]
pub fn reject_from(self, rhs: Self) -> DVec2 {
self.as_dvec2() - self.project_onto(rhs)
}
#[doc(alias = "mix")]
#[inline]
pub fn lerp(self, rhs: Self, s: f64) -> DVec2 {
self.as_dvec2().lerp(rhs.as_dvec2(), s)
}
#[inline]
pub fn abs_diff_eq(self, rhs: Self, max_abs_diff: f64) -> bool {
DVec2::abs_diff_eq(self.as_dvec2(), rhs.as_dvec2(), max_abs_diff)
}
#[inline]
pub fn mul_add(self, a: Self, b: Self) -> DVec2 {
self.as_dvec2().mul_add(a.as_dvec2(), b.as_dvec2())
}
#[inline]
pub fn from_angle(angle: f64) -> Self {
DVec2::from_angle(angle).as_unit_dvec2_unchecked()
}
#[inline]
pub fn angle_between(self, rhs: Self) -> f64 {
use crate::FloatEx;
let angle = self.dot(rhs).acos_approx();
angle * self.perp_dot(rhs).signumf()
}
#[inline]
pub fn perp(self) -> Self {
self.as_dvec2().perp().as_unit_dvec2_unchecked()
}
#[doc(alias = "wedge")]
#[doc(alias = "cross")]
#[doc(alias = "determinant")]
#[inline]
pub fn perp_dot(self, rhs: Self) -> f64 {
self.as_dvec2().perp_dot(rhs.as_dvec2())
}
#[must_use]
#[inline]
pub fn rotate(self, rhs: Self) -> Self {
self.as_dvec2()
.rotate(rhs.as_dvec2())
.as_unit_dvec2_unchecked()
}
}
impl Default for UnitDVec2 {
#[inline]
fn default() -> Self {
Self::X
}
}
impl Neg for UnitDVec2 {
type Output = Self;
#[inline]
fn neg(self) -> Self {
self.as_dvec2().neg().as_unit_dvec2_unchecked()
}
}
impl_op_ex!(/ |a: &UnitDVec2, b: &UnitDVec2| -> DVec2 {
a.as_dvec2() / b.as_dvec2()
});
impl_op_ex!(/ |a: &UnitDVec2, b: &f64| -> DVec2 {
a.as_dvec2() / b
});
impl_op_ex!(/ |a: &f64, b: &UnitDVec2| -> DVec2 {
a / b.as_dvec2()
});
impl_op_ex_commutative!(/ |a: &UnitDVec2, b: &DVec2| -> DVec2 {
a.as_dvec2() / b
});
impl_op_ex!(*|a: &UnitDVec2, b: &UnitDVec2| -> DVec2 { a.as_dvec2() * b.as_dvec2() });
impl_op_ex!(*|a: &UnitDVec2, b: &f64| -> DVec2 { a.as_dvec2() * b });
impl_op_ex!(*|a: &f64, b: &UnitDVec2| -> DVec2 { a * b.as_dvec2() });
impl_op_ex_commutative!(*|a: &UnitDVec2, b: &DVec2| -> DVec2 { a.as_dvec2() * b });
impl_op_ex!(+ |a: &UnitDVec2, b: &UnitDVec2| -> DVec2 {
a.as_dvec2() + b.as_dvec2()
});
impl_op_ex!(+ |a: &UnitDVec2, b: &f64| -> DVec2 {
a.as_dvec2() + b
});
impl_op_ex!(+ |a: &f64, b: &UnitDVec2| -> DVec2 {
a + b.as_dvec2()
});
impl_op_ex_commutative!(+ |a: &UnitDVec2, b: &DVec2| -> DVec2 {
a.as_dvec2() + b
});
impl_op_ex!(-|a: &UnitDVec2, b: &UnitDVec2| -> DVec2 { a.as_dvec2() - b.as_dvec2() });
impl_op_ex!(-|a: &UnitDVec2, b: &f64| -> DVec2 { a.as_dvec2() - b });
impl_op_ex!(-|a: &f64, b: &UnitDVec2| -> DVec2 { a - b.as_dvec2() });
impl_op_ex_commutative!(-|a: &UnitDVec2, b: &DVec2| -> DVec2 { a.as_dvec2() - b });
impl_op_ex!(% |a: &UnitDVec2, b: &UnitDVec2| -> DVec2 {
a.as_dvec2() % b.as_dvec2()
});
impl_op_ex!(% |a: &UnitDVec2, b: &f64| -> DVec2 {
a.as_dvec2() % b
});
impl_op_ex!(% |a: &f64, b: &UnitDVec2| -> DVec2 {
a % b.as_dvec2()
});
impl_op_ex_commutative!(% |a: &UnitDVec2, b: &DVec2| -> DVec2 {
a.as_dvec2() % b
});
impl Index<usize> for UnitDVec2 {
type Output = f64;
#[inline]
fn index(&self, index: usize) -> &Self::Output {
match index {
0 => &self.x,
1 => &self.y,
_ => panic!("index out of bounds"),
}
}
}
#[cfg(not(target_arch = "spirv"))]
impl fmt::Display for UnitDVec2 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "[{}, {}]", self.x, self.y)
}
}
#[cfg(not(target_arch = "spirv"))]
impl fmt::Debug for UnitDVec2 {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_tuple(stringify!(UnitDVec2))
.field(&self.x)
.field(&self.y)
.finish()
}
}
impl From<UnitDVec2> for [f64; 2] {
#[inline]
fn from(v: UnitDVec2) -> Self {
v.as_dvec2().into()
}
}
impl From<UnitDVec2> for (f64, f64) {
#[inline]
fn from(v: UnitDVec2) -> Self {
v.as_dvec2().into()
}
}
#[cfg(not(target_arch = "spirv"))]
impl AsRef<[f64; 2]> for UnitDVec2 {
#[inline]
fn as_ref(&self) -> &[f64; 2] {
unsafe { &*(self as *const UnitDVec2 as *const [f64; 2]) }
}
}