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]
disable_inverse_cache = []
float-as-double = []
[dependencies]
anyhow = "1.0.41"

View File

@ -12,7 +12,9 @@ use rayon::iter::{IntoParallelIterator, ParallelIterator};
use serde::Deserialize;
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)]
#[serde(rename_all = "kebab-case")]
@ -32,12 +34,12 @@ impl FromStr for RenderStrategy {
pub struct Camera {
hsize: usize,
vsize: usize,
field_of_view: f32,
field_of_view: Float,
transform: Matrix4x4,
inverse_transform: Matrix4x4,
pixel_size: f32,
half_width: f32,
half_height: f32,
pixel_size: Float,
half_width: Float,
half_height: Float,
pub render_strategy: RenderStrategy,
}
@ -55,9 +57,7 @@ impl Camera {
///
/// # Examples
/// ```
/// use std::f32::consts::PI;
///
/// use rtchallenge::{camera::Camera, matrices::Matrix4x4};
/// use rtchallenge::{camera::Camera, float::consts::PI, matrices::Matrix4x4};
///
/// let hsize = 160;
/// let vsize = 120;
@ -75,15 +75,15 @@ impl Camera {
/// let c = Camera::new(150, 200, PI / 2.);
/// 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 aspect = hsize as f32 / vsize as f32;
let aspect = hsize as Float / vsize as Float;
let (half_width, half_height) = if aspect >= 1. {
(half_view, half_view / aspect)
} else {
(half_view * aspect, half_view)
};
let pixel_size = 2. * half_width / hsize as f32;
let pixel_size = 2. * half_width / hsize as Float;
Camera {
hsize,
vsize,
@ -102,7 +102,7 @@ impl Camera {
pub fn vsize(&self) -> usize {
self.vsize
}
pub fn field_of_view(&self) -> f32 {
pub fn field_of_view(&self) -> Float {
self.field_of_view
}
pub fn transform(&self) -> Matrix4x4 {
@ -112,7 +112,7 @@ impl Camera {
self.transform = t;
self.inverse_transform = t.inverse();
}
pub fn pixel_size(&self) -> f32 {
pub fn pixel_size(&self) -> Float {
self.pixel_size
}
pub fn supersample_rays_for_pixel(&self, px: usize, py: usize, samples: usize) -> Vec<Ray> {
@ -121,8 +121,8 @@ impl Camera {
(0..samples)
.map(|_| {
// 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 yoffset = (py as f32 + rng.gen::<f32>()) * self.pixel_size;
let xoffset = (px as Float + rng.gen::<Float>()) * self.pixel_size;
let yoffset = (py as Float + rng.gen::<Float>()) * self.pixel_size;
// The untransformed coordinates of the pixle in world space.
// (Remember that the camera looks toward -z, so +x is to the left.)
@ -146,9 +146,9 @@ impl Camera {
///
/// # Examples
/// ```
/// use std::f32::consts::PI;
///
/// use rtchallenge::{camera::Camera, matrices::Matrix4x4, tuples::Tuple};
/// 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.);
@ -169,14 +169,14 @@ impl Camera {
/// assert_eq!(r.origin, Tuple::point(0., 2., -5.));
/// assert_eq!(
/// 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"))]
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 f32 + 0.5) * self.pixel_size;
let yoffset = (py as f32 + 0.5) * self.pixel_size;
let xoffset = (px as Float + 0.5) * self.pixel_size;
let yoffset = (py as Float + 0.5) * self.pixel_size;
// The untransformed coordinates of the pixle in world space.
// (Remember that the camera looks toward -z, so +x is to the left.)
@ -195,8 +195,8 @@ impl Camera {
#[cfg(feature = "disable_inverse_cache")]
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 f32 + 0.5) * self.pixel_size;
let yoffset = (py as f32 + 0.5) * self.pixel_size;
let xoffset = (px as Float + 0.5) * self.pixel_size;
let yoffset = (py as Float + 0.5) * self.pixel_size;
// The untransformed coordinates of the pixle in world space.
// (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.
/// # Examples
/// ```
/// use std::f32::consts::PI;
///
/// use rtchallenge::{
/// camera::Camera,
/// float::consts::PI,
/// transformations::view_transform,
/// tuples::{Color, Tuple},
/// world::World,
@ -330,7 +329,7 @@ impl Camera {
.iter()
.map(|ray| w.color_at(&ray))
.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 {
let ray = self.ray_for_pixel(x, y);
let color = w.color_at(&ray);

View File

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

View File

@ -11,7 +11,29 @@ pub mod tuples;
pub mod world;
/// 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 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,
tuples::Color,
tuples::{dot, reflect, Tuple},
BLACK, WHITE,
Float, BLACK, WHITE,
};
#[derive(Debug, PartialEq, Clone)]
pub struct Material {
pub color: Color,
pub ambient: f32,
pub diffuse: f32,
pub specular: f32,
pub shininess: f32,
pub ambient: Float,
pub diffuse: Float,
pub specular: Float,
pub shininess: Float,
}
impl Default for Material {
@ -51,7 +51,7 @@ impl Default for Material {
/// lights::PointLight,
/// materials::{lighting, Material},
/// tuples::{Color, Tuple},
/// WHITE,
/// Float, WHITE,
/// };
///
/// let in_shadow = false;
@ -66,7 +66,7 @@ impl Default for Material {
/// assert_eq!(result, Color::new(1.9, 1.9, 1.9));
///
/// // 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 light = PointLight::new(Tuple::point(0., 0., -10.), WHITE);
/// 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));
///
/// // 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 light = PointLight::new(Tuple::point(0., 10., -10.), WHITE);
/// let result = lighting(&m, &light, position, eyev, normalv, in_shadow);

View File

@ -1,15 +1,15 @@
use std::fmt;
use std::ops::{Index, IndexMut, Mul, Sub};
use crate::{tuples::Tuple, EPSILON};
use crate::{tuples::Tuple, Float, EPSILON};
#[derive(Debug)]
pub struct Matrix2x2 {
m: [[f32; 2]; 2],
m: [[Float; 2]; 2],
}
impl Matrix2x2 {
/// 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] }
}
@ -24,13 +24,13 @@ impl Matrix2x2 {
///
/// assert_eq!(a.determinant(), 17.);
/// ```
pub fn determinant(&self) -> f32 {
pub fn determinant(&self) -> Float {
let m = self;
m[(0, 0)] * m[(1, 1)] - m[(0, 1)] * m[(1, 0)]
}
}
impl Index<(usize, usize)> for Matrix2x2 {
type Output = f32;
type Output = Float;
fn index(&self, (row, col): (usize, usize)) -> &Self::Output {
&self.m[row][col]
}
@ -53,11 +53,11 @@ impl PartialEq for Matrix2x2 {
#[derive(Debug)]
pub struct Matrix3x3 {
m: [[f32; 3]; 3],
m: [[Float; 3]; 3],
}
impl Matrix3x3 {
/// 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] }
}
/// 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(), 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()
}
@ -117,7 +117,7 @@ impl Matrix3x3 {
/// assert_eq!(a.minor(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. };
self.submatrix(row, col).determinant() * negate
}
@ -134,12 +134,12 @@ impl Matrix3x3 {
/// assert_eq!(a.cofactor(0, 2), -46.);
/// 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()
}
}
impl Index<(usize, usize)> for Matrix3x3 {
type Output = f32;
type Output = Float;
fn index(&self, (row, col): (usize, usize)) -> &Self::Output {
&self.m[row][col]
}
@ -166,9 +166,7 @@ impl PartialEq for Matrix3x3 {
///
/// # Examples
/// ```
/// use std::f32::consts::PI;
///
/// use rtchallenge::{matrices::Matrix4x4, tuples::Tuple};
/// use rtchallenge::{float::consts::PI, matrices::Matrix4x4, tuples::Tuple};
///
/// // Individual transformations are applied in sequence.
/// let p = Tuple::point(1., 0., 1.);
@ -195,11 +193,11 @@ impl PartialEq for Matrix3x3 {
/// ```
#[derive(Copy, Clone, Default)]
pub struct Matrix4x4 {
m: [[f32; 4]; 4],
m: [[Float; 4]; 4],
}
impl From<[f32; 16]> for Matrix4x4 {
fn from(t: [f32; 16]) -> Self {
impl From<[Float; 16]> for Matrix4x4 {
fn from(t: [Float; 16]) -> Self {
Matrix4x4 {
m: [
[t[0], t[1], t[2], t[3]],
@ -238,7 +236,7 @@ impl Matrix4x4 {
}
/// 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 {
m: [r0, r1, r2, r3],
}
@ -261,7 +259,7 @@ impl Matrix4x4 {
/// let v = Tuple::vector(-3., 4., 5.);
/// 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(
[1., 0., 0., x],
[0., 1., 0., y],
@ -295,7 +293,7 @@ impl Matrix4x4 {
/// let 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(
[x, 0., 0., 0.],
[0., y, 0., 0.],
@ -309,9 +307,7 @@ impl Matrix4x4 {
/// # Examples
///
/// ```
/// use std::f32::consts::PI;
///
/// use rtchallenge::{matrices::Matrix4x4, tuples::Tuple};
/// use rtchallenge::{float::consts::PI, matrices::Matrix4x4, tuples::Tuple, Float};
///
/// // A scaling matrix applied to a point.
/// let p = Tuple::point(0., 1., 0.);
@ -320,11 +316,11 @@ impl Matrix4x4 {
///
/// assert_eq!(
/// 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.),);
/// ```
pub fn rotation_x(radians: f32) -> Matrix4x4 {
pub fn rotation_x(radians: Float) -> Matrix4x4 {
let r = radians;
Matrix4x4::new(
[1., 0., 0., 0.],
@ -339,9 +335,7 @@ impl Matrix4x4 {
/// # Examples
///
/// ```
/// use std::f32::consts::PI;
///
/// use rtchallenge::{matrices::Matrix4x4, tuples::Tuple};
/// use rtchallenge::{float::consts::PI, matrices::Matrix4x4, tuples::Tuple, Float};
///
/// // A scaling matrix applied to a point.
/// let p = Tuple::point(0., 0., 1.);
@ -350,11 +344,11 @@ impl Matrix4x4 {
///
/// assert_eq!(
/// 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.,),);
/// ```
pub fn rotation_y(radians: f32) -> Matrix4x4 {
pub fn rotation_y(radians: Float) -> Matrix4x4 {
let r = radians;
Matrix4x4::new(
[r.cos(), 0., r.sin(), 0.],
@ -369,9 +363,7 @@ impl Matrix4x4 {
/// # Examples
///
/// ```
/// use std::f32::consts::PI;
///
/// use rtchallenge::{matrices::Matrix4x4, tuples::Tuple};
/// use rtchallenge::{float::consts::PI, matrices::Matrix4x4, tuples::Tuple, Float};
///
/// // A scaling matrix applied to a point.
/// let p = Tuple::point(0., 1., 0.);
@ -380,11 +372,11 @@ impl Matrix4x4 {
///
/// assert_eq!(
/// 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.,),);
/// ```
pub fn rotation_z(radians: f32) -> Matrix4x4 {
pub fn rotation_z(radians: Float) -> Matrix4x4 {
let r = radians;
Matrix4x4::new(
[r.cos(), -r.sin(), 0., 0.],
@ -462,7 +454,7 @@ impl Matrix4x4 {
/// let p = Tuple::point(2.,3.,4.);
/// 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(
[1., xy, xz, 0.],
[yx, 1., yz, 0.],
@ -503,7 +495,7 @@ impl Matrix4x4 {
for i in 0..4 {
let mut irow: usize = 0;
let mut icol: usize = 0;
let mut big: f32 = 0.;
let mut big: Float = 0.;
// Choose pivot
for j in 0..4 {
if ipiv[j] != 1 {
@ -538,7 +530,7 @@ impl Matrix4x4 {
}
// 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.;
for j in 0..4 {
minv[icol][j] *= pivinv;
@ -606,11 +598,11 @@ impl Matrix4x4 {
}
/// 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()
}
/// 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. };
self.submatrix(row, col).determinant() * negate
}
@ -632,7 +624,7 @@ impl Matrix4x4 {
/// assert_eq!(a.cofactor(0, 3), 51.);
/// 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()
}
@ -873,7 +865,7 @@ impl PartialEq for Matrix4x4 {
}
impl Index<(usize, usize)> for Matrix4x4 {
type Output = f32;
type Output = Float;
fn index(&self, (row, col): (usize, usize)) -> &Self::Output {
&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'.
pub struct Ray {
@ -38,7 +38,7 @@ impl Ray {
/// assert_eq!(r.position(-1.), Tuple::point(1., 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
}

View File

@ -54,7 +54,7 @@ impl Sphere {
///
/// # Examples
/// ```
/// use rtchallenge::{matrices::Matrix4x4, spheres::Sphere, tuples::Tuple};
/// use rtchallenge::{matrices::Matrix4x4, spheres::Sphere, tuples::Tuple,Float};
///
/// // Normal on X-axis
/// let s = Sphere::default();
@ -74,20 +74,20 @@ impl Sphere {
/// // 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.,
/// (3. as Float).sqrt() / 3.,
/// (3. as Float).sqrt() / 3.,
/// (3. as Float).sqrt() / 3.,
/// ));
/// assert_eq!(
/// 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.
/// let s = Sphere::default();
/// let n = s.normal_at(Tuple::point(
/// 3_f32.sqrt() / 3.,
/// 3_f32.sqrt() / 3.,
/// 3_f32.sqrt() / 3.,
/// (3. as Float).sqrt() / 3.,
/// (3. as Float).sqrt() / 3.,
/// (3. as Float).sqrt() / 3.,
/// ));
/// assert_eq!(n, n.normalize());
///
@ -98,11 +98,11 @@ impl Sphere {
/// assert_eq!(n, Tuple::vector(0., 0.70711, -0.70711));
/// // Compute the normal on a transformed sphere.
/// use std::f32::consts::PI;
/// use rtchallenge::float::consts::PI;
///
/// let mut s = Sphere::default();
/// 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));
/// ```
#[cfg(not(feature = "disable_inverse_cache"))]

View File

@ -1,25 +1,25 @@
use std::ops::{Add, Div, Mul, Neg, Sub};
use crate::EPSILON;
use crate::{Float, EPSILON};
#[derive(Debug, Copy, Clone)]
pub struct Tuple {
pub x: f32,
pub y: f32,
pub z: f32,
pub w: f32,
pub x: Float,
pub y: Float,
pub z: Float,
pub w: Float,
}
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)
}
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)
}
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 }
}
@ -31,7 +31,7 @@ impl Tuple {
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()
}
@ -50,7 +50,10 @@ impl Tuple {
///
/// # Examples
/// ```
/// use rtchallenge::tuples::{reflect, Tuple};
/// use rtchallenge::{
/// tuples::{reflect, Tuple},
/// Float,
/// };
///
/// // Reflecting a vector approaching at 45°
/// let v = Tuple::vector(1., -1., 0.);
@ -60,7 +63,7 @@ impl Tuple {
///
/// // Reflecting off a slanted surface.
/// 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);
/// 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;
fn div(self, rhs: f32) -> Self::Output {
fn div(self, rhs: Float) -> Self::Output {
Self::Output {
x: self.x / 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;
fn mul(self, rhs: f32) -> Self::Output {
fn mul(self, rhs: Float) -> Self::Output {
Self::Output {
x: self.x * 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;
fn mul(self, rhs: Tuple) -> Self::Output {
Self::Output {
@ -147,7 +150,7 @@ impl PartialEq for Tuple {
&& ((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
}
pub fn cross(a: Tuple, b: Tuple) -> Tuple {
@ -160,12 +163,12 @@ pub fn cross(a: Tuple, b: Tuple) -> Tuple {
#[derive(Copy, Clone, Debug)]
pub struct Color {
pub red: f32,
pub green: f32,
pub blue: f32,
pub red: Float,
pub green: Float,
pub blue: Float,
}
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 }
}
}
@ -187,9 +190,9 @@ impl Add for Color {
}
}
impl Div<f32> for Color {
impl Div<Float> for Color {
type Output = Self;
fn div(self, rhs: f32) -> Self::Output {
fn div(self, rhs: Float) -> Self::Output {
Self::Output {
red: self.red / 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;
fn mul(self, rhs: f32) -> Self::Output {
fn mul(self, rhs: Float) -> Self::Output {
Self::Output {
red: self.red * 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;
fn mul(self, rhs: Color) -> Self::Output {
Self::Output {
@ -253,7 +256,7 @@ impl Sub for Color {
#[cfg(test)]
mod tests {
use super::{cross, dot, Color, Tuple, EPSILON};
use super::{cross, dot, Color, Float, Tuple, EPSILON};
#[test]
fn is_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(0., 1., 0.).magnitude());
assert_eq!(1., Tuple::vector(0., 0., 1.).magnitude());
assert_eq!(14_f32.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());
assert_eq!(
(14. as Float).sqrt(),
Tuple::vector(-1., -2., -3.).magnitude()
);
}
#[test]
fn vector_normalize() {
@ -351,7 +357,11 @@ mod tests {
Tuple::vector(4., 0., 0.).normalize()
);
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()
);
}