use auto_ops::{impl_op_ex, impl_op_ex_commutative}; use std::fmt; pub type Point3 = Vec3; pub type Color = Vec3; #[derive(Clone, Default, Debug)] pub struct Vec3 { pub x: f64, pub y: f64, pub z: f64, } impl Vec3 { pub fn new() -> Vec3 { Vec3 { x: 0.0, y: 0.0, z: 0.0, } } pub fn get(&self, index: usize) -> Option<&f64> { match index { 0 => Some(&self.x), 1 => Some(&self.y), 2 => Some(&self.z), _ => None, } } pub fn get_mut(&mut self, index: usize) -> Option<&mut f64> { match index { 0 => Some(&mut self.x), 1 => Some(&mut self.y), 2 => Some(&mut self.z), _ => None, } } pub fn length(&self) -> f64 { self.length_squared().sqrt() } pub fn length_squared(&self) -> f64 { self.x * self.x + self.y * self.y + self.z * self.z } pub fn dot(&self, other: &Vec3) -> f64 { self.x * other.x + self.y * other.y + self.z * other.z } pub fn cross(&self, other: &Vec3) -> Vec3 { Vec3 { 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 unit_vector(&self) -> Vec3 { self / self.length() } pub fn random() -> Vec3 { Vec3 { x: rand::random::(), y: rand::random::(), z: rand::random::(), } } pub fn random_in_range(min: f64, max: f64) -> Vec3 { Vec3 { x: min + (max - min) * rand::random::(), y: min + (max - min) * rand::random::(), z: min + (max - min) * rand::random::(), } } pub fn random_in_unit_sphere() -> Vec3 { loop { let p = Vec3 { x: 2.0 * rand::random::() - 1.0, y: 2.0 * rand::random::() - 1.0, z: 2.0 * rand::random::() - 1.0, }; if p.length_squared() < 1.0 { return p; } }; } pub fn random_unit_vector() -> Vec3 { Self::random_in_unit_sphere().unit_vector() } pub fn random_in_unit_disk() -> Vec3 { loop { let p = Vec3 { x: 2.0 * rand::random::() -1.0, y: 2.0 * rand::random::() -1.0, z: 0.0, }; if p.length_squared() < 1.0 { return p; } } } pub fn near_zero(&self) -> bool { const S: f64 = 1e-8; self.x.abs() < S && self.y.abs() < S && self.z.abs() < S } pub fn reflect(&self, normal: &Vec3) -> Vec3 { self - 2.0 * self.dot(normal) * normal } pub fn refract(&self, normal: &Vec3, etai_over_etat: f64) -> Vec3 { let cos_theta = normal.dot(&-self).min(1.0); let r_out_perp = etai_over_etat * (self + cos_theta * normal); let r_out_parallel = -((1.0 - r_out_perp.length_squared()).abs().sqrt()) * normal; r_out_perp + r_out_parallel } pub fn has_infinite_member(&self) -> bool { self.x.is_infinite() || self.y.is_infinite() || self.z.is_infinite() } // fn hue_to_rgb(&self) -> f64 { // let mut z = self.z; // if z < 0.0 { z += 1.0 } // if z > 1.0 { z -= 1.0 } // if z < 1.0/6.0 { // self.x + (self.y - self.x) * 6.0 * z // } else if z < 1.0/2.0 { // self.y // } else if z < 2.0/3.0 { // self.x + (self.y - self.x) * (2.0/3.0 - z) * 6.0 // } else { // self.x // } // } fn hue_to_rgb(p: f64, q: f64, t:f64) -> f64 { let mut t = t; if t < 0.0 { t += 1.0 } if t > 1.0 { t -= 1.0 } if t < 1.0/6.0 { p + (q - p) * 6.0 * t } else if t < 1.0/2.0 { q } else if t < 2.0/3.0 { p + (q - p) * (2.0/3.0 - t) * 6.0 } else { p } } pub fn hsl_to_rgb(&self) -> Vec3 { if self.y == 0.0 { Vec3 {x: self.z, y: self.z, z: self.z} } else { let q = if self.z < 0.5 { self.z * (1.0 + self.y) } else { self.z + self.y - self.z * self.y }; let p = 2.0 * self.z - q; Vec3{x: Self::hue_to_rgb(p, q, self.x + 1.0/3.0), y: Self::hue_to_rgb(p, q, self.x), z: Self::hue_to_rgb(p, q, self.x - 1.0/3.0)} } } pub fn xy_diff(&self, func: &dyn Fn(&Vec3) -> f64) -> Vec3 { let h = f64::EPSILON.powf(1.0 / 3.0); let here = func(self); let x_there = func(&(self + Vec3{x: h, y: 0.0, z: 0.0 })); let y_there = func(&(self + Vec3{x: 0.0, y: h, z: 0.0 })); let x_diff = (x_there - here) / h; let y_diff = (y_there - here) / h; Vec3 { x: x_diff, y: y_diff, z: 0.0, } } } impl fmt::Display for Vec3 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{} {} {}", self.x, self.y, self.z) } } impl<'a> IntoIterator for &'a Vec3 { type Item = f64; type IntoIter = Vec3Iterator<'a>; fn into_iter(self) -> Self::IntoIter { Vec3Iterator { vec3: self, index: 0, } } } pub struct Vec3Iterator<'a> { vec3: &'a Vec3, index: usize, } impl<'a> Iterator for Vec3Iterator<'a> { type Item = f64; fn next(&mut self) -> Option { let result = match self.index { 0 => self.vec3.x, 1 => self.vec3.y, 2 => self.vec3.z, _ => return None, }; self.index += 1; Some(result) } } impl_op_ex!(- |a: &Vec3| -> Vec3 { Vec3 { x: -a.x, y: -a.y, z: -a.z, } }); impl_op_ex!(+= |lhs: &mut Vec3, rhs: Vec3| { *lhs = Vec3 { x: lhs.x + rhs.x, y: lhs.y + rhs.y, z: lhs.z + rhs.z } }); impl_op_ex!(*= |lhs: &mut Vec3, rhs: &f64| { *lhs = Vec3 { x: lhs.x * rhs, y: lhs.y * rhs, z: lhs.z * rhs } }); impl_op_ex!(/= |lhs: &mut Vec3, rhs: &f64| { *lhs *= 1.0 / rhs }); impl_op_ex!(+ |lhs: &Vec3, rhs: &Vec3| -> Vec3 { Vec3 { x: lhs.x + rhs.x, y: lhs.y + rhs.y, z: lhs.z + rhs.z } }); impl_op_ex!(-|lhs: &Vec3, rhs: &Vec3| -> Vec3 { Vec3 { x: lhs.x - rhs.x, y: lhs.y - rhs.y, z: lhs.z - rhs.z, } }); impl_op_ex!(*|lhs: &Vec3, rhs: &Vec3| -> Vec3 { Vec3 { x: lhs.x * rhs.x, y: lhs.y * rhs.y, z: lhs.z * rhs.z, } }); impl_op_ex_commutative!(*|lhs: &Vec3, rhs: &f64| -> Vec3 { Vec3 { x: lhs.x * rhs, y: lhs.y * rhs, z: lhs.z * rhs, } }); impl_op_ex!(/ |lhs: &Vec3, rhs: &f64| -> Vec3 { lhs * (1.0/rhs) });