use crate::ALMOST_ZERO;
use rand::Rng;
#[derive(Debug)]
pub struct Vector3D {
pub x: f64,
pub y: f64,
pub z: f64,
}
pub const X: Vector3D = Vector3D {
x: 1.0,
y: 0.0,
z: 0.0,
};
pub const Y: Vector3D = Vector3D {
x: 0.0,
y: 1.0,
z: 0.0,
};
pub const Z: Vector3D = Vector3D {
x: 0.0,
y: 0.0,
z: 1.0,
};
impl Vector3D {
pub fn new(x: f64, y: f64, z: f64) -> Vector3D {
Vector3D { x, y, z }
}
pub fn length_l1(&self) -> f64 {
vec![self.x, self.y, self.z]
.iter()
.map(|i| i.abs())
.reduce(f64::max)
.unwrap()
}
pub fn is_close_to_zero(self: &Vector3D) -> bool {
self.length_l1() < ALMOST_ZERO
}
pub fn plus(self: &Vector3D, a: &Vector3D) -> Vector3D {
Vector3D {
x: self.x + a.x,
y: self.y + a.y,
z: self.z + a.z,
}
}
pub fn minus(self: &Vector3D, a: &Vector3D) -> Vector3D {
Vector3D {
x: self.x - a.x,
y: self.y - a.y,
z: self.z - a.z,
}
}
pub fn almost_equals(self: &Vector3D, a: &Vector3D) -> bool {
self.minus(a).is_close_to_zero()
}
pub fn revert(&self) -> Vector3D {
Vector3D {
x: -self.x,
y: -self.y,
z: -self.z,
}
}
pub fn generate_random_vectors(n: usize) -> Vec<Vector3D> {
(0..n).map(|_| Self::random_vector()).collect()
}
pub fn random_vector() -> Vector3D {
let mut rng = rand::rng();
Vector3D::new(
rng.random_range(-1.0..=1.0),
rng.random_range(-1.0..=1.0),
rng.random_range(-1.0..=1.0),
)
}
pub fn from_reference(vector_reference: &Vector3D) -> Vector3D {
Vector3D::new(vector_reference.x, vector_reference.y, vector_reference.z)
}
pub fn components(&self) -> [f64; 3] {
[self.x, self.y, self.z]
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn plus_and_minus_are_opposite() {
let a = Vector3D::random_vector();
let b = Vector3D::random_vector();
let c = a.plus(&b).minus(&b);
assert!(c.almost_equals(&a));
}
#[test]
fn minus_and_revert() {
let a = Vector3D::random_vector();
let b = Vector3D::random_vector();
let c = a.minus(&(b.revert()));
assert!(a.plus(&b).almost_equals(&c));
}
#[test]
fn from_reference_delivers_identical_vector() {
let a = Vector3D::random_vector();
let b = Vector3D::from_reference(&a);
assert!(b.almost_equals(&a));
}
}