use std::convert::From; use std::fmt; use std::num::ParseFloatError; use std::ops::Add; use std::ops::Div; use std::ops::Index; use std::ops::Mul; use std::ops::Neg; use std::ops::Sub; use std::str; use serde_derive::Deserialize; use serde_derive::Serialize; #[derive(Default, Debug, Deserialize, Serialize, PartialEq, Copy, Clone)] pub struct Vec3 { pub x: f32, pub y: f32, pub z: f32, } pub fn cross(v1: Vec3, v2: Vec3) -> Vec3 { Vec3 { x: v1.y * v2.z - v1.z * v2.y, y: v1.z * v2.x - v1.x * v2.z, z: v1.x * v2.y - v1.y * v2.x, } } pub fn dot(v1: Vec3, v2: Vec3) -> f32 { v1.x * v2.x + v1.y * v2.y + v1.z * v2.z } impl Vec3 { pub fn new(x: f32, y: f32, z: f32) -> Vec3 { Vec3 { x, y, z } } pub fn min(self) -> f32 { self.x.min(self.y).min(self.z) } pub fn max(self) -> f32 { self.x.max(self.y).max(self.z) } pub fn length(self) -> f32 { self.squared_length().sqrt() } pub fn squared_length(self) -> f32 { self.x * self.x + self.y * self.y + self.z * self.z } pub fn unit_vector(self) -> Vec3 { self / self.length() } pub fn make_unit_vector(&mut self) { *self = self.unit_vector(); } } impl From<[f32; 3]> for Vec3 { fn from(v: [f32; 3]) -> Self { Vec3 { x: v[0], y: v[1], z: v[2], } } } impl fmt::Display for Vec3 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{} {} {}", self.x, self.y, self.z) } } impl str::FromStr for Vec3 { type Err = ParseFloatError; fn from_str(s: &str) -> Result { let coords: Vec<&str> = s.split(' ').collect(); Ok(Vec3 { x: coords[0].parse::()?, y: coords[1].parse::()?, z: coords[2].parse::()?, }) } } impl Add for Vec3 { type Output = Vec3; fn add(self, r: f32) -> Vec3 { Vec3 { x: self.x + r, y: self.y + r, z: self.z + r, } } } impl Add for Vec3 { type Output = Vec3; fn add(self, r: Vec3) -> Vec3 { Vec3 { x: self.x + r.x, y: self.y + r.y, z: self.z + r.z, } } } impl Div for f32 { type Output = Vec3; fn div(self, r: Vec3) -> Vec3 { Vec3 { x: self / r.x, y: self / r.y, z: self / r.z, } } } impl Div for Vec3 { type Output = Vec3; fn div(self, r: f32) -> Vec3 { Vec3 { x: self.x / r, y: self.y / r, z: self.z / r, } } } impl Index for Vec3 { type Output = f32; fn index(&self, idx: usize) -> &f32 { match idx { 0 => &self.x, 1 => &self.y, 2 => &self.z, _ => panic!(format!("idx {} out of range for vec3", idx)), } } } impl Mul for Vec3 { type Output = Vec3; fn mul(self, r: Vec3) -> Vec3 { Vec3 { x: self.x * r.x, y: self.y * r.y, z: self.z * r.z, } } } impl Mul for f32 { type Output = Vec3; fn mul(self, v: Vec3) -> Vec3 { Vec3 { x: v.x * self, y: v.y * self, z: v.z * self, } } } impl Mul for Vec3 { type Output = Vec3; fn mul(self, r: f32) -> Vec3 { Vec3 { x: self.x * r, y: self.y * r, z: self.z * r, } } } impl Neg for Vec3 { type Output = Vec3; fn neg(self) -> Vec3 { -1. * self } } impl Sub for Vec3 { type Output = Vec3; fn sub(self, r: Vec3) -> Vec3 { Vec3 { x: self.x - r.x, y: self.y - r.y, z: self.z - r.z, } } } #[cfg(test)] mod tests { use std::f32::consts::PI; use std::str::FromStr; use super::*; #[test] fn vec_add() { let v0 = Vec3::new(1., 2., 3.); let v1 = Vec3::new(1., 1., 1.); assert_eq!(v0 + v1, Vec3::new(2., 3., 4.)); } #[test] fn vec_div() { let v0 = Vec3::new(1., 2., 4.); assert_eq!(v0 / 2., Vec3::new(0.5, 1., 2.)); } #[test] fn vec_mul() { let v0 = Vec3::new(1., 2., 4.); assert_eq!(v0 * 0.5, Vec3::new(0.5, 1., 2.)); assert_eq!(v0 * v0, Vec3::new(1., 4., 16.)); } #[test] fn vec_sub() { let v0 = Vec3::new(1., 2., 3.); let v1 = Vec3::new(1., 1., 1.); assert_eq!(v0 - v1, Vec3::new(0., 1., 2.)); } #[test] fn vec_idx() { let v0 = Vec3::new(1., 2., 3.); assert_eq!(v0[2], 3.); } #[test] fn vec_display() { let v0 = Vec3::new(1., 2., 3.); assert_eq!(format!("{}", v0), "1 2 3".to_owned()); } #[test] fn vec_from_str() { assert_eq!(Vec3::from_str("1. 2. 3.").unwrap(), Vec3::new(1., 2., 3.)); } #[test] fn vec_str_roundtrip() { let v = Vec3::from_str("1 2 3").unwrap(); let s = format!("{}", v); assert_eq!(v, Vec3::from_str(&s).unwrap()); } #[test] fn vec_dot() { let v0 = Vec3::new(1., 0., 0.); let v1 = Vec3::new(-1., 0., 0.); assert_eq!(dot(v0, v1), v0.length() * v1.length() * PI.cos()); } #[test] fn vec_cross() { let v0 = Vec3::new(1., 0., 0.); let v1 = Vec3::new(0., 1., 0.); assert_eq!(cross(v0, v1), Vec3::new(0., 0., 1.)); } }