use num::Float;
use std::ops::{Index, IndexMut, AddAssign, SubAssign, MulAssign, DivAssign, Add, Neg, Sub, Mul, Div};
use std::fmt::{Debug, Formatter, Result};
use crate::vector3::Vector3;
pub struct Vector4<T: Float> {
pub x: T,
pub y: T,
pub z: T,
pub w: T,
}
pub type Vector4F = Vector4<f32>;
pub type Vector4D = Vector4<f64>;
impl<T: Float> Vector4<T> {
pub fn new_default() -> Vector4<T> {
Vector4 {
x: T::zero(),
y: T::zero(),
z: T::zero(),
w: T::zero(),
}
}
pub fn new(x_: T, y_: T, z_: T, w_: T) -> Vector4<T> {
Vector4 {
x: x_,
y: y_,
z: z_,
w: w_,
}
}
pub fn new_vec(v: Vector3<T>, w_: T) -> Vector4<T> {
Vector4 {
x: v.x,
y: v.y,
z: v.z,
w: w_,
}
}
pub fn new_lst(lst: [T; 4]) -> Vector4<T> {
Vector4 {
x: lst[0],
y: lst[1],
z: lst[2],
w: lst[3],
}
}
}
impl<T: Float> Vector4<T> {
pub fn set_scalar(&mut self, s: T) {
self.x = s;
self.y = s;
self.z = s;
self.w = s;
}
pub fn set_scalar4(&mut self, x: T, y: T, z: T, w: T) {
self.x = x;
self.y = y;
self.z = z;
self.w = w;
}
pub fn set_vec(&mut self, pt: Vector3<T>, w: T) {
self.x = pt.x;
self.y = pt.y;
self.z = pt.z;
self.w = w;
}
pub fn set_lst(&mut self, lst: [T; 4]) {
self.x = lst[0];
self.y = lst[1];
self.z = lst[2];
self.w = lst[3];
}
pub fn set_self(&mut self, v: Vector4<T>) {
self.x = v.x;
self.y = v.y;
self.z = v.z;
self.w = v.w;
}
pub fn set_zero(&mut self) {
self.x = T::zero();
self.y = T::zero();
self.z = T::zero();
self.w = T::zero();
}
pub fn normalize(&mut self) {
let l = self.length();
self.x = self.x / l;
self.y = self.y / l;
self.z = self.z / l;
self.w = self.w / l;
}
}
impl<T: Float> Vector4<T> {
pub fn add_scalar(&self, v: T) -> Vector4<T> {
return Vector4::new(self.x + v, self.y + v, self.z + v, self.w + v);
}
pub fn add_vec(&self, v: Vector4<T>) -> Vector4<T> {
return Vector4::new(self.x + v.x, self.y + v.y, self.z + v.z, self.w + v.w);
}
pub fn sub_scalar(&self, v: T) -> Vector4<T> {
return Vector4::new(self.x - v, self.y - v, self.z - v, self.w - v);
}
pub fn sub_vec(&self, v: Vector4<T>) -> Vector4<T> {
return Vector4::new(self.x - v.x, self.y - v.y, self.z - v.z, self.w - v.w);
}
pub fn mul_scalar(&self, v: T) -> Vector4<T> {
return Vector4::new(self.x * v, self.y * v, self.z * v, self.w * v);
}
pub fn mul_vec(&self, v: Vector4<T>) -> Vector4<T> {
return Vector4::new(self.x * v.x, self.y * v.y, self.z * v.z, self.w * v.w);
}
pub fn div_scalar(&self, v: T) -> Vector4<T> {
return Vector4::new(self.x / v, self.y / v, self.z / v, self.w / v);
}
pub fn div_vec(&self, v: Vector4<T>) -> Vector4<T> {
return Vector4::new(self.x / v.x, self.y / v.y, self.z / v.z, self.w / v.w);
}
pub fn dot(&self, v: &Vector4<T>) -> T {
return self.x * v.x + self.y * v.y + self.z * v.z + self.w * v.w;
}
}
impl<T: Float> Vector4<T> {
pub fn rsub_scalar(&self, v: T) -> Vector4<T> {
return Vector4::new(v - self.x, v - self.y, v - self.z, v - self.w);
}
pub fn rsub_vec(&self, v: Vector4<T>) -> Vector4<T> {
return Vector4::new(v.x - self.x, v.y - self.y, v.z - self.z, v.w - self.w);
}
pub fn rdiv_scalar(&self, v: T) -> Vector4<T> {
return Vector4::new(v / self.x, v / self.y, v / self.z, v / self.w);
}
pub fn rdiv_vec(&self, v: Vector4<T>) -> Vector4<T> {
return Vector4::new(v.x / self.x, v.y / self.y, v.z / self.z, v.w / self.w);
}
}
impl<T: Float> Vector4<T> {
pub fn iadd_scalar(&mut self, v: T) {
self.x = self.x + v;
self.y = self.y + v;
self.z = self.z + v;
self.w = self.w + v;
}
pub fn iadd_vec(&mut self, v: Vector4<T>) {
self.x = self.x + v.x;
self.y = self.y + v.y;
self.z = self.z + v.z;
self.w = self.w + v.w;
}
pub fn isub_scalar(&mut self, v: T) {
self.x = self.x - v;
self.y = self.y - v;
self.z = self.z - v;
self.w = self.w - v;
}
pub fn isub_vec(&mut self, v: Vector4<T>) {
self.x = self.x - v.x;
self.y = self.y - v.y;
self.z = self.z - v.z;
self.w = self.w - v.w;
}
pub fn imul_scalar(&mut self, v: T) {
self.x = self.x * v;
self.y = self.y * v;
self.z = self.z * v;
self.w = self.w * v;
}
pub fn imul_vec(&mut self, v: Vector4<T>) {
self.x = self.x * v.x;
self.y = self.y * v.y;
self.z = self.z * v.z;
self.w = self.w * v.w;
}
pub fn idiv_scalar(&mut self, v: T) {
self.x = self.x / v;
self.y = self.y / v;
self.z = self.z / v;
self.w = self.w / v;
}
pub fn idiv_vec(&mut self, v: Vector4<T>) {
self.x = self.x / v.x;
self.y = self.y / v.y;
self.z = self.z / v.z;
self.w = self.w / v.w;
}
}
impl<T: Float> Vector4<T> {
pub fn at(&self, i: usize) -> &T {
match i {
0 => return &self.x,
1 => return &self.y,
2 => return &self.z,
3 => return &self.w,
_ => { panic!() }
}
}
pub fn at_mut(&mut self, i: usize) -> &mut T {
match i {
0 => return &mut self.x,
1 => return &mut self.y,
2 => return &mut self.z,
3 => return &mut self.w,
_ => { panic!() }
}
}
pub fn sum(&self) -> T {
return self.x + self.y + self.z + self.w;
}
pub fn avg(&self) -> T {
return (self.x + self.y + self.z + self.w) * T::from(0.25).unwrap();
}
pub fn min(&self) -> T {
return T::min(T::min(self.x, self.y), T::min(self.z, self.w));
}
pub fn max(&self) -> T {
return T::max(T::max(self.x, self.y), T::max(self.z, self.w));
}
pub fn absmin(&self) -> T {
return crate::math_utils::absmin(crate::math_utils::absmin(self.x, self.y),
crate::math_utils::absmin(self.z, self.w));
}
pub fn absmax(&self) -> T {
return crate::math_utils::absmax(crate::math_utils::absmax(self.x, self.y),
crate::math_utils::absmax(self.z, self.w));
}
pub fn dominant_axis(&self) -> usize {
return match T::abs(self.x) > T::abs(self.y) {
true => match T::abs(self.x) > T::abs(self.z) {
true => match T::abs(self.x) > T::abs(self.w) {
true => 0,
false => 3
}
false => match T::abs(self.z) > T::abs(self.w) {
true => 2,
false => 3
}
}
false => match T::abs(self.y) > T::abs(self.z) {
true => match T::abs(self.y) > T::abs(self.w) {
true => 1,
false => 3
}
false => match T::abs(self.z) > T::abs(self.w) {
true => 2,
false => 3
}
}
};
}
pub fn subminant_axis(&self) -> usize {
return match T::abs(self.x) < T::abs(self.y) {
true => match T::abs(self.x) < T::abs(self.z) {
true => match T::abs(self.x) < T::abs(self.w) {
true => 0,
false => 3
}
false => match T::abs(self.z) < T::abs(self.w) {
true => 2,
false => 3
}
}
false => match T::abs(self.y) < T::abs(self.z) {
true => match T::abs(self.y) < T::abs(self.w) {
true => 1,
false => 3
}
false => match T::abs(self.z) < T::abs(self.w) {
true => 2,
false => 3
}
}
};
}
pub fn normalized(&self) -> Vector4<T> {
let l = self.length();
return Vector4::new(self.x / l, self.y / l, self.z / l, self.w / l);
}
pub fn length(&self) -> T {
return T::sqrt(self.x * self.x + self.y * self.y + self.z * self.z + self.w * self.w);
}
pub fn length_squared(&self) -> T {
return self.x * self.x + self.y * self.y + self.z * self.z + self.w * self.w;
}
pub fn distance_to(&self, other: Vector4<T>) -> T {
return self.sub_vec(other).length();
}
pub fn distance_squared_to(&self, other: Vector4<T>) -> T {
return self.sub_vec(other).length_squared();
}
pub fn is_equal(&self, other: &Vector4<T>) -> bool {
return self.x == other.x && self.y == other.y && self.z == other.z && self.w == other.w;
}
pub fn is_similar(&self, other: &Vector4<T>, epsilon: Option<T>) -> bool {
return (T::abs(self.x - other.x) < epsilon.unwrap_or(T::epsilon())) &&
(T::abs(self.y - other.y) < epsilon.unwrap_or(T::epsilon())) &&
(T::abs(self.z - other.z) < epsilon.unwrap_or(T::epsilon())) &&
(T::abs(self.w - other.w) < epsilon.unwrap_or(T::epsilon()));
}
}
impl<T: Float> Clone for Vector4<T> {
fn clone(&self) -> Self {
return Vector4 {
x: self.x,
y: self.y,
z: self.z,
w: self.w,
};
}
}
impl<T: Float> Copy for Vector4<T> {}
impl<T: Float> Index<usize> for Vector4<T> {
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
return self.at(index);
}
}
impl<T: Float> IndexMut<usize> for Vector4<T> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
return self.at_mut(index);
}
}
impl<T: Float> AddAssign<T> for Vector4<T> {
fn add_assign(&mut self, rhs: T) {
self.iadd_scalar(rhs);
}
}
impl<T: Float> AddAssign for Vector4<T> {
fn add_assign(&mut self, rhs: Self) {
self.iadd_vec(rhs);
}
}
impl<T: Float> SubAssign<T> for Vector4<T> {
fn sub_assign(&mut self, rhs: T) {
self.isub_scalar(rhs);
}
}
impl<T: Float> SubAssign for Vector4<T> {
fn sub_assign(&mut self, rhs: Self) {
self.isub_vec(rhs);
}
}
impl<T: Float> MulAssign<T> for Vector4<T> {
fn mul_assign(&mut self, rhs: T) {
self.imul_scalar(rhs);
}
}
impl<T: Float> MulAssign for Vector4<T> {
fn mul_assign(&mut self, rhs: Self) {
self.imul_vec(rhs);
}
}
impl<T: Float> DivAssign<T> for Vector4<T> {
fn div_assign(&mut self, rhs: T) {
self.idiv_scalar(rhs);
}
}
impl<T: Float> DivAssign for Vector4<T> {
fn div_assign(&mut self, rhs: Self) {
self.idiv_vec(rhs);
}
}
impl<T: Float> PartialEq for Vector4<T> {
fn eq(&self, other: &Self) -> bool {
return self.is_equal(other);
}
}
impl<T: Float> Eq for Vector4<T> {}
impl<T: Float> Neg for Vector4<T> {
type Output = Vector4<T>;
fn neg(self) -> Self::Output {
return Vector4::new(-self.x, -self.y, -self.z, -self.w);
}
}
impl<T: Float> Add<T> for Vector4<T> {
type Output = Vector4<T>;
fn add(self, rhs: T) -> Self::Output {
return self.add_scalar(rhs);
}
}
impl<T: Float> Add for Vector4<T> {
type Output = Vector4<T>;
fn add(self, rhs: Self) -> Self::Output {
return self.add_vec(rhs);
}
}
impl<T: Float> Sub<T> for Vector4<T> {
type Output = Vector4<T>;
fn sub(self, rhs: T) -> Self::Output {
return self.sub_scalar(rhs);
}
}
impl<T: Float> Sub for Vector4<T> {
type Output = Vector4<T>;
fn sub(self, rhs: Self) -> Self::Output {
return self.sub_vec(rhs);
}
}
impl<T: Float> Mul<T> for Vector4<T> {
type Output = Vector4<T>;
fn mul(self, rhs: T) -> Self::Output {
return self.mul_scalar(rhs);
}
}
impl<T: Float> Mul for Vector4<T> {
type Output = Vector4<T>;
fn mul(self, rhs: Self) -> Self::Output {
return self.mul_vec(rhs);
}
}
impl<T: Float> Div<T> for Vector4<T> {
type Output = Vector4<T>;
fn div(self, rhs: T) -> Self::Output {
return self.div_scalar(rhs);
}
}
impl<T: Float> Div for Vector4<T> {
type Output = Vector4<T>;
fn div(self, rhs: Self) -> Self::Output {
return self.div_vec(rhs);
}
}
impl<T: Float + Debug> Debug for Vector4<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
f.debug_tuple("")
.field(&self.x)
.field(&self.y)
.field(&self.z)
.field(&self.w)
.finish()
}
}
pub fn min<T: Float>(a: &Vector4<T>, b: &Vector4<T>) -> Vector4<T> {
return Vector4::new(T::min(a.x, b.x), T::min(a.y, b.y),
T::min(a.z, b.z), T::min(a.w, b.w));
}
pub fn max<T: Float>(a: &Vector4<T>, b: &Vector4<T>) -> Vector4<T> {
return Vector4::new(T::max(a.x, b.x), T::max(a.y, b.y),
T::max(a.z, b.z), T::max(a.w, b.w));
}
pub fn clamp<T: Float>(v: &Vector4<T>, low: &Vector4<T>,
high: &Vector4<T>) -> Vector4<T> {
return Vector4::new(crate::math_utils::clamp(v.x, low.x, high.x),
crate::math_utils::clamp(v.y, low.y, high.y),
crate::math_utils::clamp(v.z, low.z, high.z),
crate::math_utils::clamp(v.w, low.w, high.w));
}
pub fn ceil<T: Float>(a: &Vector4<T>) -> Vector4<T> {
return Vector4::new(T::ceil(a.x), T::ceil(a.y), T::ceil(a.z),
T::ceil(a.w));
}
pub fn floor<T: Float>(a: &Vector4<T>) -> Vector4<T> {
return Vector4::new(T::floor(a.x), T::floor(a.y), T::floor(a.z),
T::floor(a.w));
}
pub fn monotonic_catmull_rom<T: Float>(v0: Vector4<T>, v1: Vector4<T>,
v2: Vector4<T>, v3: Vector4<T>, f: T) -> Vector4<T> {
let two = T::from(2.0).unwrap();
let three = T::from(3.0).unwrap();
let mut d1 = (v2 - v0) / two;
let mut d2 = (v3 - v1) / two;
let d_diff = v2 - v1;
if T::abs(d_diff.x) < T::epsilon() ||
crate::math_utils::sign(d_diff.x) != crate::math_utils::sign(d1.x) ||
crate::math_utils::sign(d_diff.x) != crate::math_utils::sign(d2.x) {
d1.x = T::zero();
d2.x = T::zero();
}
if T::abs(d_diff.y) < T::epsilon() ||
crate::math_utils::sign(d_diff.y) != crate::math_utils::sign(d1.y) ||
crate::math_utils::sign(d_diff.y) != crate::math_utils::sign(d2.y) {
d1.y = T::zero();
d2.y = T::zero();
}
if T::abs(d_diff.z) < T::epsilon() ||
crate::math_utils::sign(d_diff.z) != crate::math_utils::sign(d1.z) ||
crate::math_utils::sign(d_diff.z) != crate::math_utils::sign(d2.z) {
d1.z = T::zero();
d2.z = T::zero();
}
if T::abs(d_diff.w) < T::epsilon() ||
crate::math_utils::sign(d_diff.w) != crate::math_utils::sign(d1.w) ||
crate::math_utils::sign(d_diff.w) != crate::math_utils::sign(d2.w) {
d1.w = T::zero();
d2.w = T::zero();
}
let a3 = d1 + d2 - d_diff * two;
let a2 = d_diff * three - d1 * two - d2;
let a1 = d1;
let a0 = v1;
return a3 * crate::math_utils::cubic(f) + a2 * crate::math_utils::square(f) + a1 * f + a0;
}