diff --git a/rtchallenge/src/camera.rs b/rtchallenge/src/camera.rs index e94a25c..f7ddb4f 100644 --- a/rtchallenge/src/camera.rs +++ b/rtchallenge/src/camera.rs @@ -118,27 +118,6 @@ enum Response { impl Camera { /// Create a camera with a canvas of pixel hsize (height) and vsize (width) /// with the given field of view (in radians). - /// - /// # Examples - /// ``` - /// use rtchallenge::{camera::Camera, float::consts::PI, matrices::Matrix4x4, EPSILON}; - /// - /// let hsize = 160; - /// let vsize = 120; - /// let field_of_view = PI / 2.; - /// let c = Camera::new(hsize, vsize, field_of_view); - /// assert_eq!(c.hsize(), 160); - /// assert_eq!(c.vsize(), 120); - /// assert_eq!(c.transform(), Matrix4x4::identity()); - /// - /// // Pixel size for a horizontal canvas. - /// let c = Camera::new(200, 150, PI / 2.); - /// assert!((c.pixel_size() - 0.010).abs() < EPSILON); - /// - /// // Pixel size for a horizontal canvas. - /// let c = Camera::new(150, 200, PI / 2.); - /// assert!((c.pixel_size() - 0.010).abs() < EPSILON); - /// ``` pub fn new(hsize: usize, vsize: usize, field_of_view: Float) -> Camera { let half_view = (field_of_view / 2.).tan(); let aspect = hsize as Float / vsize as Float; @@ -208,35 +187,6 @@ impl Camera { /// Calculate ray that starts at the camera and passes through the (x,y) /// pixel on the canvas. - /// - /// # Examples - /// ``` - /// use rtchallenge::{ - /// camera::Camera, float::consts::PI, matrices::Matrix4x4, tuples::Tuple, Float, - /// }; - /// - /// // Constructing a ray through the center of the canvas. - /// let c = Camera::new(201, 101, PI / 2.); - /// let r = c.ray_for_pixel(100, 50); - /// assert_eq!(r.origin, Tuple::point(0., 0., 0.)); - /// assert_eq!(r.direction, Tuple::vector(0., 0., -1.)); - /// - /// // Constructing a ray through the corner of the canvas. - /// let c = Camera::new(201, 101, PI / 2.); - /// let r = c.ray_for_pixel(0, 0); - /// assert_eq!(r.origin, Tuple::point(0., 0., 0.)); - /// assert_eq!(r.direction, Tuple::vector(0.66519, 0.33259, -0.66851)); - /// - /// // Constructing a ray when the camera is transformed. - /// let mut c = Camera::new(201, 101, PI / 2.); - /// c.set_transform(Matrix4x4::rotation_y(PI / 4.) * Matrix4x4::translation(0., -2., 5.)); - /// let r = c.ray_for_pixel(100, 50); - /// assert_eq!(r.origin, Tuple::point(0., 2., -5.)); - /// assert_eq!( - /// r.direction, - /// Tuple::vector((2. as Float).sqrt() / 2., 0., -(2. as Float).sqrt() / 2.) - /// ); - /// ``` pub fn ray_for_pixel(&self, px: usize, py: usize) -> Ray { // The offset from the edge of the canvas to the pixel's corner. let xoffset = (px as Float + 0.5) * self.pixel_size; @@ -258,26 +208,6 @@ impl Camera { } /// Use camera to render an image of the given world. - /// # Examples - /// ``` - /// use rtchallenge::{ - /// camera::Camera, - /// float::consts::PI, - /// transformations::view_transform, - /// tuples::{Color, Tuple}, - /// world::World, - /// }; - /// - /// // Rendering a world with a camera. - /// let w = World::test_world(); - /// let mut c = Camera::new(11, 11, PI / 2.); - /// let from = Tuple::point(0., 0., -5.); - /// let to = Tuple::point(0., 0., 0.); - /// let up = Tuple::vector(0., 1., 0.); - /// c.set_transform(view_transform(from, to, up)); - /// let image = c.render(&w); - /// assert_eq!(image.get(5, 5), Color::new(0.38066, 0.47583, 0.2855)); - /// ``` pub fn render(&self, w: &World) -> Canvas { use RenderStrategy::*; @@ -437,3 +367,70 @@ fn render_worker_task( } } } + +#[cfg(test)] +mod tests { + use crate::{ + camera::Camera, + float::consts::PI, + matrices::Matrix4x4, + transformations::view_transform, + tuples::{point, vector}, + world::World, + Float, EPSILON, + }; + #[test] + fn new() { + let hsize = 160; + let vsize = 120; + let field_of_view = PI / 2.; + let c = Camera::new(hsize, vsize, field_of_view); + assert_eq!(c.hsize(), 160); + assert_eq!(c.vsize(), 120); + assert_eq!(c.transform(), Matrix4x4::identity()); + + // Pixel size for a horizontal canvas. + let c = Camera::new(200, 150, PI / 2.); + assert!((c.pixel_size() - 0.010).abs() < EPSILON); + + // Pixel size for a horizontal canvas. + let c = Camera::new(150, 200, PI / 2.); + assert!((c.pixel_size() - 0.010).abs() < EPSILON); + } + #[test] + fn ray_for_pixel() { + // Constructing a ray through the center of the canvas. + let c = Camera::new(201, 101, PI / 2.); + let r = c.ray_for_pixel(100, 50); + assert_eq!(r.origin, point(0., 0., 0.)); + assert_eq!(r.direction, vector(0., 0., -1.)); + + // Constructing a ray through the corner of the canvas. + let c = Camera::new(201, 101, PI / 2.); + let r = c.ray_for_pixel(0, 0); + assert_eq!(r.origin, point(0., 0., 0.)); + assert_eq!(r.direction, vector(0.66519, 0.33259, -0.66851)); + + // Constructing a ray when the camera is transformed. + let mut c = Camera::new(201, 101, PI / 2.); + c.set_transform(Matrix4x4::rotation_y(PI / 4.) * Matrix4x4::translation(0., -2., 5.)); + let r = c.ray_for_pixel(100, 50); + assert_eq!(r.origin, point(0., 2., -5.)); + assert_eq!( + r.direction, + vector((2. as Float).sqrt() / 2., 0., -(2. as Float).sqrt() / 2.) + ); + } + #[test] + fn render() { + // Rendering a world with a camera. + let w = World::test_world(); + let mut c = Camera::new(11, 11, PI / 2.); + let from = point(0., 0., -5.); + let to = point(0., 0., 0.); + let up = vector(0., 1., 0.); + c.set_transform(view_transform(from, to, up)); + let image = c.render(&w); + assert_eq!(image.get(5, 5), [0.38066, 0.47583, 0.2855].into()); + } +}