summaryrefslogtreecommitdiff
path: root/src/vec3.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/vec3.rs')
-rw-r--r--src/vec3.rs260
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) });