use core::ops::{Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign};
use num_traits::{ConstZero, MulAdd, MulAddAssign, One, Signed, Zero, float::FloatCore};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use crate::{MathConstants, Quaternion, QuaternionMath, SqrtMethods, Vector2d, Vector3dMath};
pub type Vector3df32 = Vector3d<f32>;
pub type Vector3df64 = Vector3d<f64>;
#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "no_align", repr(C, align(4)))]
#[cfg_attr(not(feature = "no_align"), repr(C, align(16)))]
pub struct Vector3d<T> {
pub x: T,
pub y: T,
pub z: T,
}
impl<T> Default for Vector3d<T>
where
T: Copy + Zero,
{
fn default() -> Self {
Self::new(T::zero(), T::zero(), T::zero())
}
}
impl<T> Vector3d<T>
where
T: Copy,
{
#[inline]
pub const fn new(x: T, y: T, z: T) -> Self {
Self { x, y, z }
}
}
impl<T> Zero for Vector3d<T>
where
T: Copy + Zero + PartialEq + Vector3dMath,
{
#[inline]
fn zero() -> Self {
Self { x: T::zero(), y: T::zero(), z: T::zero() }
}
#[inline]
fn is_zero(&self) -> bool {
self.x == T::zero() && self.y == T::zero() && self.z == T::zero()
}
}
impl<T> ConstZero for Vector3d<T>
where
T: Copy + ConstZero + PartialEq + Vector3dMath,
{
const ZERO: Self = Self { x: T::ZERO, y: T::ZERO, z: T::ZERO };
}
impl<T> Neg for Vector3d<T>
where
T: Copy + Vector3dMath,
{
type Output = Self;
#[inline]
fn neg(self) -> Self {
T::v3_neg(self)
}
}
impl<T> Add for Vector3d<T>
where
T: Copy + Vector3dMath,
{
type Output = Self;
#[inline]
fn add(self, other: Self) -> Self {
T::v3_add(self, other)
}
}
impl<T> AddAssign for Vector3d<T>
where
T: Copy + Vector3dMath,
{
#[inline]
fn add_assign(&mut self, other: Self) {
*self = *self + other;
}
}
impl<T> MulAdd<T> for Vector3d<T>
where
T: Copy + Vector3dMath,
{
type Output = Self;
#[inline]
fn mul_add(self, k: T, other: Self) -> Self {
T::v3_mul_add(self, k, other)
}
}
impl MulAdd<i32> for Vector3d<i16> {
type Output = Self;
#[inline]
fn mul_add(self, k: i32, other: Self) -> Self {
#[allow(clippy::cast_possible_truncation)]
Vector3d {
x: self.x * (k as i16) + other.x,
y: self.y * (k as i16) + other.y,
z: self.z * (k as i16) + other.z,
}
}
}
impl MulAdd<f32> for Vector3d<i16> {
type Output = Self;
#[inline]
fn mul_add(self, k: f32, other: Self) -> Self {
#[allow(clippy::cast_possible_truncation)]
Vector3d {
x: self.x * (k as i16) + other.x,
y: self.y * (k as i16) + other.y,
z: self.z * (k as i16) + other.z,
}
}
}
impl<T> MulAddAssign<T> for Vector3d<T>
where
T: Copy + Vector3dMath,
{
#[inline]
fn mul_add_assign(&mut self, k: T, other: Self) {
*self = self.mul_add(k, other);
}
}
impl<T> Sub for Vector3d<T>
where
T: Copy + Vector3dMath,
{
type Output = Self;
#[inline]
fn sub(self, other: Self) -> Self {
self + (-other)
}
}
impl<T> SubAssign for Vector3d<T>
where
T: Copy + Vector3dMath,
{
#[inline]
fn sub_assign(&mut self, other: Self) {
*self = *self - other;
}
}
impl Mul<Vector3d<f32>> for f32 {
type Output = Vector3d<f32>;
#[inline]
fn mul(self, other: Vector3d<f32>) -> Vector3d<f32> {
f32::v3_mul_scalar(other, self)
}
}
impl Mul<Vector3d<f64>> for f64 {
type Output = Vector3d<f64>;
#[inline]
fn mul(self, other: Vector3d<f64>) -> Vector3d<f64> {
f64::v3_mul_scalar(other, self)
}
}
impl<T> Mul<T> for Vector3d<T>
where
T: Copy + Vector3dMath,
{
type Output = Self;
#[inline]
fn mul(self, k: T) -> Self {
T::v3_mul_scalar(self, k)
}
}
impl Mul<i32> for Vector3d<i16> {
type Output = Self;
#[inline]
fn mul(self, k: i32) -> Self {
#[allow(clippy::cast_possible_truncation)]
Vector3d { x: self.x * (k as i16), y: self.y * (k as i16), z: self.z * (k as i16) }
}
}
impl Mul<i16> for Vector3d<f32> {
type Output = Self;
#[inline]
fn mul(self, k: i16) -> Self {
Vector3d { x: self.x * f32::from(k), y: self.y * f32::from(k), z: self.z * f32::from(k) }
}
}
impl Mul<i32> for Vector3d<f32> {
type Output = Self;
#[inline]
fn mul(self, k: i32) -> Self {
#[allow(clippy::cast_precision_loss)]
Vector3d { x: self.x * (k as f32), y: self.y * (k as f32), z: self.z * (k as f32) }
}
}
impl<T> MulAssign<T> for Vector3d<T>
where
T: Copy + Vector3dMath,
{
#[inline]
fn mul_assign(&mut self, k: T) {
*self = *self * k;
}
}
impl<T> Mul<Vector3d<T>> for Vector3d<T>
where
T: Copy + Vector3dMath,
{
type Output = Self;
#[inline]
fn mul(self, other: Self) -> Self {
T::v3_mul_elementwise(self, other)
}
}
impl<T> Div<T> for Vector3d<T>
where
T: Copy + Vector3dMath,
{
type Output = Self;
#[inline]
fn div(self, k: T) -> Self {
T::v3_div_scalar(self, k)
}
}
impl<T> DivAssign<T> for Vector3d<T>
where
T: Copy + Vector3dMath,
{
#[inline]
fn div_assign(&mut self, k: T) {
*self = self.div(k);
}
}
impl<T> Div<Vector3d<T>> for Vector3d<T>
where
T: Copy + Vector3dMath,
{
type Output = Self;
#[inline]
fn div(self, other: Self) -> Self {
T::v3_div_elementwise(self, other)
}
}
impl<T> Index<usize> for Vector3d<T> {
type Output = T;
#[inline]
fn index(&self, index: usize) -> &T {
match index {
0 => &self.x,
1 => &self.y,
_ => &self.z, }
}
}
impl<T> IndexMut<usize> for Vector3d<T> {
#[inline]
fn index_mut(&mut self, index: usize) -> &mut T {
match index {
0 => &mut self.x,
1 => &mut self.y,
_ => &mut self.z, }
}
}
impl<T> Vector3d<T>
where
T: Copy + Signed,
{
#[inline]
pub fn abs(self) -> Self {
Self { x: self.x.abs(), y: self.y.abs(), z: self.z.abs() }
}
#[inline]
pub fn abs_in_place(&mut self) -> &mut Self {
*self = self.abs();
self
}
}
impl<T> Vector3d<T>
where
T: Copy + FloatCore,
{
#[inline]
pub fn clamp(self, min: T, max: T) -> Self {
Self { x: self.x.clamp(min, max), y: self.y.clamp(min, max), z: self.z.clamp(min, max) }
}
#[inline]
pub fn clamp_in_place(&mut self, min: T, max: T) -> &mut Self {
*self = self.clamp(min, max);
self
}
}
impl<T> Vector3d<T>
where
T: Copy + Vector3dMath,
{
#[inline]
pub fn dot(self, other: Self) -> T {
T::v3_dot(self, other)
}
}
impl<T> Vector3d<T>
where
T: Copy + Vector3dMath,
{
#[inline]
pub fn cross(self, other: Self) -> Vector3d<T> {
T::v3_cross(self, other)
}
}
impl<T> Vector3d<T>
where
T: Copy + Vector3dMath,
{
#[inline]
pub fn norm_squared(self) -> T {
T::v3_norm_squared(self)
}
#[inline]
pub fn distance_squared(self, other: Self) -> T {
(self - other).norm_squared()
}
}
impl<T> Vector3d<T>
where
T: Copy + SqrtMethods + Vector3dMath,
{
#[inline]
pub fn norm(self) -> T {
Self::norm_squared(self).sqrt()
}
}
impl<T> Vector3d<T>
where
T: Copy + Zero + PartialEq + SqrtMethods + Vector3dMath,
{
#[inline]
pub fn normalize(self) -> Self {
let norm_squared = self.norm_squared();
if norm_squared == T::zero() {
return self;
}
self * norm_squared.sqrt_reciprocal()
}
#[inline]
pub fn normalize_in_place(&mut self) -> &mut Self {
*self = self.normalize();
self
}
#[inline]
pub fn normalize_unchecked(self) -> Self {
let norm_squared = self.norm_squared();
self * norm_squared.sqrt_reciprocal()
}
#[inline]
pub fn normalize_unchecked_in_place(&mut self) -> &mut Self {
*self = self.normalize_unchecked();
self
}
}
impl<T> Vector3d<T>
where
T: Copy + Vector3dMath,
{
#[inline]
pub fn is_normalized(self) -> bool {
T::v3_is_normalized(self)
}
}
impl<T> Vector3d<T>
where
T: Copy + Zero + SqrtMethods + Vector3dMath,
{
#[inline]
pub fn distance(self, other: Self) -> T {
self.distance_squared(other).sqrt()
}
}
impl<T> Vector3d<T>
where
T: Copy + Mul<Output = T> + MathConstants,
{
#[inline]
pub fn to_degrees(self) -> Self {
Self { x: self.x * T::RADIANS_TO_DEGREES, y: self.y * T::RADIANS_TO_DEGREES, z: self.z * T::RADIANS_TO_DEGREES }
}
#[inline]
pub fn to_radians(self) -> Self {
Self { x: self.x * T::DEGREES_TO_RADIANS, y: self.y * T::DEGREES_TO_RADIANS, z: self.z * T::DEGREES_TO_RADIANS }
}
}
impl<T> Vector3d<T>
where
T: Copy + Add<Output = T> + Mul<Output = T>,
{
#[inline]
pub fn sum(self) -> T {
self.x + self.y + self.z
}
#[inline]
pub fn product(self) -> T {
self.x * self.y * self.z
}
}
impl<T> Vector3d<T>
where
T: Copy + One + Add<Output = T> + Div<Output = T>,
{
#[inline]
pub fn mean(self) -> T {
let three = T::one() + T::one() + T::one();
self.sum() / three
}
}
impl<T> Vector3d<T>
where
T: Copy + Vector3dMath,
{
#[inline]
pub fn max(self) -> T {
T::v3_max(self)
}
#[inline]
pub fn min(self) -> T {
T::v3_min(self)
}
}
impl<T> Vector3d<T>
where
T: Copy + Zero + One + SqrtMethods + Vector3dMath + QuaternionMath,
{
#[inline]
pub fn rotate_by(self, q: Quaternion<T>) -> Self {
let q_xyz = Vector3d { x: q.x, y: q.y, z: q.z };
let uv = q_xyz.cross(self) * (T::one() + T::one());
self + (uv * q.w) + q_xyz.cross(uv)
}
#[inline]
pub fn rotate_back_by(self, q: Quaternion<T>) -> Self {
self.rotate_by(q.conjugate())
}
}
impl<T> From<(T, T, T)> for Vector3d<T> {
#[inline]
fn from((x, y, z): (T, T, T)) -> Self {
Self { x, y, z }
}
}
impl<T> From<[T; 3]> for Vector3d<T>
where
T: Copy,
{
#[inline]
fn from(v: [T; 3]) -> Self {
Self { x: v[0], y: v[1], z: v[2] }
}
}
impl<T> From<Vector3d<T>> for [T; 3] {
#[inline]
fn from(v: Vector3d<T>) -> Self {
[v.x, v.y, v.z]
}
}
impl<T> From<Vector2d<T>> for Vector3d<T>
where
T: Copy + Zero,
{
#[inline]
fn from(other: Vector2d<T>) -> Self {
Self { x: other.x, y: other.y, z: T::zero() }
}
}
impl<T> From<Vector3d<T>> for Vector2d<T>
where
T: Copy + Zero,
{
#[inline]
fn from(v: Vector3d<T>) -> Self {
Vector2d::<T> { x: v.x, y: v.y }
}
}
pub type Vector3di16 = Vector3d<i16>;
impl Mul<f32> for Vector3d<i16> {
type Output = Self;
#[inline]
fn mul(self, k: f32) -> Self {
#[allow(clippy::cast_possible_truncation)]
Self { x: (f32::from(self.x) * k) as i16, y: (f32::from(self.y) * k) as i16, z: (f32::from(self.z) * k) as i16 }
}
}
impl From<Vector3d<i16>> for Vector3d<f32> {
#[inline]
fn from(v: Vector3d<i16>) -> Self {
Self { x: f32::from(v.x), y: f32::from(v.y), z: f32::from(v.z) }
}
}
impl From<Vector3d<f32>> for Vector3d<i16> {
#[inline]
fn from(v: Vector3d<f32>) -> Self {
#[allow(clippy::cast_possible_truncation)]
Self { x: v.x as i16, y: v.y as i16, z: v.z as i16 }
}
}
impl From<[i16; 3]> for Vector3d<f32> {
#[inline]
fn from(v: [i16; 3]) -> Self {
Self { x: f32::from(v[0]), y: f32::from(v[1]), z: f32::from(v[2]) }
}
}
impl From<Vector3d<f32>> for [i16; 3] {
#[inline]
fn from(v: Vector3d<f32>) -> Self {
#[allow(clippy::cast_possible_truncation)]
[v.x as i16, v.y as i16, v.z as i16]
}
}
pub type Vector3di32 = Vector3d<i32>;
impl Mul<f32> for Vector3d<i32> {
type Output = Self;
#[inline]
fn mul(self, k: f32) -> Self {
#[allow(clippy::cast_precision_loss)]
#[allow(clippy::cast_possible_truncation)]
Self { x: ((self.x as f32) * k) as i32, y: ((self.y as f32) * k) as i32, z: ((self.z as f32) * k) as i32 }
}
}
impl From<Vector3d<i32>> for Vector3d<f32> {
#[inline]
#[allow(clippy::cast_precision_loss)]
fn from(v: Vector3d<i32>) -> Self {
Self { x: v.x as f32, y: v.y as f32, z: v.z as f32 }
}
}
impl From<Vector3d<f32>> for Vector3d<i32> {
#[inline]
fn from(v: Vector3d<f32>) -> Self {
#[allow(clippy::cast_possible_truncation)]
Self { x: v.x as i32, y: v.y as i32, z: v.z as i32 }
}
}
impl From<[i32; 3]> for Vector3d<f32> {
#[inline]
fn from(v: [i32; 3]) -> Self {
#[allow(clippy::cast_precision_loss)]
Self { x: v[0] as f32, y: v[1] as f32, z: v[2] as f32 }
}
}
impl From<Vector3d<f32>> for [i32; 3] {
#[inline]
fn from(v: Vector3d<f32>) -> Self {
#[allow(clippy::cast_possible_truncation)]
[v.x as i32, v.y as i32, v.z as i32]
}
}