use std::fmt;
use std::ops::{Add, AddAssign, Sub, SubAssign, Mul, MulAssign, Div, DivAssign, Neg};
#[derive(PartialEq, Debug, Clone, Copy)]
pub struct Vec3 {
pub x: f32,
pub y: f32,
pub z: f32,
}
impl Vec3 {
pub const DOWN: Vec3 = Vec3 {x: 0., y: -1., z: 0.};
pub const UP: Vec3 = Vec3 {x: 0., y: 1., z: 0. };
pub const RIGHT: Vec3 = Vec3 {x: 1., y: 0., z: 0. };
pub const LEFT: Vec3 = Vec3 {x: -1., y: 0., z: 0. };
pub const FORWARD: Vec3 = Vec3 {x: 0., y: 0., z: 1. };
pub const BACK: Vec3 = Vec3 {x: 0., y: 0., z: -1. };
pub const ONE: Vec3 = Vec3 {x: 1., y: 1., z: 1. };
pub const ZERO: Vec3 = Vec3 {x: 0., y: 0., z: 0. };
pub fn new(x: f32, y: f32, z: f32) -> Vec3 {
Vec3 { x, y, z }
}
pub fn set(&mut self, x: f32, y: f32, z: f32) {
self.x = x;
self.y = y;
self.z = z;
}
pub fn magnitude(&self) -> f32 {
Vec3::ZERO.distance_to(*self)
}
pub fn magnitude_squared(&self) -> f32 {
Vec3::ZERO.distance_to_squared(*self)
}
pub fn equals(&self, other: Vec3, epsilon: f32) -> bool {
(self.x - other.x).abs() < epsilon &&
(self.y - other.y).abs() < epsilon &&
(self.z - other.z).abs() < epsilon
}
pub fn normalized(&self) -> Vec3 {
let magnitude = self.magnitude();
*self / Vec3::new(magnitude, magnitude, magnitude)
}
pub fn distance_to(&self, other: Vec3) -> f32 {
self.distance_to_squared(other).sqrt()
}
pub fn distance_to_squared(&self, other: Vec3) -> f32 {
let lx = other.x - self.x;
let ly = other.y - self.y;
let lz = other.z - self.z;
lx.powi(2) + ly.powi(2) + lz.powi(2)
}
pub fn dot(&self, other: Vec3) -> f32 {
self.x * other.x + self.y * other.y + self.z * other.z
}
pub fn cross(&self, other: Vec3) -> Vec3 {
Vec3::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)
}
pub fn angle_between(&self, other: Vec3) -> f32 {
let dot = self.dot(other);
let magnitude_product = self.magnitude() * other.magnitude();
if magnitude_product == 0.0 {
return 0.0;
}
let cos_theta = dot / magnitude_product;
cos_theta.min(1.0).max(-1.0).acos()
}
pub fn lerp(&self, other: Vec3, t: f32) -> Vec3 {
Vec3 {
x: self.x * (1.0 - t) + other.x * t,
y: self.y * (1.0 - t) + other.y * t,
z: self.z * (1.0 - t) + other.z * t,
}
}
pub fn project(&self, onto: Vec3) -> Vec3 {
let onto_normalized = onto.normalized();
let scalar = self.dot(onto_normalized);
Vec3::new(onto_normalized.x * scalar, onto_normalized.y * scalar, onto_normalized.z * scalar)
}
}
impl Add for Vec3 {
type Output = Vec3;
fn add(self, rhs: Self) -> Self::Output {
Vec3::new(self.x + rhs.x, self.y + rhs.y, self.z + rhs.z)
}
}
impl AddAssign<Vec3> for Vec3 {
fn add_assign(&mut self, rhs: Vec3) {
self.x += rhs.x;
self.y += rhs.y;
self.z += rhs.z;
}
}
impl Sub for Vec3 {
type Output = Vec3;
fn sub(self, rhs: Self) -> Self::Output {
Vec3::new(self.x - rhs.x, self.y - rhs.y, self.z - rhs.z)
}
}
impl SubAssign<Vec3> for Vec3 {
fn sub_assign(&mut self, rhs: Vec3) {
self.x -= rhs.x;
self.y -= rhs.y;
self.z -= rhs.z;
}
}
impl Mul for Vec3 {
type Output = Vec3;
fn mul(self, rhs: Self) -> Self::Output {
Vec3::new(self.x * rhs.x, self.y * rhs.y, self.z * rhs.z)
}
}
impl MulAssign<Vec3> for Vec3 {
fn mul_assign(&mut self, rhs: Vec3) {
self.x *= rhs.x;
self.y *= rhs.y;
self.z *= rhs.z;
}
}
impl Div for Vec3 {
type Output = Vec3;
fn div(self, rhs: Self) -> Self::Output {
Vec3::new(self.x / rhs.x, self.y / rhs.y, self.z / rhs.z)
}
}
impl DivAssign<Vec3> for Vec3 {
fn div_assign(&mut self, rhs: Vec3) {
self.x /= rhs.x;
self.y /= rhs.y;
self.z /= rhs.z;
}
}
impl Neg for Vec3 {
type Output = Vec3;
fn neg(self) -> Self::Output {
Vec3::new(-self.x, -self.y, -self.z)
}
}
impl fmt::Display for Vec3 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "({}, {}, {})", self.x, self.y, self.z)
}
}