diff --git a/rtchallenge/src/intersections.rs b/rtchallenge/src/intersections.rs index 72bf17c..219cbf6 100644 --- a/rtchallenge/src/intersections.rs +++ b/rtchallenge/src/intersections.rs @@ -2,7 +2,7 @@ use std::ops::Index; use crate::spheres::Sphere; -#[derive(Debug, PartialEq)] +#[derive(Debug, Clone, PartialEq)] pub struct Intersection<'i> { pub t: f32, pub object: &'i Sphere, @@ -60,8 +60,56 @@ impl<'i> Intersections<'i> { pub fn len(&self) -> usize { self.0.len() } + /// Finds nearest hit for this collection of intersections. + /// + /// # Examples + /// ``` + /// use rtchallenge::{ + /// intersections::{Intersection, Intersections}, + /// rays::Ray, + /// spheres::{intersect, Sphere}, + /// tuples::Tuple, + /// }; + /// + /// // The hit, when all intersections have positive t. + /// let s = Sphere::default(); + /// let i1 = Intersection::new(1., &s); + /// let i2 = Intersection::new(2., &s); + /// let xs = Intersections::new(vec![i2, i1.clone()]); + /// let i = xs.hit(); + /// assert_eq!(i, Some(&i1)); + /// + /// // The hit, when some intersections have negative t. + /// let s = Sphere::default(); + /// let i1 = Intersection::new(-1., &s); + /// let i2 = Intersection::new(1., &s); + /// let xs = Intersections::new(vec![i2.clone(), i1]); + /// let i = xs.hit(); + /// assert_eq!(i, Some(&i2)); + /// + /// // The hit, when all intersections have negative t. + /// let s = Sphere::default(); + /// let i1 = Intersection::new(-2., &s); + /// let i2 = Intersection::new(-1., &s); + /// let xs = Intersections::new(vec![i2, i1]); + /// let i = xs.hit(); + /// assert_eq!(i, None); + /// + /// // The hit is always the lowest nonnegative intersection. + /// let s = Sphere::default(); + /// let i1 = Intersection::new(5., &s); + /// let i2 = Intersection::new(7., &s); + /// let i3 = Intersection::new(-3., &s); + /// let i4 = Intersection::new(2., &s); + /// let xs = Intersections::new(vec![i1, i2, i3, i4.clone()]); + /// let i = xs.hit(); + /// assert_eq!(i, Some(&i4)); + /// ``` pub fn hit(&self) -> Option<&Intersection> { - todo!("Intersections::hit") + self.0.iter().filter(|i| i.t > 0.).min_by(|i1, i2| { + i1.t.partial_cmp(&i2.t) + .expect("an intersection has a t value that is NaN") + }) } }