use std::ops::{Add, Sub, Mul, Div, Neg};
use std::ops::{AddAssign, SubAssign, DivAssign, MulAssign};
use std::ops::{Index, IndexMut};
use std::cmp::PartialEq;
use std::str::FromStr;
use std::fmt;
use std::num;
#[derive(Debug, Clone, Copy)]
pub struct Vec3 {
pub x: f64,
pub y: f64,
pub z: f64,
}
impl Vec3 {
pub fn new<I: Into<f64>>(x: I, y: I, z: I) -> Vec3 {
Vec3 {
x: x.into(),
y: y.into(),
z: z.into(),
}
}
pub fn from_spherical<I: Into<f64>>(r: I, theta: I, phi: I) -> Vec3 {
let (r, theta, phi) = (r.into(), theta.into(), phi.into());
Vec3::new(r * f64::sin(theta) * f64::cos(phi),
r * f64::sin(theta) * f64::sin(phi),
r * f64::cos(theta))
}
pub fn zero() -> Vec3 {
Vec3::new(0.0, 0.0, 0.0)
}
pub fn dot(self, rhs: Vec3) -> f64 {
self.x * rhs.x + self.y * rhs.y + self.z * rhs.z
}
pub fn cross(self, rhs: Vec3) -> Self {
Self::new(self.y * rhs.z - self.z * rhs.y,
self.z * rhs.x - self.x * rhs.z,
self.x * rhs.y - self.y * rhs.x)
}
pub fn len(self) -> f64 {
self.dot(self).sqrt()
}
pub fn ort(self) -> Vec3 {
self / self.len()
}
pub fn sqr(self) -> Vec3 {
self * self
}
pub fn sqrt(self) -> Vec3 {
Vec3::new(self.x.sqrt(), self.y.sqrt(), self.z.sqrt())
}
pub fn dual_basis(basis: (Vec3, Vec3, Vec3)) -> (Vec3, Vec3, Vec3) {
let (a, b, c) = basis;
let triple_prod = a.cross(b).dot(c);
(b.cross(c) / triple_prod,
c.cross(a) / triple_prod,
a.cross(b) / triple_prod)
}
fn size(&self) -> usize { 3 }
}
op_default!(add, Add, +=, Vec3);
op_default!(sub, Sub, -=, Vec3);
op_default!(mul, Mul, *=, Vec3);
op_default!(f64, mul, Mul, *=, Vec3);
op_default!(f64, div, Div, /=, Vec3);
op_assign!(add_assign, AddAssign, +=, Vec3);
op_assign!(sub_assign, SubAssign, -=, Vec3);
op_assign!(mul_assign, MulAssign, *=, Vec3);
op_assign!(f64, mul_assign, MulAssign, *=, Vec3);
op_assign!(f64, div_assign, DivAssign, /=, Vec3);
impl Neg for Vec3 {
type Output = Self;
fn neg(self) -> Self {
Self::new(-self.x, -self.y, -self.z)
}
}
impl Index<usize> for Vec3 {
type Output = f64;
fn index(&self, index: usize) -> &Self::Output {
match index {
0 => &self.x,
1 => &self.y,
2 => &self.z,
i => panic!("Index {} out of [0, 2] range", i)
}
}
}
impl IndexMut<usize> for Vec3 {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
match index {
0 => &mut self.x,
1 => &mut self.y,
2 => &mut self.z,
i => panic!("Index {} out of [0, 2] range", i)
}
}
}
impl PartialEq for Vec3 {
fn eq(&self, other: &Self) -> bool {
self.x == other.x && self.y == other.y && self.z == other.z
}
}
impl fmt::Display for Vec3 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} {} {}", self.x, self.y, self.z)
}
}
impl FromStr for Vec3 {
type Err = num::ParseFloatError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let words: Vec<&str> = s.split_whitespace().collect();
let x: f64 = words[0].parse()?;
let y: f64 = words[1].parse()?;
let z: f64 = words[2].parse()?;
Ok(Self::new(x, y, z))
}
}
#[cfg(test)]
mod linal_test {
use super::*;
#[test]
fn vec3_mul() {
let a = Vec3::new(1, 2, 3);
let b = Vec3::new(3, 6, 9);
let r = a * 3;
let mut z = a;
let mut x = a;
z *= 3;
x *= b;
assert_eq!(r, b);
assert_eq!(z, b);
assert_eq!(x, Vec3::new(3, 12, 27));
}
#[test]
fn vec3_div() {
let a = Vec3::new(10, 20, 30);
let b = Vec3::new(1, 2, 3);
let mut z = a;
z /= 10;
assert_eq!(a / 10, b);
assert_eq!(z, b);
}
#[test]
fn vec3_div_inf() {
let a = Vec3::new(1, 2, 3);
let b = a / 0;
assert!(b.x.is_infinite() && b.y.is_infinite() && b.z.is_infinite());
}
#[test]
fn vec3_from_spherical() {
use std::f64::consts::PI;
let a = Vec3::from_spherical(5.0, PI / 2.0, 3f64.atan2(4.0));
let b = Vec3::new(4, 3, 0);
assert!((a - b).len() < 1e-10);
}
#[test]
fn vec3_add() {
let a = Vec3::new(1, 2, 3);
let b = Vec3::new(-3, 6, 4);
let c = Vec3::new(-2, 8, 7);
let mut z = a;
z += b;
assert_eq!(a + b, c);
assert_eq!(z, c);
}
#[test]
fn vec3_sub() {
let a = Vec3::new(1, 2, 3);
let b = Vec3::new(-3, 6, 4);
let c = Vec3::new(4, -4, -1);
let mut z = a;
z -= b;
assert_eq!(a - b, c);
assert_eq!(z, c);
}
#[test]
fn vec3_dot() {
let a = Vec3::new(1, 2, 3);
let b = Vec3::new(-3, 6, 4);
let c = 21.0;
assert_eq!(a.dot(b), c);
assert_eq!(b.dot(a), c);
}
#[test]
fn vec3_cross() {
let a = Vec3::new(4, 0, 0);
let b = Vec3::new(3, 5, 0);
let c = Vec3::new(0, 0, 20);
assert_eq!(a.cross(b), c);
assert_eq!(b.cross(a), -c);
}
#[test]
fn vec3_neg() {
let a = Vec3::new(1, 2, 3);
let b = Vec3::new(-1, -2, -3);
assert_eq!(-a, b);
}
#[test]
fn vec3_index() {
let a = Vec3::new(1, 2, 3);
assert_eq!(a[0], 1.0);
assert_eq!(a[1], 2.0);
assert_eq!(a[2], 3.0);
}
#[test]
#[should_panic]
fn vec3_index_out_of_range() {
let a = Vec3::new(1, 2, 3);
let _ = a[10];
}
#[test]
fn vec3_index_mut() {
let mut a = Vec3::zero();
for i in 0..3 {
a[i] = (i as f64 + 1.0).powi(2);
}
assert_eq!(a[0], 1.0);
assert_eq!(a[1], 4.0);
assert_eq!(a[2], 9.0);
}
#[test]
#[should_panic]
fn vec3_index_mut_out_of_range() {
let mut a = Vec3::zero();
a[10] = 10.0;
}
#[test]
fn vec3_parse() {
let a: Vec3 = "1 2 3".parse().unwrap();
assert_eq!(a, Vec3::new(1, 2, 3));
}
}