spheres: implement normal_at.

This commit is contained in:
Bill Thiede 2021-07-17 07:57:59 -07:00
parent e430e3769e
commit 6e7bd1c136

View File

@ -3,6 +3,7 @@ use crate::{
matrices::Matrix4x4,
rays::Ray,
tuples::{dot, Tuple},
EPSILON,
};
#[derive(Debug, PartialEq)]
@ -34,6 +35,65 @@ impl Default for Sphere {
}
}
impl Sphere {
/// Find the normal at the point on the sphere.
///
/// # Examples
/// ```
/// use rtchallenge::{matrices::Matrix4x4, spheres::Sphere, tuples::Tuple};
///
/// // Normal on X-axis
/// let s = Sphere::default();
/// let n = s.normal_at(Tuple::point(1., 0., 0.));
/// assert_eq!(n, Tuple::vector(1., 0., 0.));
///
/// // Normal on Y-axis
/// let s = Sphere::default();
/// let n = s.normal_at(Tuple::point(0., 1., 0.));
/// assert_eq!(n, Tuple::vector(0., 1., 0.));
///
/// // Normal on Z-axis
/// let s = Sphere::default();
/// let n = s.normal_at(Tuple::point(0., 0., 1.));
/// assert_eq!(n, Tuple::vector(0., 0., 1.));
///
/// // Normal on a sphere at a nonaxial point.
/// let s = Sphere::default();
/// let n = s.normal_at(Tuple::point(
/// 3_f32.sqrt() / 3.,
/// 3_f32.sqrt() / 3.,
/// 3_f32.sqrt() / 3.,
/// ));
/// assert_eq!(
/// n,
/// Tuple::vector(3_f32.sqrt() / 3., 3_f32.sqrt() / 3., 3_f32.sqrt() / 3.,)
/// );
/// // Normals returned are normalized.
/// let s = Sphere::default();
/// let n = s.normal_at(Tuple::point(
/// 3_f32.sqrt() / 3.,
/// 3_f32.sqrt() / 3.,
/// 3_f32.sqrt() / 3.,
/// ));
/// assert_eq!(n, n.normalize());
/// ```
/// ```should_panic
/// use rtchallenge::{spheres::Sphere, tuples::Tuple};
///
/// // In debug builds points not on the sphere should fail.
/// let s = Sphere::default();
/// let n = s.normal_at(Tuple::point(0., 0., 0.5));
/// ```
pub fn normal_at(&self, point: Tuple) -> Tuple {
debug_assert!(
((point - Tuple::point(0., 0., 0.)).magnitude() - 1.).abs() < EPSILON,
"{} != 1.",
(point - Tuple::point(0., 0., 0.)).magnitude()
);
(point - Tuple::point(0., 0., 0.)).normalize()
}
}
/// Intersect a ray with a sphere.
///
/// # Examples