camera: moving another doctest to unit

This commit is contained in:
Bill Thiede 2021-07-30 21:44:58 -07:00
parent e3d8988658
commit 3838efd134

View File

@ -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());
}
}