From af7d8680a0f6c806c399cce083497599c3493427 Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Sun, 23 Jun 2024 14:13:02 -0400 Subject: [PATCH] Translate and scale a ray --- ray-tracer/src/types/ray.rs | 58 +++++++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 16 deletions(-) diff --git a/ray-tracer/src/types/ray.rs b/ray-tracer/src/types/ray.rs index 87f590c..6b904b8 100644 --- a/ray-tracer/src/types/ray.rs +++ b/ray-tracer/src/types/ray.rs @@ -1,7 +1,6 @@ +use crate::types::{Matrix, Point, Sphere, Vector}; use std::cmp::Ordering; -use crate::types::{Point, Sphere, Vector}; - #[derive(Clone, Debug, PartialEq)] pub struct Intersection<'a> { t: f64, @@ -10,7 +9,7 @@ pub struct Intersection<'a> { pub struct Intersections<'a>(Vec>); -impl <'a> Intersections<'a> { +impl<'a> Intersections<'a> { pub fn len(&'a self) -> usize { self.0.len() } @@ -20,14 +19,14 @@ impl <'a> Intersections<'a> { } } -impl <'a> std::ops::Index for Intersections<'a> { +impl<'a> std::ops::Index for Intersections<'a> { type Output = Intersection<'a>; fn index(&self, idx: usize) -> &Intersection<'a> { &self.0[idx] } } -impl <'a> From>> for Intersections<'a> { +impl<'a> From>> for Intersections<'a> { fn from(mut v: Vec>) -> Self { v.sort_by(|l, r| l.t.partial_cmp(&r.t).unwrap_or(Ordering::Equal)); Self(v) @@ -65,13 +64,22 @@ impl Ray { vec![ Intersection { t: t1, object: &s }, Intersection { t: t2, object: &s }, - ].into() + ] + .into() + } + + pub fn transform(&self, m: Matrix) -> Self { + Self { + origin: m.clone() * self.origin, + direction: m * self.direction, + } } } #[cfg(test)] mod tests { use super::*; + use crate::transforms::{scaling, translation}; #[test] fn computing_point_from_distance() { @@ -135,8 +143,8 @@ mod tests { #[test] fn hit_all_intersections_are_positive() { let s = Sphere::new(); - let i1 = Intersection{ t: 1., object: &s }; - let i2 = Intersection{ t: 2., object: &s }; + let i1 = Intersection { t: 1., object: &s }; + let i2 = Intersection { t: 2., object: &s }; let xs = Intersections::from(vec![i1.clone(), i2]); assert_eq!(xs.hit(), Some(&i1)); @@ -145,8 +153,8 @@ mod tests { #[test] fn hit_some_intersections_are_negative() { let s = Sphere::new(); - let i1 = Intersection{ t: -1., object: &s }; - let i2 = Intersection{ t: 1., object: &s }; + let i1 = Intersection { t: -1., object: &s }; + let i2 = Intersection { t: 1., object: &s }; let xs = Intersections::from(vec![i1, i2.clone()]); assert_eq!(xs.hit(), Some(&i2)); @@ -155,8 +163,8 @@ mod tests { #[test] fn hit_all_intersections_are_negative() { let s = Sphere::new(); - let i1 = Intersection{ t: -2., object: &s }; - let i2 = Intersection{ t: -1., object: &s }; + let i1 = Intersection { t: -2., object: &s }; + let i2 = Intersection { t: -1., object: &s }; let xs = Intersections::from(vec![i1, i2]); assert_eq!(xs.hit(), None); @@ -165,12 +173,30 @@ mod tests { #[test] fn hit_is_always_lowest_nonnegative() { let s = Sphere::new(); - let i1 = Intersection{ t: 5., object: &s }; - let i2 = Intersection{ t: 7., object: &s }; - let i3 = Intersection{ t: -3., object: &s }; - let i4 = Intersection{ t: 2., object: &s }; + let i1 = Intersection { t: 5., object: &s }; + let i2 = Intersection { t: 7., object: &s }; + let i3 = Intersection { t: -3., object: &s }; + let i4 = Intersection { t: 2., object: &s }; let xs = Intersections::from(vec![i1, i2, i3, i4.clone()]); assert_eq!(xs.hit(), Some(&i4)); } + + #[test] + fn translate_a_ray() { + let r = Ray::new(Point::new(1., 2., 3.), Vector::new(0., 1., 0.)); + let m = translation(3., 4., 5.); + let r2 = r.transform(m); + assert_eq!(r2.origin, Point::new(4., 6., 8.)); + assert_eq!(r2.direction, Vector::new(0., 1., 0.)); + } + + #[test] + fn scale_a_ray() { + let r = Ray::new(Point::new(1., 2., 3.), Vector::new(0., 1., 0.)); + let m = scaling(2., 3., 4.); + let r2 = r.transform(m); + assert_eq!(r2.origin, Point::new(2., 6., 12.)); + assert_eq!(r2.direction, Vector::new(0., 3., 0.,)); + } }