From 192857eead5f5b6c57e23d4200e604deabf9cbe0 Mon Sep 17 00:00:00 2001 From: Matthew Gordon Date: Fri, 8 Nov 2019 07:25:15 -0500 Subject: [PATCH] Add Sphere struct, Intersect trait, and sphere-ray intersection --- src/lib.rs | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 66 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 03984cd..f0fd570 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,11 +19,57 @@ impl Ray { } } +#[derive(Debug)] +struct IntersectionInfo { + distance: T, + location: Vector3, +} + +trait Intersect { + fn intersect(&self, ray: &Ray) -> Option>; +} + +pub struct Sphere { + centre: Vector3, + radius: T, +} + +impl Sphere { + pub fn new(centre: Vector3, radius: T) -> Sphere { + Sphere { centre, radius } + } +} + +impl Intersect for Sphere { + fn intersect(&self, ray: &Ray) -> Option> { + // t0/p0 is the point on the ray that's closest to the centre of the sphere + let t0 = (self.centre - ray.origin).dot(&ray.direction); + let p0 = ray.point_at(t0); + if (self.centre - p0).norm() <= self.radius { + Some(IntersectionInfo { + distance: t0, + location: p0, + }) + } else { + None + } + } +} + #[cfg(test)] -extern crate quickcheck; -#[macro_use(quickcheck)] -extern crate quickcheck_macros; mod tests { + use quickcheck_macros::quickcheck; + + macro_rules! assert_matches { + ($expression:expr, $($pattern:tt)+) => { + match $expression { + $($pattern)+ => (), + ref e => panic!("assertion failed: `{:?}` does not match `{}`", e, + stringify!($($pattern)+)), + } + } + } + use super::*; use quickcheck::{Arbitrary, Gen}; impl Arbitrary for Ray { @@ -51,7 +97,9 @@ mod tests { let p3 = ray.point_at(t3); let epsilon = [t1, t2, t3, ray.origin[0], ray.origin[1], ray.origin[2]] .iter() - .fold(0.0, |a, &b| a.max(b.abs())) * std::f64::EPSILON * 128.0; + .fold(0.0, |a, &b| a.max(b.abs())) + * std::f64::EPSILON + * 256.0; (p2 - p1).cross(&(p3 - p2)).norm() < epsilon } @@ -59,4 +107,18 @@ mod tests { fn t_is_distance(ray: Ray, t: f64) -> bool { (ray.point_at(t) - ray.origin).norm() - t.abs() < 0.0000000001 } + + #[test] + fn ray_intersects_sphere() { + let r = Ray::new(Vector3::new(1.0, 2.0, 3.0), Vector3::new(0.0, 0.0, 1.0)); + let s = Sphere::new(Vector3::new(1.5, 1.5, 15.0), 5.0); + assert_matches!(s.intersect(&r), Some(_)); + } + + #[test] + fn ray_does_not_intersect_sphere() { + let r = Ray::new(Vector3::new(1.0, 2.0, 3.0), Vector3::new(0.0, 0.0, 1.0)); + let s = Sphere::new(Vector3::new(-5.0, 1.5, 15.0), 5.0); + assert_matches!(s.intersect(&r), None); + } }