use std::ops::{Add, Sub, Mul, Div, Index, IndexMut};
use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Vector3 {
pub x: f64,
pub y: f64,
pub z: f64,
}
impl Vector3 {
#[inline]
pub fn new(x: f64, y: f64, z: f64) -> Self {
Self { x, y, z }
}
#[inline]
pub fn zero() -> Self {
Self { x: 0.0, y: 0.0, z: 0.0 }
}
#[inline]
pub fn unit_x() -> Self {
Self { x: 1.0, y: 0.0, z: 0.0 }
}
#[inline]
pub fn unit_y() -> Self {
Self { x: 0.0, y: 1.0, z: 0.0 }
}
#[inline]
pub fn unit_z() -> Self {
Self { x: 0.0, y: 0.0, z: 1.0 }
}
#[inline]
pub fn magnitude(&self) -> f64 {
(self.x * self.x + self.y * self.y + self.z * self.z).sqrt()
}
#[inline]
pub fn magnitude_squared(&self) -> f64 {
self.x * self.x + self.y * self.y + self.z * self.z
}
#[inline]
pub fn normalize(&self) -> Self {
let mag = self.magnitude();
if mag == 0.0 {
*self
} else {
Self::new(self.x / mag, self.y / mag, self.z / mag)
}
}
#[inline]
pub fn dot(&self, other: &Self) -> f64 {
self.x * other.x + self.y * other.y + self.z * other.z
}
#[inline]
pub fn cross(&self, other: &Self) -> Self {
Self::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 distance_to(&self, other: &Self) -> f64 {
(*self - *other).magnitude()
}
#[inline]
pub fn lerp(&self, other: &Self, t: f64) -> Self {
Self::new(
self.x + (other.x - self.x) * t,
self.y + (other.y - self.y) * t,
self.z + (other.z - self.z) * t,
)
}
#[inline]
pub fn as_array(&self) -> [f64; 3] {
[self.x, self.y, self.z]
}
}
impl Add for Vector3 {
type Output = Self;
#[inline]
fn add(self, other: Self) -> Self {
Self::new(self.x + other.x, self.y + other.y, self.z + other.z)
}
}
impl Sub for Vector3 {
type Output = Self;
#[inline]
fn sub(self, other: Self) -> Self {
Self::new(self.x - other.x, self.y - other.y, self.z - other.z)
}
}
impl Mul<f64> for Vector3 {
type Output = Self;
#[inline]
fn mul(self, scalar: f64) -> Self {
Self::new(self.x * scalar, self.y * scalar, self.z * scalar)
}
}
impl Div<f64> for Vector3 {
type Output = Self;
#[inline]
fn div(self, scalar: f64) -> Self {
Self::new(self.x / scalar, self.y / scalar, self.z / scalar)
}
}
impl fmt::Display for Vector3 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "({}, {}, {})", self.x, self.y, self.z)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_vector3_basic_operations() {
let v1 = Vector3::new(1.0, 2.0, 3.0);
let v2 = Vector3::new(4.0, 5.0, 6.0);
assert_eq!(v1 + v2, Vector3::new(5.0, 7.0, 9.0));
assert_eq!(v1 - v2, Vector3::new(-3.0, -3.0, -3.0));
}
#[test]
fn test_vector3_cross_product() {
let v1 = Vector3::unit_x();
let v2 = Vector3::unit_y();
let result = v1.cross(&v2);
assert_eq!(result, Vector3::unit_z());
}
}