use crate::vector3_error::{Vector3DeserializationErrorKind, Vector3Error, Vector3ErrorKind};
use std::f64::consts::PI;
use std::fmt::{Debug, Formatter};
use std::ops::{Add, Div, Mul, Sub};
#[derive(Clone, Copy, Default)]
pub struct Vector3 {
pub x: f64,
pub y: f64,
pub z: f64,
}
impl Vector3 {
pub fn new(x: f64, y: f64, z: f64) -> Vector3 {
Self { x, y, z }
}
pub fn magnitude(&self) -> f64 {
(self.x.powi(2) + self.y.powi(2) + self.z.powi(2)).sqrt()
}
pub fn normalize(&self) -> Vector3 {
let magnitude = self.magnitude();
Vector3 {
x: self.x / magnitude,
y: self.y / magnitude,
z: self.z / magnitude,
}
}
pub fn is_zero(&self) -> bool {
self.magnitude().abs() < f64::EPSILON
}
pub fn distance_to(&self, other: Vector3) -> f64 {
((self.x - other.x).powi(2) + (self.y - other.y).powi(2) + (self.z - other.z).powi(2))
.sqrt()
}
pub fn dot(&self, other: &Vector3) -> f64 {
self.x * other.x + self.y * other.y + self.z * other.z
}
pub fn cross(&self, other: &Vector3) -> Vector3 {
Vector3 {
x: self.y * other.z - other.y * self.z,
y: -(self.x * other.z - other.x * self.z),
z: self.x * other.y - other.x * self.y,
}
}
pub fn angle(&self, other: &Vector3) -> f64 {
(self.dot(other) / self.magnitude() * other.magnitude()).acos()
}
pub fn angle_deg(&self, other: &Vector3) -> f64 {
self.angle(other) * (180.0 / PI)
}
pub fn from_i32(x: i32, y: i32, z: i32) -> Vector3 {
Vector3 {
x: x as f64,
y: y as f64,
z: z as f64,
}
}
pub fn to_string(&self) -> String {
format!("({}, {}, {})", self.x, self.y, self.z)
}
}
impl Add for Vector3 {
type Output = Vector3;
fn add(self, other: Vector3) -> Vector3 {
Vector3 {
x: self.x + other.x,
y: self.y + other.y,
z: self.z + other.z,
}
}
}
impl Sub for Vector3 {
type Output = Vector3;
fn sub(self, other: Vector3) -> Vector3 {
Vector3 {
x: self.x - other.x,
y: self.y - other.y,
z: self.z - other.z,
}
}
}
impl Mul<f64> for Vector3 {
type Output = Vector3;
fn mul(self, scalar: f64) -> Vector3 {
Vector3 {
x: self.x * scalar,
y: self.y * scalar,
z: self.z * scalar,
}
}
}
impl Div<f64> for Vector3 {
type Output = Vector3;
fn div(self, scalar: f64) -> Vector3 {
Vector3 {
x: self.x / scalar,
y: self.y / scalar,
z: self.z / scalar,
}
}
}
impl PartialEq<Self> for Vector3 {
fn eq(&self, other: &Self) -> bool {
(self.x - other.x).abs() < f64::EPSILON
&& (self.y - other.y).abs() < f64::EPSILON
&& (self.z - other.z).abs() < f64::EPSILON
}
}
impl From<(f64, f64, f64)> for Vector3 {
fn from(tuple: (f64, f64, f64)) -> Vector3 {
let (x, y, z) = tuple;
Vector3 { x, y, z }
}
}
impl TryFrom<String> for Vector3 {
type Error = Vector3Error;
fn try_from(string: String) -> Result<Vector3, Self::Error> {
let nums: Vec<f64> = string
.replace("(", "")
.replace(")", "")
.split(",")
.map(|s| s.trim().parse())
.flat_map(Result::ok)
.collect();
if nums.len() != 3 {
return Err(Vector3Error::new(Vector3ErrorKind::Deserialization(
Vector3DeserializationErrorKind::InsufficientNumberOfValues(nums.len()),
)));
}
Ok(Self::new(
nums[0],
nums[1],
nums[2],
))
}
}
impl Debug for Vector3 {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(&format!("({}, {}, {})", self.x, self.y, self.z))
}
}