diff options
Diffstat (limited to 'src/vec3.rs')
-rw-r--r-- | src/vec3.rs | 260 |
1 files changed, 260 insertions, 0 deletions
diff --git a/src/vec3.rs b/src/vec3.rs new file mode 100644 index 0000000..1bf864d --- /dev/null +++ b/src/vec3.rs @@ -0,0 +1,260 @@ +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::<f64>(), + y: rand::random::<f64>(), + z: rand::random::<f64>(), + } + } + + pub fn random_in_range(min: f64, max: f64) -> Vec3 { + Vec3 { + x: min + (max - min) * rand::random::<f64>(), + y: min + (max - min) * rand::random::<f64>(), + z: min + (max - min) * rand::random::<f64>(), + } + } + + pub fn random_in_unit_sphere() -> Vec3 { + loop { + let p = Vec3 { + x: 2.0 * rand::random::<f64>() - 1.0, + y: 2.0 * rand::random::<f64>() - 1.0, + z: 2.0 * rand::random::<f64>() - 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::<f64>() -1.0, + y: 2.0 * rand::random::<f64>() -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<f64> { + 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) }); |