aboutsummaryrefslogtreecommitdiff
path: root/src/vec3.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/vec3.rs')
-rw-r--r--src/vec3.rs201
1 files changed, 201 insertions, 0 deletions
diff --git a/src/vec3.rs b/src/vec3.rs
new file mode 100644
index 0000000..8525fdd
--- /dev/null
+++ b/src/vec3.rs
@@ -0,0 +1,201 @@
+use auto_ops::{impl_op_ex, impl_op_ex_commutative};
+use std::fmt;
+
+pub type Point3 = Vec3;
+pub type Color = Vec3;
+
+#[derive(Clone, Default)]
+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()
+ }
+}
+
+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) });