use rand::Rng;
use std::ops::{Add, AddAssign, Div, Mul, MulAssign, Sub};
#[derive(Debug, PartialEq, Clone, Copy)]
pub struct Vector {
pub x: f64,
pub y: f64,
pub z: f64,
}
impl Add<Vector> for Vector {
type Output = Vector;
fn add(self, other: Vector) -> Vector {
Vector {
x: self.x + other.x,
y: self.y + other.y,
z: self.z + other.z,
}
}
}
impl Mul<f64> for Vector {
type Output = Vector;
fn mul(self, scalar: f64) -> Vector {
Vector {
x: self.x * scalar,
y: self.y * scalar,
z: self.z * scalar,
}
}
}
impl Div<f64> for Vector {
type Output = Vector;
fn div(self, scalar: f64) -> Self::Output {
Vector {
x: self.x / scalar,
y: self.y / scalar,
z: self.z / scalar,
}
}
}
impl Sub<Vector> for Vector {
type Output = Vector;
fn sub(self, rhs: Vector) -> Self::Output {
Vector::new(self.x - rhs.x, self.y - rhs.y, self.z - rhs.z)
}
}
impl AddAssign for Vector {
fn add_assign(&mut self, other: Self) {
self.x += other.x;
self.y += other.y;
self.z += other.z;
}
}
impl MulAssign<f64> for Vector {
fn mul_assign(&mut self, scalar: f64) {
self.x = self.x * scalar;
self.y = self.y * scalar;
self.z = self.z * scalar;
}
}
impl Default for Vector {
fn default() -> Vector {
Vector::new(0.0, 0.0, 0.0)
}
}
impl Vector {
pub fn from_vec(array: &[f64; 3]) -> Vector {
Vector {
x: array[0],
y: array[1],
z: array[2],
}
}
pub fn new(x: f64, y: f64, z: f64) -> Self {
Self { x, y, z }
}
pub fn x() -> Self {
Self::new(1.0, 0.0, 0.0)
}
pub fn y() -> Self {
Self::new(0.0, 1.0, 0.0)
}
pub fn z() -> Self {
Self::new(0.0, 0.0, 1.0)
}
pub fn difference(&self, other: &Self) -> Self {
let dx = self.x - other.x;
let dy = self.y - other.y;
let dz = self.z - other.z;
Self::new(dx, dy, dz)
}
pub fn length(&self) -> f64 {
(self.x.powi(2) + self.y.powi(2) + self.z.powi(2)).sqrt()
}
pub fn squared_length(&self) -> f64 {
self.x.powi(2) + self.y.powi(2) + self.z.powi(2)
}
pub fn dot(&self, other: &Self) -> f64 {
self.x * other.x + self.y * other.y + self.z * other.z
}
pub fn distance(&self, other: &Self) -> f64 {
self.difference(other).length()
}
pub fn distance_squared(&self, other: &Self) -> f64 {
let difference = *other - *self;
difference.x.powi(2) + difference.y.powi(2) + difference.z.powi(2)
}
pub fn random_unit_vector() -> Self {
let mut rng = rand::thread_rng();
let theta = rng.gen_range(0.0..std::f64::consts::PI);
let phi = rng.gen_range(0.0..2.0 * std::f64::consts::PI);
let x = theta.sin() * phi.cos();
let y = theta.sin() * phi.sin();
let z = theta.cos();
Vector::new(x, y, z)
}
pub fn cross(&self, other: &Self) -> Self {
Self {
x: self.y * other.z - self.z * other.y,
y: self.z * other.x - self.x * other.z,
z: self.x * other.y - self.y * other.x,
}
}
pub fn angle_between(&self, other: &Vector) -> f64 {
let lengths_product = self.length() * other.length();
if lengths_product == 0.0 {
0.0
} else {
let angle_cosine = (self.dot(other) / (lengths_product)).clamp(-1.0, 1.0);
angle_cosine.acos()
}
}
pub fn normalize(&self) -> Self {
if self.length() == 0.0 {
*self
} else {
*self / self.length()
}
}
pub fn angle_between_points(&self, middle_point: &Vector, end_point: &Vector) -> f64 {
let v1 = *middle_point - *self;
let v2 = *end_point - *middle_point;
v1.angle_between(&v2)
}
pub fn as_tuple(&self) -> (f64, f64, f64) {
(self.x, self.y, self.z)
}
pub fn as_array(&self) -> [f64; 3] {
[self.x, self.y, self.z]
}
pub fn as_vec(&self) -> Vec<f64> {
vec![self.x, self.y, self.z]
}
}