use core::cmp::{Eq, PartialEq};
use core::fmt;
use core::hash::Hash;
use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
use num_traits::{Float, NumCast, Signed};
#[repr(C)]
pub struct Vector3D<T> {
pub x: T,
pub y: T,
pub z: T,
}
impl<T: Copy> Copy for Vector3D<T> {}
impl<T: Clone> Clone for Vector3D<T> {
fn clone(&self) -> Self {
Vector3D {
x: self.x.clone(),
y: self.y.clone(),
z: self.z.clone(),
}
}
}
#[cfg(feature = "serde")]
impl<'de, T> serde::Deserialize<'de> for Vector3D<T>
where
T: serde::Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let (x, y, z) = serde::Deserialize::deserialize(deserializer)?;
Ok(Vector3D {
x,
y,
z,
})
}
}
#[cfg(feature = "serde")]
impl<T> serde::Serialize for Vector3D<T>
where
T: serde::Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
(&self.x, &self.y, &self.z).serialize(serializer)
}
}
impl<T: Eq> Eq for Vector3D<T> {}
impl<T: PartialEq> PartialEq for Vector3D<T> {
fn eq(&self, other: &Self) -> bool {
self.x == other.x && self.y == other.y && self.z == other.z
}
}
impl<T: Hash> Hash for Vector3D<T> {
fn hash<H: core::hash::Hasher>(&self, h: &mut H) {
self.x.hash(h);
self.y.hash(h);
self.z.hash(h);
}
}
impl<T: fmt::Debug> fmt::Debug for Vector3D<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("")
.field(&self.x)
.field(&self.y)
.field(&self.z)
.finish()
}
}
impl<T: Default> Default for Vector3D<T> {
fn default() -> Self {
Vector3D::new(Default::default(), Default::default(), Default::default())
}
}
impl<T> Vector3D<T> {
#[inline]
pub const fn new(x: T, y: T, z: T) -> Self {
Vector3D {
x,
y,
z,
}
}
#[inline]
pub fn splat(v: T) -> Self
where
T: Clone,
{
Vector3D {
x: v.clone(),
y: v.clone(),
z: v,
}
}
#[inline]
pub fn from_untyped(p: Vector3D<T>) -> Self {
Vector3D::new(p.x, p.y, p.z)
}
pub fn abs(self) -> Self
where
T: Signed,
{
Vector3D::new(self.x.abs(), self.y.abs(), self.z.abs())
}
#[inline]
pub fn dot(self, other: Self) -> T
where
T: Add<Output = T> + Mul<Output = T>,
{
self.x * other.x + self.y * other.y + self.z * other.z
}
}
impl<T: Copy> Vector3D<T> {
#[inline]
pub fn cross(self, other: Self) -> Self
where
T: Sub<Output = T> + Mul<Output = T>,
{
Vector3D::new(
self.y * other.z - self.z * other.y,
self.z * other.x - self.x * other.z,
self.x * other.y - self.y * other.x,
)
}
#[inline]
pub fn component_mul(self, other: Self) -> Self
where
T: Mul<Output = T>,
{
Vector3D::new(self.x * other.x, self.y * other.y, self.z * other.z)
}
#[inline]
pub fn component_div(self, other: Self) -> Self
where
T: Div<Output = T>,
{
Vector3D::new(self.x / other.x, self.y / other.y, self.z / other.z)
}
#[inline]
pub fn to_array(self) -> [T; 3] {
[self.x, self.y, self.z]
}
#[inline]
pub fn to_tuple(self) -> (T, T, T) {
(self.x, self.y, self.z)
}
#[inline]
pub fn to_untyped(self) -> Vector3D<T> {
Vector3D::new(self.x, self.y, self.z)
}
}
impl<T> Vector3D<T>
where
T: Copy + Mul<T, Output = T> + Add<T, Output = T>,
{
#[inline]
pub fn square_length(self) -> T {
self.x * self.x + self.y * self.y + self.z * self.z
}
#[inline]
pub fn project_onto_vector(self, onto: Self) -> Self
where
T: Sub<T, Output = T> + Div<T, Output = T>,
{
onto * (self.dot(onto) / onto.square_length())
}
}
impl<T: Float> Vector3D<T> {
#[inline]
pub fn length(self) -> T {
self.square_length().sqrt()
}
#[inline]
#[must_use]
pub fn normalize(self) -> Self {
self / self.length()
}
#[inline]
#[must_use]
pub fn try_normalize(self) -> Option<Self> {
let len = self.length();
if len == T::zero() {
None
} else {
Some(self / len)
}
}
#[inline]
#[must_use]
pub fn robust_normalize(self) -> Self {
let length = self.length();
if length.is_infinite() {
let scaled = self / T::max_value();
scaled / scaled.length()
} else {
self / length
}
}
#[inline]
pub fn with_max_length(self, max_length: T) -> Self {
let square_length = self.square_length();
if square_length > max_length * max_length {
return self * (max_length / square_length.sqrt());
}
self
}
#[inline]
pub fn with_min_length(self, min_length: T) -> Self {
let square_length = self.square_length();
if square_length < min_length * min_length {
return self * (min_length / square_length.sqrt());
}
self
}
#[inline]
pub fn clamp_length(self, min: T, max: T) -> Self {
debug_assert!(min <= max);
self.with_min_length(min).with_max_length(max)
}
#[inline]
pub fn is_finite(self) -> bool {
self.x.is_finite() && self.y.is_finite() && self.z.is_finite()
}
}
impl<T: PartialOrd> Vector3D<T> {
}
impl<T: NumCast + Copy> Vector3D<T> {
#[inline]
pub fn cast<NewT: NumCast>(self) -> Vector3D<NewT> {
self.try_cast().unwrap()
}
pub fn try_cast<NewT: NumCast>(self) -> Option<Vector3D<NewT>> {
match (
NumCast::from(self.x),
NumCast::from(self.y),
NumCast::from(self.z),
) {
(Some(x), Some(y), Some(z)) => Some(Vector3D::new(x, y, z)),
_ => None,
}
}
#[inline]
pub fn to_f32(self) -> Vector3D<f32> {
self.cast()
}
#[inline]
pub fn to_f64(self) -> Vector3D<f64> {
self.cast()
}
#[inline]
pub fn to_usize(self) -> Vector3D<usize> {
self.cast()
}
#[inline]
pub fn to_u32(self) -> Vector3D<u32> {
self.cast()
}
#[inline]
pub fn to_i32(self) -> Vector3D<i32> {
self.cast()
}
#[inline]
pub fn to_i64(self) -> Vector3D<i64> {
self.cast()
}
}
impl<T: Neg> Neg for Vector3D<T> {
type Output = Vector3D<T::Output>;
#[inline]
fn neg(self) -> Self::Output {
Vector3D::new(-self.x, -self.y, -self.z)
}
}
impl<T: Add> Add for Vector3D<T> {
type Output = Vector3D<T::Output>;
#[inline]
fn add(self, other: Self) -> Self::Output {
Vector3D::new(self.x + other.x, self.y + other.y, self.z + other.z)
}
}
impl<T: Copy + Add<T, Output = T>> AddAssign for Vector3D<T> {
#[inline]
fn add_assign(&mut self, other: Self) {
*self = *self + other
}
}
impl<T: Sub> Sub for Vector3D<T> {
type Output = Vector3D<T::Output>;
#[inline]
fn sub(self, other: Self) -> Self::Output {
Vector3D::new(self.x - other.x, self.y - other.y, self.z - other.z)
}
}
impl<T: Copy + Sub<T, Output = T>> SubAssign<Vector3D<T>> for Vector3D<T> {
#[inline]
fn sub_assign(&mut self, other: Self) {
*self = *self - other
}
}
impl<T: Copy + Mul> Mul<T> for Vector3D<T> {
type Output = Vector3D<T::Output>;
#[inline]
fn mul(self, scale: T) -> Self::Output {
Vector3D::new(
self.x * scale,
self.y * scale,
self.z * scale,
)
}
}
impl<T: Copy + Mul<T, Output = T>> MulAssign<T> for Vector3D<T> {
#[inline]
fn mul_assign(&mut self, scale: T) {
*self = *self * scale
}
}
impl<T: Copy + Div> Div<T> for Vector3D<T> {
type Output = Vector3D<T::Output>;
#[inline]
fn div(self, scale: T) -> Self::Output {
Vector3D::new(
self.x / scale,
self.y / scale,
self.z / scale,
)
}
}
impl<T: Copy + Div<T, Output = T>> DivAssign<T> for Vector3D<T> {
#[inline]
fn div_assign(&mut self, scale: T) {
*self = *self / scale
}
}
impl<T> Into<[T; 3]> for Vector3D<T> {
fn into(self) -> [T; 3] {
[self.x, self.y, self.z]
}
}
impl<T> From<[T; 3]> for Vector3D<T> {
fn from([x, y, z]: [T; 3]) -> Self {
Vector3D::new(x, y, z)
}
}
impl<T> Into<(T, T, T)> for Vector3D<T> {
fn into(self) -> (T, T, T) {
(self.x, self.y, self.z)
}
}
impl<T> From<(T, T, T)> for Vector3D<T> {
fn from(tuple: (T, T, T)) -> Self {
Vector3D::new(tuple.0, tuple.1, tuple.2)
}
}
#[cfg(test)]
mod vector3d {
use crate::foundation::Vector3D;
#[cfg(feature = "mint")]
use mint;
type Vec3 = Vector3D<f32>;
#[test]
pub fn test_dot() {
let p1: Vec3 = Vector3D::new(7.0, 21.0, 32.0);
let p2: Vec3 = Vector3D::new(43.0, 5.0, 16.0);
assert_eq!(p1.dot(p2), 918.0);
}
#[test]
pub fn test_cross() {
let p1: Vec3 = Vector3D::new(4.0, 7.0, 9.0);
let p2: Vec3 = Vector3D::new(13.0, 8.0, 3.0);
let p3 = p1.cross(p2);
assert_eq!(p3, Vector3D::new(-51.0, 105.0, -59.0));
}
#[cfg(feature = "mint")]
#[test]
pub fn test_mint() {
let v1 = Vec3::new(1.0, 3.0, 5.0);
let vm: mint::Vector3<_> = v1.into();
let v2 = Vec3::from(vm);
assert_eq!(v1, v2);
}
}