all: s/f32/Float/g now using customer Float alias.

This commit is contained in:
Bill Thiede 2021-07-18 17:18:08 -07:00
parent 5d57304d95
commit 95de5863cc
9 changed files with 147 additions and 123 deletions

View File

@ -8,6 +8,7 @@ edition = "2018"
[features] [features]
disable_inverse_cache = [] disable_inverse_cache = []
float-as-double = []
[dependencies] [dependencies]
anyhow = "1.0.41" anyhow = "1.0.41"

View File

@ -12,7 +12,9 @@ use rayon::iter::{IntoParallelIterator, ParallelIterator};
use serde::Deserialize; use serde::Deserialize;
use structopt::StructOpt; use structopt::StructOpt;
use crate::{canvas::Canvas, matrices::Matrix4x4, rays::Ray, tuples::Tuple, world::World, BLACK}; use crate::{
canvas::Canvas, matrices::Matrix4x4, rays::Ray, tuples::Tuple, world::World, Float, BLACK,
};
#[derive(Copy, Clone, StructOpt, Debug, Deserialize)] #[derive(Copy, Clone, StructOpt, Debug, Deserialize)]
#[serde(rename_all = "kebab-case")] #[serde(rename_all = "kebab-case")]
@ -32,12 +34,12 @@ impl FromStr for RenderStrategy {
pub struct Camera { pub struct Camera {
hsize: usize, hsize: usize,
vsize: usize, vsize: usize,
field_of_view: f32, field_of_view: Float,
transform: Matrix4x4, transform: Matrix4x4,
inverse_transform: Matrix4x4, inverse_transform: Matrix4x4,
pixel_size: f32, pixel_size: Float,
half_width: f32, half_width: Float,
half_height: f32, half_height: Float,
pub render_strategy: RenderStrategy, pub render_strategy: RenderStrategy,
} }
@ -55,9 +57,7 @@ impl Camera {
/// ///
/// # Examples /// # Examples
/// ``` /// ```
/// use std::f32::consts::PI; /// use rtchallenge::{camera::Camera, float::consts::PI, matrices::Matrix4x4};
///
/// use rtchallenge::{camera::Camera, matrices::Matrix4x4};
/// ///
/// let hsize = 160; /// let hsize = 160;
/// let vsize = 120; /// let vsize = 120;
@ -75,15 +75,15 @@ impl Camera {
/// let c = Camera::new(150, 200, PI / 2.); /// let c = Camera::new(150, 200, PI / 2.);
/// assert_eq!(c.pixel_size(), 0.01); /// assert_eq!(c.pixel_size(), 0.01);
/// ``` /// ```
pub fn new(hsize: usize, vsize: usize, field_of_view: f32) -> Camera { pub fn new(hsize: usize, vsize: usize, field_of_view: Float) -> Camera {
let half_view = (field_of_view / 2.).tan(); let half_view = (field_of_view / 2.).tan();
let aspect = hsize as f32 / vsize as f32; let aspect = hsize as Float / vsize as Float;
let (half_width, half_height) = if aspect >= 1. { let (half_width, half_height) = if aspect >= 1. {
(half_view, half_view / aspect) (half_view, half_view / aspect)
} else { } else {
(half_view * aspect, half_view) (half_view * aspect, half_view)
}; };
let pixel_size = 2. * half_width / hsize as f32; let pixel_size = 2. * half_width / hsize as Float;
Camera { Camera {
hsize, hsize,
vsize, vsize,
@ -102,7 +102,7 @@ impl Camera {
pub fn vsize(&self) -> usize { pub fn vsize(&self) -> usize {
self.vsize self.vsize
} }
pub fn field_of_view(&self) -> f32 { pub fn field_of_view(&self) -> Float {
self.field_of_view self.field_of_view
} }
pub fn transform(&self) -> Matrix4x4 { pub fn transform(&self) -> Matrix4x4 {
@ -112,7 +112,7 @@ impl Camera {
self.transform = t; self.transform = t;
self.inverse_transform = t.inverse(); self.inverse_transform = t.inverse();
} }
pub fn pixel_size(&self) -> f32 { pub fn pixel_size(&self) -> Float {
self.pixel_size self.pixel_size
} }
pub fn supersample_rays_for_pixel(&self, px: usize, py: usize, samples: usize) -> Vec<Ray> { pub fn supersample_rays_for_pixel(&self, px: usize, py: usize, samples: usize) -> Vec<Ray> {
@ -121,8 +121,8 @@ impl Camera {
(0..samples) (0..samples)
.map(|_| { .map(|_| {
// The offset from the edge of the canvas to the pixel's corner. // The offset from the edge of the canvas to the pixel's corner.
let xoffset = (px as f32 + rng.gen::<f32>()) * self.pixel_size; let xoffset = (px as Float + rng.gen::<Float>()) * self.pixel_size;
let yoffset = (py as f32 + rng.gen::<f32>()) * self.pixel_size; let yoffset = (py as Float + rng.gen::<Float>()) * self.pixel_size;
// The untransformed coordinates of the pixle in world space. // The untransformed coordinates of the pixle in world space.
// (Remember that the camera looks toward -z, so +x is to the left.) // (Remember that the camera looks toward -z, so +x is to the left.)
@ -146,9 +146,9 @@ impl Camera {
/// ///
/// # Examples /// # Examples
/// ``` /// ```
/// use std::f32::consts::PI; /// use rtchallenge::{
/// /// camera::Camera, float::consts::PI, matrices::Matrix4x4, tuples::Tuple, Float,
/// use rtchallenge::{camera::Camera, matrices::Matrix4x4, tuples::Tuple}; /// };
/// ///
/// // Constructing a ray through the center of the canvas. /// // Constructing a ray through the center of the canvas.
/// let c = Camera::new(201, 101, PI / 2.); /// let c = Camera::new(201, 101, PI / 2.);
@ -169,14 +169,14 @@ impl Camera {
/// assert_eq!(r.origin, Tuple::point(0., 2., -5.)); /// assert_eq!(r.origin, Tuple::point(0., 2., -5.));
/// assert_eq!( /// assert_eq!(
/// r.direction, /// r.direction,
/// Tuple::vector(2_f32.sqrt() / 2., 0., -2_f32.sqrt() / 2.) /// Tuple::vector((2. as Float).sqrt() / 2., 0., -(2. as Float).sqrt() / 2.)
/// ); /// );
/// ``` /// ```
#[cfg(not(feature = "disable_inverse_cache"))] #[cfg(not(feature = "disable_inverse_cache"))]
pub fn ray_for_pixel(&self, px: usize, py: usize) -> Ray { pub fn ray_for_pixel(&self, px: usize, py: usize) -> Ray {
// The offset from the edge of the canvas to the pixel's corner. // The offset from the edge of the canvas to the pixel's corner.
let xoffset = (px as f32 + 0.5) * self.pixel_size; let xoffset = (px as Float + 0.5) * self.pixel_size;
let yoffset = (py as f32 + 0.5) * self.pixel_size; let yoffset = (py as Float + 0.5) * self.pixel_size;
// The untransformed coordinates of the pixle in world space. // The untransformed coordinates of the pixle in world space.
// (Remember that the camera looks toward -z, so +x is to the left.) // (Remember that the camera looks toward -z, so +x is to the left.)
@ -195,8 +195,8 @@ impl Camera {
#[cfg(feature = "disable_inverse_cache")] #[cfg(feature = "disable_inverse_cache")]
pub fn ray_for_pixel(&self, px: usize, py: usize) -> Ray { pub fn ray_for_pixel(&self, px: usize, py: usize) -> Ray {
// The offset from the edge of the canvas to the pixel's corner. // The offset from the edge of the canvas to the pixel's corner.
let xoffset = (px as f32 + 0.5) * self.pixel_size; let xoffset = (px as Float + 0.5) * self.pixel_size;
let yoffset = (py as f32 + 0.5) * self.pixel_size; let yoffset = (py as Float + 0.5) * self.pixel_size;
// The untransformed coordinates of the pixle in world space. // The untransformed coordinates of the pixle in world space.
// (Remember that the camera looks toward -z, so +x is to the left.) // (Remember that the camera looks toward -z, so +x is to the left.)
@ -216,10 +216,9 @@ impl Camera {
/// Use camera to render an image of the given world. /// Use camera to render an image of the given world.
/// # Examples /// # Examples
/// ``` /// ```
/// use std::f32::consts::PI;
///
/// use rtchallenge::{ /// use rtchallenge::{
/// camera::Camera, /// camera::Camera,
/// float::consts::PI,
/// transformations::view_transform, /// transformations::view_transform,
/// tuples::{Color, Tuple}, /// tuples::{Color, Tuple},
/// world::World, /// world::World,
@ -330,7 +329,7 @@ impl Camera {
.iter() .iter()
.map(|ray| w.color_at(&ray)) .map(|ray| w.color_at(&ray))
.fold(BLACK, |acc, c| acc + c); .fold(BLACK, |acc, c| acc + c);
row_image.set(x, 0, color / SAMPLES as f32); row_image.set(x, 0, color / SAMPLES as Float);
} else { } else {
let ray = self.ray_for_pixel(x, y); let ray = self.ray_for_pixel(x, y);
let color = w.color_at(&ray); let color = w.color_at(&ray);

View File

@ -4,12 +4,12 @@ use crate::{
rays::Ray, rays::Ray,
spheres::Sphere, spheres::Sphere,
tuples::{dot, Tuple}, tuples::{dot, Tuple},
EPSILON, Float, EPSILON,
}; };
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct Intersection<'i> { pub struct Intersection<'i> {
pub t: f32, pub t: Float,
pub object: &'i Sphere, pub object: &'i Sphere,
} }
@ -26,7 +26,7 @@ impl<'i> Intersection<'i> {
/// assert_eq!(i.t, 3.5); /// assert_eq!(i.t, 3.5);
/// assert_eq!(i.object, &s); /// assert_eq!(i.object, &s);
/// ``` /// ```
pub fn new(t: f32, object: &Sphere) -> Intersection { pub fn new(t: Float, object: &Sphere) -> Intersection {
Intersection { t, object } Intersection { t, object }
} }
} }
@ -137,7 +137,7 @@ impl<'i> Index<usize> for Intersections<'i> {
#[derive(Debug)] #[derive(Debug)]
pub struct PrecomputedData<'i> { pub struct PrecomputedData<'i> {
pub t: f32, pub t: Float,
pub object: &'i Sphere, pub object: &'i Sphere,
pub point: Tuple, pub point: Tuple,
pub over_point: Tuple, pub over_point: Tuple,

View File

@ -11,7 +11,29 @@ pub mod tuples;
pub mod world; pub mod world;
/// Value considered close enough for PartialEq implementations. /// Value considered close enough for PartialEq implementations.
pub const EPSILON: f32 = 0.00001; pub const EPSILON: Float = 0.00001;
pub const BLACK: tuples::Color = tuples::Color::new(0., 0., 0.); pub const BLACK: tuples::Color = tuples::Color::new(0., 0., 0.);
pub const WHITE: tuples::Color = tuples::Color::new(1., 1., 1.); pub const WHITE: tuples::Color = tuples::Color::new(1., 1., 1.);
#[cfg(feature = "float-as-double")]
/// submodule to defined types, constants and methods when `Float` is defined as a `f64` using the
/// "float-as-double" cargo feature.
pub mod float {
pub use std::f64::*;
/// Alias of the `f64` type, to be used through out the codebase anywhere a default sized
/// `Float` is necessary.
pub type Float = f64;
}
#[cfg(not(feature = "float-as-double"))]
/// submodule to defined types, constants and methods when `Float` is defined as a `f32` when not using the
/// "float-as-double" cargo feature.
pub mod float {
pub use std::f32::*;
/// Alias of the `f32` type, to be used through out the codebase anywhere a default sized
/// `Float` is necessary.
pub type Float = f32;
}
pub use float::Float;

View File

@ -2,15 +2,15 @@ use crate::{
lights::PointLight, lights::PointLight,
tuples::Color, tuples::Color,
tuples::{dot, reflect, Tuple}, tuples::{dot, reflect, Tuple},
BLACK, WHITE, Float, BLACK, WHITE,
}; };
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub struct Material { pub struct Material {
pub color: Color, pub color: Color,
pub ambient: f32, pub ambient: Float,
pub diffuse: f32, pub diffuse: Float,
pub specular: f32, pub specular: Float,
pub shininess: f32, pub shininess: Float,
} }
impl Default for Material { impl Default for Material {
@ -51,7 +51,7 @@ impl Default for Material {
/// lights::PointLight, /// lights::PointLight,
/// materials::{lighting, Material}, /// materials::{lighting, Material},
/// tuples::{Color, Tuple}, /// tuples::{Color, Tuple},
/// WHITE, /// Float, WHITE,
/// }; /// };
/// ///
/// let in_shadow = false; /// let in_shadow = false;
@ -66,7 +66,7 @@ impl Default for Material {
/// assert_eq!(result, Color::new(1.9, 1.9, 1.9)); /// assert_eq!(result, Color::new(1.9, 1.9, 1.9));
/// ///
/// // Lighting with the eye between the light and the surface, eye offset 45°. /// // Lighting with the eye between the light and the surface, eye offset 45°.
/// let eyev = Tuple::vector(0., 2_f32.sqrt() / 2., -2_f32.sqrt() / 2.); /// let eyev = Tuple::vector(0., (2. as Float).sqrt() / 2., -(2. as Float).sqrt() / 2.);
/// let normalv = Tuple::vector(0., 0., -1.); /// let normalv = Tuple::vector(0., 0., -1.);
/// let light = PointLight::new(Tuple::point(0., 0., -10.), WHITE); /// let light = PointLight::new(Tuple::point(0., 0., -10.), WHITE);
/// let result = lighting(&m, &light, position, eyev, normalv, in_shadow); /// let result = lighting(&m, &light, position, eyev, normalv, in_shadow);
@ -80,7 +80,7 @@ impl Default for Material {
/// assert_eq!(result, Color::new(0.7364, 0.7364, 0.7364)); /// assert_eq!(result, Color::new(0.7364, 0.7364, 0.7364));
/// ///
/// // Lighting with the eye in the path of the reflection vector. /// // Lighting with the eye in the path of the reflection vector.
/// let eyev = Tuple::vector(0., -2_f32.sqrt() / 2., -2_f32.sqrt() / 2.); /// let eyev = Tuple::vector(0., -(2.0 as Float).sqrt() / 2., -(2.0 as Float).sqrt() / 2.);
/// let normalv = Tuple::vector(0., 0., -1.); /// let normalv = Tuple::vector(0., 0., -1.);
/// let light = PointLight::new(Tuple::point(0., 10., -10.), WHITE); /// let light = PointLight::new(Tuple::point(0., 10., -10.), WHITE);
/// let result = lighting(&m, &light, position, eyev, normalv, in_shadow); /// let result = lighting(&m, &light, position, eyev, normalv, in_shadow);

View File

@ -1,15 +1,15 @@
use std::fmt; use std::fmt;
use std::ops::{Index, IndexMut, Mul, Sub}; use std::ops::{Index, IndexMut, Mul, Sub};
use crate::{tuples::Tuple, EPSILON}; use crate::{tuples::Tuple, Float, EPSILON};
#[derive(Debug)] #[derive(Debug)]
pub struct Matrix2x2 { pub struct Matrix2x2 {
m: [[f32; 2]; 2], m: [[Float; 2]; 2],
} }
impl Matrix2x2 { impl Matrix2x2 {
/// Create a `Matrix2x2` with each of the given rows. /// Create a `Matrix2x2` with each of the given rows.
pub fn new(r0: [f32; 2], r1: [f32; 2]) -> Matrix2x2 { pub fn new(r0: [Float; 2], r1: [Float; 2]) -> Matrix2x2 {
Matrix2x2 { m: [r0, r1] } Matrix2x2 { m: [r0, r1] }
} }
@ -24,13 +24,13 @@ impl Matrix2x2 {
/// ///
/// assert_eq!(a.determinant(), 17.); /// assert_eq!(a.determinant(), 17.);
/// ``` /// ```
pub fn determinant(&self) -> f32 { pub fn determinant(&self) -> Float {
let m = self; let m = self;
m[(0, 0)] * m[(1, 1)] - m[(0, 1)] * m[(1, 0)] m[(0, 0)] * m[(1, 1)] - m[(0, 1)] * m[(1, 0)]
} }
} }
impl Index<(usize, usize)> for Matrix2x2 { impl Index<(usize, usize)> for Matrix2x2 {
type Output = f32; type Output = Float;
fn index(&self, (row, col): (usize, usize)) -> &Self::Output { fn index(&self, (row, col): (usize, usize)) -> &Self::Output {
&self.m[row][col] &self.m[row][col]
} }
@ -53,11 +53,11 @@ impl PartialEq for Matrix2x2 {
#[derive(Debug)] #[derive(Debug)]
pub struct Matrix3x3 { pub struct Matrix3x3 {
m: [[f32; 3]; 3], m: [[Float; 3]; 3],
} }
impl Matrix3x3 { impl Matrix3x3 {
/// Create a `Matrix3x2` with each of the given rows. /// Create a `Matrix3x2` with each of the given rows.
pub fn new(r0: [f32; 3], r1: [f32; 3], r2: [f32; 3]) -> Matrix3x3 { pub fn new(r0: [Float; 3], r1: [Float; 3], r2: [Float; 3]) -> Matrix3x3 {
Matrix3x3 { m: [r0, r1, r2] } Matrix3x3 { m: [r0, r1, r2] }
} }
/// submatrix extracts a 2x2 matrix ignoring the 0-based `row` and `col` given. /// submatrix extracts a 2x2 matrix ignoring the 0-based `row` and `col` given.
@ -101,7 +101,7 @@ impl Matrix3x3 {
/// assert_eq!(b.determinant(), 25.0); /// assert_eq!(b.determinant(), 25.0);
/// assert_eq!(b.determinant(), a.minor(1, 0)); /// assert_eq!(b.determinant(), a.minor(1, 0));
/// ``` /// ```
pub fn minor(&self, row: usize, col: usize) -> f32 { pub fn minor(&self, row: usize, col: usize) -> Float {
self.submatrix(row, col).determinant() self.submatrix(row, col).determinant()
} }
@ -117,7 +117,7 @@ impl Matrix3x3 {
/// assert_eq!(a.minor(1, 0), 25.); /// assert_eq!(a.minor(1, 0), 25.);
/// assert_eq!(a.cofactor(1, 0), -25.); /// assert_eq!(a.cofactor(1, 0), -25.);
/// ``` /// ```
pub fn cofactor(&self, row: usize, col: usize) -> f32 { pub fn cofactor(&self, row: usize, col: usize) -> Float {
let negate = if (row + col) % 2 == 0 { 1. } else { -1. }; let negate = if (row + col) % 2 == 0 { 1. } else { -1. };
self.submatrix(row, col).determinant() * negate self.submatrix(row, col).determinant() * negate
} }
@ -134,12 +134,12 @@ impl Matrix3x3 {
/// assert_eq!(a.cofactor(0, 2), -46.); /// assert_eq!(a.cofactor(0, 2), -46.);
/// assert_eq!(a.determinant(), -196.); /// assert_eq!(a.determinant(), -196.);
/// ``` /// ```
pub fn determinant(&self) -> f32 { pub fn determinant(&self) -> Float {
(0..3).map(|i| self.cofactor(0, i) * self[(0, i)]).sum() (0..3).map(|i| self.cofactor(0, i) * self[(0, i)]).sum()
} }
} }
impl Index<(usize, usize)> for Matrix3x3 { impl Index<(usize, usize)> for Matrix3x3 {
type Output = f32; type Output = Float;
fn index(&self, (row, col): (usize, usize)) -> &Self::Output { fn index(&self, (row, col): (usize, usize)) -> &Self::Output {
&self.m[row][col] &self.m[row][col]
} }
@ -166,9 +166,7 @@ impl PartialEq for Matrix3x3 {
/// ///
/// # Examples /// # Examples
/// ``` /// ```
/// use std::f32::consts::PI; /// use rtchallenge::{float::consts::PI, matrices::Matrix4x4, tuples::Tuple};
///
/// use rtchallenge::{matrices::Matrix4x4, tuples::Tuple};
/// ///
/// // Individual transformations are applied in sequence. /// // Individual transformations are applied in sequence.
/// let p = Tuple::point(1., 0., 1.); /// let p = Tuple::point(1., 0., 1.);
@ -195,11 +193,11 @@ impl PartialEq for Matrix3x3 {
/// ``` /// ```
#[derive(Copy, Clone, Default)] #[derive(Copy, Clone, Default)]
pub struct Matrix4x4 { pub struct Matrix4x4 {
m: [[f32; 4]; 4], m: [[Float; 4]; 4],
} }
impl From<[f32; 16]> for Matrix4x4 { impl From<[Float; 16]> for Matrix4x4 {
fn from(t: [f32; 16]) -> Self { fn from(t: [Float; 16]) -> Self {
Matrix4x4 { Matrix4x4 {
m: [ m: [
[t[0], t[1], t[2], t[3]], [t[0], t[1], t[2], t[3]],
@ -238,7 +236,7 @@ impl Matrix4x4 {
} }
/// Create a `Matrix4x4` with each of the given rows. /// Create a `Matrix4x4` with each of the given rows.
pub fn new(r0: [f32; 4], r1: [f32; 4], r2: [f32; 4], r3: [f32; 4]) -> Matrix4x4 { pub fn new(r0: [Float; 4], r1: [Float; 4], r2: [Float; 4], r3: [Float; 4]) -> Matrix4x4 {
Matrix4x4 { Matrix4x4 {
m: [r0, r1, r2, r3], m: [r0, r1, r2, r3],
} }
@ -261,7 +259,7 @@ impl Matrix4x4 {
/// let v = Tuple::vector(-3., 4., 5.); /// let v = Tuple::vector(-3., 4., 5.);
/// assert_eq!(transform * v, v); /// assert_eq!(transform * v, v);
/// ``` /// ```
pub fn translation(x: f32, y: f32, z: f32) -> Matrix4x4 { pub fn translation(x: Float, y: Float, z: Float) -> Matrix4x4 {
Matrix4x4::new( Matrix4x4::new(
[1., 0., 0., x], [1., 0., 0., x],
[0., 1., 0., y], [0., 1., 0., y],
@ -295,7 +293,7 @@ impl Matrix4x4 {
/// let p = Tuple::point(2., 3., 4.); /// let p = Tuple::point(2., 3., 4.);
/// assert_eq!(transform * p, Tuple::point(-2., 3., 4.)); /// assert_eq!(transform * p, Tuple::point(-2., 3., 4.));
/// ``` /// ```
pub fn scaling(x: f32, y: f32, z: f32) -> Matrix4x4 { pub fn scaling(x: Float, y: Float, z: Float) -> Matrix4x4 {
Matrix4x4::new( Matrix4x4::new(
[x, 0., 0., 0.], [x, 0., 0., 0.],
[0., y, 0., 0.], [0., y, 0., 0.],
@ -309,9 +307,7 @@ impl Matrix4x4 {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use std::f32::consts::PI; /// use rtchallenge::{float::consts::PI, matrices::Matrix4x4, tuples::Tuple, Float};
///
/// use rtchallenge::{matrices::Matrix4x4, tuples::Tuple};
/// ///
/// // A scaling matrix applied to a point. /// // A scaling matrix applied to a point.
/// let p = Tuple::point(0., 1., 0.); /// let p = Tuple::point(0., 1., 0.);
@ -320,11 +316,11 @@ impl Matrix4x4 {
/// ///
/// assert_eq!( /// assert_eq!(
/// half_quarter * p, /// half_quarter * p,
/// Tuple::point(0., 2_f32.sqrt() / 2., 2_f32.sqrt() / 2.) /// Tuple::point(0., (2.0 as Float).sqrt() / 2., (2.0 as Float).sqrt() / 2.)
/// ); /// );
/// assert_eq!(full_quarter * p, Tuple::point(0., 0., 1.),); /// assert_eq!(full_quarter * p, Tuple::point(0., 0., 1.),);
/// ``` /// ```
pub fn rotation_x(radians: f32) -> Matrix4x4 { pub fn rotation_x(radians: Float) -> Matrix4x4 {
let r = radians; let r = radians;
Matrix4x4::new( Matrix4x4::new(
[1., 0., 0., 0.], [1., 0., 0., 0.],
@ -339,9 +335,7 @@ impl Matrix4x4 {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use std::f32::consts::PI; /// use rtchallenge::{float::consts::PI, matrices::Matrix4x4, tuples::Tuple, Float};
///
/// use rtchallenge::{matrices::Matrix4x4, tuples::Tuple};
/// ///
/// // A scaling matrix applied to a point. /// // A scaling matrix applied to a point.
/// let p = Tuple::point(0., 0., 1.); /// let p = Tuple::point(0., 0., 1.);
@ -350,11 +344,11 @@ impl Matrix4x4 {
/// ///
/// assert_eq!( /// assert_eq!(
/// half_quarter * p, /// half_quarter * p,
/// Tuple::point(2_f32.sqrt() / 2., 0., 2_f32.sqrt() / 2.) /// Tuple::point((2.0 as Float).sqrt() / 2., 0., (2.0 as Float).sqrt() / 2.)
/// ); /// );
/// assert_eq!(full_quarter * p, Tuple::point(1., 0., 0.,),); /// assert_eq!(full_quarter * p, Tuple::point(1., 0., 0.,),);
/// ``` /// ```
pub fn rotation_y(radians: f32) -> Matrix4x4 { pub fn rotation_y(radians: Float) -> Matrix4x4 {
let r = radians; let r = radians;
Matrix4x4::new( Matrix4x4::new(
[r.cos(), 0., r.sin(), 0.], [r.cos(), 0., r.sin(), 0.],
@ -369,9 +363,7 @@ impl Matrix4x4 {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use std::f32::consts::PI; /// use rtchallenge::{float::consts::PI, matrices::Matrix4x4, tuples::Tuple, Float};
///
/// use rtchallenge::{matrices::Matrix4x4, tuples::Tuple};
/// ///
/// // A scaling matrix applied to a point. /// // A scaling matrix applied to a point.
/// let p = Tuple::point(0., 1., 0.); /// let p = Tuple::point(0., 1., 0.);
@ -380,11 +372,11 @@ impl Matrix4x4 {
/// ///
/// assert_eq!( /// assert_eq!(
/// half_quarter * p, /// half_quarter * p,
/// Tuple::point(-2_f32.sqrt() / 2., 2_f32.sqrt() / 2., 0.) /// Tuple::point(-(2.0 as Float).sqrt() / 2., (2.0 as Float).sqrt() / 2., 0.)
/// ); /// );
/// assert_eq!(full_quarter * p, Tuple::point(-1., 0., 0.,),); /// assert_eq!(full_quarter * p, Tuple::point(-1., 0., 0.,),);
/// ``` /// ```
pub fn rotation_z(radians: f32) -> Matrix4x4 { pub fn rotation_z(radians: Float) -> Matrix4x4 {
let r = radians; let r = radians;
Matrix4x4::new( Matrix4x4::new(
[r.cos(), -r.sin(), 0., 0.], [r.cos(), -r.sin(), 0., 0.],
@ -462,7 +454,7 @@ impl Matrix4x4 {
/// let p = Tuple::point(2.,3.,4.); /// let p = Tuple::point(2.,3.,4.);
/// assert_eq!(transform * p, Tuple::point(2.,3.,7.)); /// assert_eq!(transform * p, Tuple::point(2.,3.,7.));
pub fn shearing(xy: f32, xz: f32, yx: f32, yz: f32, zx: f32, zy: f32) -> Matrix4x4 { pub fn shearing(xy: Float, xz: Float, yx: Float, yz: Float, zx: Float, zy: Float) -> Matrix4x4 {
Matrix4x4::new( Matrix4x4::new(
[1., xy, xz, 0.], [1., xy, xz, 0.],
[yx, 1., yz, 0.], [yx, 1., yz, 0.],
@ -503,7 +495,7 @@ impl Matrix4x4 {
for i in 0..4 { for i in 0..4 {
let mut irow: usize = 0; let mut irow: usize = 0;
let mut icol: usize = 0; let mut icol: usize = 0;
let mut big: f32 = 0.; let mut big: Float = 0.;
// Choose pivot // Choose pivot
for j in 0..4 { for j in 0..4 {
if ipiv[j] != 1 { if ipiv[j] != 1 {
@ -538,7 +530,7 @@ impl Matrix4x4 {
} }
// Set $m[icol][icol]$ to one by scaling row _icol_ appropriately // Set $m[icol][icol]$ to one by scaling row _icol_ appropriately
let pivinv: f32 = minv[icol][icol].recip(); let pivinv: Float = minv[icol][icol].recip();
minv[icol][icol] = 1.; minv[icol][icol] = 1.;
for j in 0..4 { for j in 0..4 {
minv[icol][j] *= pivinv; minv[icol][j] *= pivinv;
@ -606,11 +598,11 @@ impl Matrix4x4 {
} }
/// Compute minor of a 4x4 matrix. /// Compute minor of a 4x4 matrix.
pub fn minor(&self, row: usize, col: usize) -> f32 { pub fn minor(&self, row: usize, col: usize) -> Float {
self.submatrix(row, col).determinant() self.submatrix(row, col).determinant()
} }
/// Compute cofactor of a 4x4 matrix. /// Compute cofactor of a 4x4 matrix.
pub fn cofactor(&self, row: usize, col: usize) -> f32 { pub fn cofactor(&self, row: usize, col: usize) -> Float {
let negate = if (row + col) % 2 == 0 { 1. } else { -1. }; let negate = if (row + col) % 2 == 0 { 1. } else { -1. };
self.submatrix(row, col).determinant() * negate self.submatrix(row, col).determinant() * negate
} }
@ -632,7 +624,7 @@ impl Matrix4x4 {
/// assert_eq!(a.cofactor(0, 3), 51.); /// assert_eq!(a.cofactor(0, 3), 51.);
/// assert_eq!(a.determinant(), -4071.); /// assert_eq!(a.determinant(), -4071.);
/// ``` /// ```
pub fn determinant(&self) -> f32 { pub fn determinant(&self) -> Float {
(0..4).map(|i| self.cofactor(0, i) * self[(0, i)]).sum() (0..4).map(|i| self.cofactor(0, i) * self[(0, i)]).sum()
} }
@ -873,7 +865,7 @@ impl PartialEq for Matrix4x4 {
} }
impl Index<(usize, usize)> for Matrix4x4 { impl Index<(usize, usize)> for Matrix4x4 {
type Output = f32; type Output = Float;
fn index(&self, (row, col): (usize, usize)) -> &Self::Output { fn index(&self, (row, col): (usize, usize)) -> &Self::Output {
&self.m[row][col] &self.m[row][col]
} }

View File

@ -1,4 +1,4 @@
use crate::{matrices::Matrix4x4, tuples::Tuple}; use crate::{matrices::Matrix4x4, tuples::Tuple, Float};
/// Rays have an origin and a direction. This datatype is the 'ray' in 'raytracer'. /// Rays have an origin and a direction. This datatype is the 'ray' in 'raytracer'.
pub struct Ray { pub struct Ray {
@ -38,7 +38,7 @@ impl Ray {
/// assert_eq!(r.position(-1.), Tuple::point(1., 3., 4.)); /// assert_eq!(r.position(-1.), Tuple::point(1., 3., 4.));
/// assert_eq!(r.position(2.5), Tuple::point(4.5, 3., 4.)); /// assert_eq!(r.position(2.5), Tuple::point(4.5, 3., 4.));
/// ``` /// ```
pub fn position(&self, t: f32) -> Tuple { pub fn position(&self, t: Float) -> Tuple {
self.origin + self.direction * t self.origin + self.direction * t
} }

View File

@ -54,7 +54,7 @@ impl Sphere {
/// ///
/// # Examples /// # Examples
/// ``` /// ```
/// use rtchallenge::{matrices::Matrix4x4, spheres::Sphere, tuples::Tuple}; /// use rtchallenge::{matrices::Matrix4x4, spheres::Sphere, tuples::Tuple,Float};
/// ///
/// // Normal on X-axis /// // Normal on X-axis
/// let s = Sphere::default(); /// let s = Sphere::default();
@ -74,20 +74,20 @@ impl Sphere {
/// // Normal on a sphere at a nonaxial point. /// // Normal on a sphere at a nonaxial point.
/// let s = Sphere::default(); /// let s = Sphere::default();
/// let n = s.normal_at(Tuple::point( /// let n = s.normal_at(Tuple::point(
/// 3_f32.sqrt() / 3., /// (3. as Float).sqrt() / 3.,
/// 3_f32.sqrt() / 3., /// (3. as Float).sqrt() / 3.,
/// 3_f32.sqrt() / 3., /// (3. as Float).sqrt() / 3.,
/// )); /// ));
/// assert_eq!( /// assert_eq!(
/// n, /// n,
/// Tuple::vector(3_f32.sqrt() / 3., 3_f32.sqrt() / 3., 3_f32.sqrt() / 3.,) /// Tuple::vector((3. as Float).sqrt() / 3., (3. as Float).sqrt() / 3., (3. as Float).sqrt() / 3.,)
/// ); /// );
/// // Normals returned are normalized. /// // Normals returned are normalized.
/// let s = Sphere::default(); /// let s = Sphere::default();
/// let n = s.normal_at(Tuple::point( /// let n = s.normal_at(Tuple::point(
/// 3_f32.sqrt() / 3., /// (3. as Float).sqrt() / 3.,
/// 3_f32.sqrt() / 3., /// (3. as Float).sqrt() / 3.,
/// 3_f32.sqrt() / 3., /// (3. as Float).sqrt() / 3.,
/// )); /// ));
/// assert_eq!(n, n.normalize()); /// assert_eq!(n, n.normalize());
/// ///
@ -98,11 +98,11 @@ impl Sphere {
/// assert_eq!(n, Tuple::vector(0., 0.70711, -0.70711)); /// assert_eq!(n, Tuple::vector(0., 0.70711, -0.70711));
/// // Compute the normal on a transformed sphere. /// // Compute the normal on a transformed sphere.
/// use std::f32::consts::PI; /// use rtchallenge::float::consts::PI;
/// ///
/// let mut s = Sphere::default(); /// let mut s = Sphere::default();
/// s.set_transform ( Matrix4x4::scaling(1.,0.5,1.) * Matrix4x4::rotation_z(PI/5.)); /// s.set_transform ( Matrix4x4::scaling(1.,0.5,1.) * Matrix4x4::rotation_z(PI/5.));
/// let n = s.normal_at(Tuple::point(0., 2_f32.sqrt()/2., -2_f32.sqrt()/2.)); /// let n = s.normal_at(Tuple::point(0., (2. as Float).sqrt()/2., -(2. as Float).sqrt()/2.));
/// assert_eq!(n, Tuple::vector(0., 0.97014, -0.24254)); /// assert_eq!(n, Tuple::vector(0., 0.97014, -0.24254));
/// ``` /// ```
#[cfg(not(feature = "disable_inverse_cache"))] #[cfg(not(feature = "disable_inverse_cache"))]

View File

@ -1,25 +1,25 @@
use std::ops::{Add, Div, Mul, Neg, Sub}; use std::ops::{Add, Div, Mul, Neg, Sub};
use crate::EPSILON; use crate::{Float, EPSILON};
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct Tuple { pub struct Tuple {
pub x: f32, pub x: Float,
pub y: f32, pub y: Float,
pub z: f32, pub z: Float,
pub w: f32, pub w: Float,
} }
impl Tuple { impl Tuple {
pub fn point(x: f32, y: f32, z: f32) -> Tuple { pub fn point(x: Float, y: Float, z: Float) -> Tuple {
Tuple::new(x, y, z, 1.0) Tuple::new(x, y, z, 1.0)
} }
pub fn vector(x: f32, y: f32, z: f32) -> Tuple { pub fn vector(x: Float, y: Float, z: Float) -> Tuple {
Tuple::new(x, y, z, 0.0) Tuple::new(x, y, z, 0.0)
} }
pub fn new(x: f32, y: f32, z: f32, w: f32) -> Tuple { pub fn new(x: Float, y: Float, z: Float, w: Float) -> Tuple {
Tuple { x, y, z, w } Tuple { x, y, z, w }
} }
@ -31,7 +31,7 @@ impl Tuple {
self.w == 0.0 self.w == 0.0
} }
pub fn magnitude(&self) -> f32 { pub fn magnitude(&self) -> Float {
(self.x * self.x + self.y * self.y + self.z * self.z + self.w * self.w).sqrt() (self.x * self.x + self.y * self.y + self.z * self.z + self.w * self.w).sqrt()
} }
@ -50,7 +50,10 @@ impl Tuple {
/// ///
/// # Examples /// # Examples
/// ``` /// ```
/// use rtchallenge::tuples::{reflect, Tuple}; /// use rtchallenge::{
/// tuples::{reflect, Tuple},
/// Float,
/// };
/// ///
/// // Reflecting a vector approaching at 45° /// // Reflecting a vector approaching at 45°
/// let v = Tuple::vector(1., -1., 0.); /// let v = Tuple::vector(1., -1., 0.);
@ -60,7 +63,7 @@ impl Tuple {
/// ///
/// // Reflecting off a slanted surface. /// // Reflecting off a slanted surface.
/// let v = Tuple::vector(0., -1., 0.); /// let v = Tuple::vector(0., -1., 0.);
/// let n = Tuple::vector(2_f32.sqrt() / 2., 2_f32.sqrt() / 2., 0.); /// let n = Tuple::vector((2. as Float).sqrt() / 2., (2. as Float).sqrt() / 2., 0.);
/// let r = reflect(v, n); /// let r = reflect(v, n);
/// assert_eq!(r, Tuple::vector(1., 0., 0.)); /// assert_eq!(r, Tuple::vector(1., 0., 0.));
/// ``` /// ```
@ -80,9 +83,9 @@ impl Add for Tuple {
} }
} }
impl Div<f32> for Tuple { impl Div<Float> for Tuple {
type Output = Self; type Output = Self;
fn div(self, rhs: f32) -> Self::Output { fn div(self, rhs: Float) -> Self::Output {
Self::Output { Self::Output {
x: self.x / rhs, x: self.x / rhs,
y: self.y / rhs, y: self.y / rhs,
@ -92,9 +95,9 @@ impl Div<f32> for Tuple {
} }
} }
impl Mul<f32> for Tuple { impl Mul<Float> for Tuple {
type Output = Self; type Output = Self;
fn mul(self, rhs: f32) -> Self::Output { fn mul(self, rhs: Float) -> Self::Output {
Self::Output { Self::Output {
x: self.x * rhs, x: self.x * rhs,
y: self.y * rhs, y: self.y * rhs,
@ -104,7 +107,7 @@ impl Mul<f32> for Tuple {
} }
} }
impl Mul<Tuple> for f32 { impl Mul<Tuple> for Float {
type Output = Tuple; type Output = Tuple;
fn mul(self, rhs: Tuple) -> Self::Output { fn mul(self, rhs: Tuple) -> Self::Output {
Self::Output { Self::Output {
@ -147,7 +150,7 @@ impl PartialEq for Tuple {
&& ((self.w - rhs.w).abs() < EPSILON) && ((self.w - rhs.w).abs() < EPSILON)
} }
} }
pub fn dot(a: Tuple, b: Tuple) -> f32 { pub fn dot(a: Tuple, b: Tuple) -> Float {
a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w
} }
pub fn cross(a: Tuple, b: Tuple) -> Tuple { pub fn cross(a: Tuple, b: Tuple) -> Tuple {
@ -160,12 +163,12 @@ pub fn cross(a: Tuple, b: Tuple) -> Tuple {
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub struct Color { pub struct Color {
pub red: f32, pub red: Float,
pub green: f32, pub green: Float,
pub blue: f32, pub blue: Float,
} }
impl Color { impl Color {
pub const fn new(red: f32, green: f32, blue: f32) -> Color { pub const fn new(red: Float, green: Float, blue: Float) -> Color {
Color { red, green, blue } Color { red, green, blue }
} }
} }
@ -187,9 +190,9 @@ impl Add for Color {
} }
} }
impl Div<f32> for Color { impl Div<Float> for Color {
type Output = Self; type Output = Self;
fn div(self, rhs: f32) -> Self::Output { fn div(self, rhs: Float) -> Self::Output {
Self::Output { Self::Output {
red: self.red / rhs, red: self.red / rhs,
green: self.green / rhs, green: self.green / rhs,
@ -198,9 +201,9 @@ impl Div<f32> for Color {
} }
} }
impl Mul<f32> for Color { impl Mul<Float> for Color {
type Output = Self; type Output = Self;
fn mul(self, rhs: f32) -> Self::Output { fn mul(self, rhs: Float) -> Self::Output {
Self::Output { Self::Output {
red: self.red * rhs, red: self.red * rhs,
green: self.green * rhs, green: self.green * rhs,
@ -209,7 +212,7 @@ impl Mul<f32> for Color {
} }
} }
impl Mul<Color> for f32 { impl Mul<Color> for Float {
type Output = Color; type Output = Color;
fn mul(self, rhs: Color) -> Self::Output { fn mul(self, rhs: Color) -> Self::Output {
Self::Output { Self::Output {
@ -253,7 +256,7 @@ impl Sub for Color {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::{cross, dot, Color, Tuple, EPSILON}; use super::{cross, dot, Color, Float, Tuple, EPSILON};
#[test] #[test]
fn is_point() { fn is_point() {
// A tuple with w = 1 is a point // A tuple with w = 1 is a point
@ -341,8 +344,11 @@ mod tests {
assert_eq!(1., Tuple::vector(1., 0., 0.).magnitude()); assert_eq!(1., Tuple::vector(1., 0., 0.).magnitude());
assert_eq!(1., Tuple::vector(0., 1., 0.).magnitude()); assert_eq!(1., Tuple::vector(0., 1., 0.).magnitude());
assert_eq!(1., Tuple::vector(0., 0., 1.).magnitude()); assert_eq!(1., Tuple::vector(0., 0., 1.).magnitude());
assert_eq!(14_f32.sqrt(), Tuple::vector(1., 2., 3.).magnitude()); assert_eq!((14. as Float).sqrt(), Tuple::vector(1., 2., 3.).magnitude());
assert_eq!(14_f32.sqrt(), Tuple::vector(-1., -2., -3.).magnitude()); assert_eq!(
(14. as Float).sqrt(),
Tuple::vector(-1., -2., -3.).magnitude()
);
} }
#[test] #[test]
fn vector_normalize() { fn vector_normalize() {
@ -351,7 +357,11 @@ mod tests {
Tuple::vector(4., 0., 0.).normalize() Tuple::vector(4., 0., 0.).normalize()
); );
assert_eq!( assert_eq!(
Tuple::vector(1. / 14_f32.sqrt(), 2. / 14_f32.sqrt(), 3. / 14_f32.sqrt()), Tuple::vector(
1. / (14. as Float).sqrt(),
2. / (14. as Float).sqrt(),
3. / (14. as Float).sqrt()
),
Tuple::vector(1., 2., 3.).normalize() Tuple::vector(1., 2., 3.).normalize()
); );
} }