From d6b5c8775988d5fb1017ab045309155263b0e814 Mon Sep 17 00:00:00 2001 From: Matthew Gordon Date: Mon, 10 Feb 2020 16:52:09 -0500 Subject: [PATCH] Create Real trait to replace nalgebra::RealField Real inherits RealField, but I want to add more to it. --- src/camera.rs | 12 ++--- src/colour.rs | 16 ++++--- src/image.rs | 14 +++--- src/integrators.rs | 12 ++--- src/lib.rs | 3 ++ src/materials.rs | 19 ++++---- src/mesh.rs | 9 ++-- src/raycasting/axis_aligned_bounding_box.rs | 4 +- src/raycasting/mod.rs | 24 +++++----- src/raycasting/plane.rs | 13 +++--- src/raycasting/sphere.rs | 13 +++--- src/raycasting/triangle.rs | 25 ++++++----- src/realtype.rs | 6 +++ src/sampler.rs | 6 +-- src/scene.rs | 5 ++- src/util/algebra_utils.rs | 6 ++- src/util/axis_aligned_bounding_box.rs | 7 +-- src/util/interval.rs | 8 ++-- src/util/normalizer.rs | 50 +++++++++++---------- 19 files changed, 141 insertions(+), 111 deletions(-) create mode 100644 src/realtype.rs diff --git a/src/camera.rs b/src/camera.rs index 043bc2f..477db28 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -1,4 +1,4 @@ -use nalgebra::{convert, Point3, RealField, Vector3}; +use nalgebra::{convert, Point3, Vector3}; use super::colour::{ColourRgbF, NamedColour}; use super::image::ImageRgbF; @@ -7,9 +7,11 @@ use super::raycasting::Ray; use super::sampler::Sampler; use super::scene::Scene; +use crate::Real; + use std::sync::{Arc, Mutex}; -struct ImageSampler { +struct ImageSampler { image_height_pixels: u32, image_width_pixels: u32, @@ -20,7 +22,7 @@ struct ImageSampler { film_distance: T, } -impl ImageSampler { +impl ImageSampler { pub fn new(width: u32, height: u32, camera_location: Point3) -> ImageSampler { let (film_width, film_height) = { let width: T = convert(width as f64); @@ -64,13 +66,13 @@ impl ImageSampler { } } -pub fn render_scene(output_image: Arc>>, scene: Arc>) { +pub fn render_scene(output_image: Arc>>, scene: Arc>) { let height = output_image.lock().unwrap().get_height(); let width = output_image.lock().unwrap().get_width(); partial_render_scene(output_image, scene, 0, height, 0, width, height, width) } -pub fn partial_render_scene( +pub fn partial_render_scene( output_image: Arc>>, scene: Arc>, row_start: u32, diff --git a/src/colour.rs b/src/colour.rs index 9aad6db..43dfa05 100644 --- a/src/colour.rs +++ b/src/colour.rs @@ -1,13 +1,15 @@ -use nalgebra::{convert, RealField, Vector3}; +use nalgebra::{convert, Vector3}; + +use crate::Real; use std::ops::{Add, Mul}; #[derive(Copy, Clone, Debug)] -pub struct ColourRgbF { +pub struct ColourRgbF { values: Vector3, } -impl ColourRgbF { +impl ColourRgbF { pub fn new(red: T, green: T, blue: T) -> ColourRgbF { ColourRgbF { values: Vector3::new(red, green, blue), @@ -80,7 +82,7 @@ pub enum NamedColour { Navy, } -impl Add> for ColourRgbF { +impl Add> for ColourRgbF { type Output = ColourRgbF; fn add(self, rhs: ColourRgbF) -> ColourRgbF { ColourRgbF { @@ -89,7 +91,7 @@ impl Add> for ColourRgbF { } } -impl Mul for ColourRgbF { +impl Mul for ColourRgbF { type Output = ColourRgbF; fn mul(self, rhs: T) -> ColourRgbF { ColourRgbF { @@ -98,7 +100,7 @@ impl Mul for ColourRgbF { } } -impl Mul> for ColourRgbF { +impl Mul> for ColourRgbF { type Output = ColourRgbF; fn mul(self, rhs: ColourRgbF) -> ColourRgbF { ColourRgbF { @@ -115,7 +117,7 @@ mod tests { use super::*; use quickcheck::{Arbitrary, Gen}; use quickcheck_macros::quickcheck; - impl Arbitrary for ColourRgbF { + impl Arbitrary for ColourRgbF { fn arbitrary(g: &mut G) -> ColourRgbF { let values = as Arbitrary>::arbitrary(g); ColourRgbF { values } diff --git a/src/image.rs b/src/image.rs index 77b8574..a26df56 100644 --- a/src/image.rs +++ b/src/image.rs @@ -1,9 +1,11 @@ use std::convert::TryInto; -use nalgebra::{clamp, convert, RealField, Vector3}; +use nalgebra::{clamp, convert, Vector3}; use super::colour::{ColourRgbF, ColourRgbU8}; +use crate::Real; + pub struct ImageRgbU8 { pixel_data: Vec, width: u32, @@ -64,13 +66,13 @@ impl ImageRgbU8 { } } -pub struct ImageRgbF { +pub struct ImageRgbF { pixel_data: Vec, width: u32, height: u32, } -impl ImageRgbF { +impl ImageRgbF { pub fn new(width: u32, height: u32) -> ImageRgbF { ImageRgbF { width, @@ -145,7 +147,7 @@ impl NormalizedAsByte for f64 { } } -pub trait ToneMapper { +pub trait ToneMapper { fn apply_tone_mapping(&self, image_in: &ImageRgbF, image_out: &mut ImageRgbU8); } @@ -153,12 +155,12 @@ pub trait ToneMapper { pub struct ClampingToneMapper {} impl ClampingToneMapper { - fn clamp(v: &T) -> u8 { + fn clamp(v: &T) -> u8 { clamp(v, &T::zero(), &T::one()).normalized_to_byte() } } -impl ToneMapper for ClampingToneMapper { +impl ToneMapper for ClampingToneMapper { fn apply_tone_mapping(&self, image_in: &ImageRgbF, image_out: &mut ImageRgbU8) { assert!(image_in.get_width() == image_out.get_width()); assert!(image_in.get_height() == image_out.get_height()); diff --git a/src/integrators.rs b/src/integrators.rs index e3f2abe..255c4c8 100644 --- a/src/integrators.rs +++ b/src/integrators.rs @@ -1,27 +1,29 @@ -use nalgebra::{convert, RealField, Vector3}; +use nalgebra::{convert, Vector3}; use super::colour::ColourRgbF; use super::raycasting::{IntersectionInfo, Ray}; use super::sampler::Sampler; use super::util::algebra_utils::try_change_of_basis_matrix; -pub trait Integrator { +use crate::Real; + +pub trait Integrator { fn integrate(&self, sampler: &Sampler, info: &IntersectionInfo) -> ColourRgbF; } -pub struct DirectionalLight { +pub struct DirectionalLight { pub direction: Vector3, pub colour: ColourRgbF, } -pub struct WhittedIntegrator { +pub struct WhittedIntegrator { pub ambient_light: ColourRgbF, pub lights: Vec>, } // TODO: Get rid of the magic bias number, which should be calculated base on expected error // bounds and tangent direction -impl Integrator for WhittedIntegrator { +impl Integrator for WhittedIntegrator { fn integrate(&self, sampler: &Sampler, info: &IntersectionInfo) -> ColourRgbF { let world_to_bsdf_space = try_change_of_basis_matrix(&info.tangent, &info.cotangent, &info.normal) diff --git a/src/lib.rs b/src/lib.rs index e0111e9..5b9e733 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,10 +5,13 @@ pub mod integrators; pub mod materials; pub mod mesh; pub mod raycasting; +pub mod realtype; pub mod sampler; pub mod scene; pub mod util; +use realtype::Real; + #[cfg(bench)] mod tests { extern crate test; diff --git a/src/materials.rs b/src/materials.rs index 1f103b6..8f6875e 100644 --- a/src/materials.rs +++ b/src/materials.rs @@ -1,12 +1,13 @@ -use nalgebra::{clamp, convert, RealField, Vector3}; +use nalgebra::{clamp, convert, Vector3}; use super::colour::{ColourRgbF, NamedColour}; +use crate::Real; use std::fmt::Debug; type Bsdf<'a, T> = Box, Vector3, ColourRgbF) -> ColourRgbF + 'a>; -pub trait Material: Debug + Sync + Send { +pub trait Material: Debug + Sync + Send { fn bsdf<'a>(&'a self) -> Bsdf<'a, T>; fn sample(&self, _w_o: &Vector3) -> Vec> { @@ -15,12 +16,12 @@ pub trait Material: Debug + Sync + Send { } #[derive(Debug)] -pub struct LambertianMaterial { +pub struct LambertianMaterial { pub colour: ColourRgbF, pub diffuse_strength: T, } -impl LambertianMaterial { +impl LambertianMaterial { pub fn new_dummy() -> LambertianMaterial { LambertianMaterial { colour: ColourRgbF::new(T::one(), T::one(), T::one()), @@ -29,7 +30,7 @@ impl LambertianMaterial { } } -impl Material for LambertianMaterial { +impl Material for LambertianMaterial { fn bsdf<'a>(&'a self) -> Bsdf<'a, T> { Box::new( move |_w_o: Vector3, _w_i: Vector3, colour_in: ColourRgbF| { @@ -40,14 +41,14 @@ impl Material for LambertianMaterial { } #[derive(Debug)] -pub struct PhongMaterial { +pub struct PhongMaterial { pub colour: ColourRgbF, pub diffuse_strength: T, pub specular_strength: T, pub smoothness: T, } -impl Material for PhongMaterial { +impl Material for PhongMaterial { fn bsdf<'a>(&'a self) -> Bsdf<'a, T> { Box::new( move |w_o: Vector3, w_i: Vector3, colour_in: ColourRgbF| { @@ -66,13 +67,13 @@ impl Material for PhongMaterial { } #[derive(Debug)] -pub struct ReflectiveMaterial { +pub struct ReflectiveMaterial { pub colour: ColourRgbF, pub diffuse_strength: T, pub reflection_strength: T, } -impl Material for ReflectiveMaterial { +impl Material for ReflectiveMaterial { fn bsdf<'a>(&'a self) -> Bsdf<'a, T> { Box::new( move |w_o: Vector3, w_i: Vector3, colour_in: ColourRgbF| { diff --git a/src/mesh.rs b/src/mesh.rs index 8477d8a..d6a89d1 100644 --- a/src/mesh.rs +++ b/src/mesh.rs @@ -1,17 +1,18 @@ mod wavefront_obj { use crate::materials::Material; + use crate::Real; use crate::raycasting::Triangle; use alga::general::SupersetOf; - use nalgebra::{convert, Point3, RealField, Vector3}; + use nalgebra::{convert, Point3, Vector3}; use obj::{IndexTuple, Obj, SimplePolygon}; use std::io::Result; use std::path::Path; use std::sync::Arc; - fn get_vertex_and_normal( + fn get_vertex_and_normal( index_tuple: &IndexTuple, vertex_positions: &Vec<[f32; 3]>, normal_positions: &Vec<[f32; 3]>, @@ -28,7 +29,7 @@ mod wavefront_obj { (vertex, normal) } - fn get_triangles( + fn get_triangles( polygon: &SimplePolygon, vertex_positions: &Vec<[f32; 3]>, normal_positions: &Vec<[f32; 3]>, @@ -63,7 +64,7 @@ mod wavefront_obj { } } - pub fn load_obj( + pub fn load_obj( filename: &Path, material: Arc>, ) -> Result>> diff --git a/src/raycasting/axis_aligned_bounding_box.rs b/src/raycasting/axis_aligned_bounding_box.rs index 304929a..2275d6c 100644 --- a/src/raycasting/axis_aligned_bounding_box.rs +++ b/src/raycasting/axis_aligned_bounding_box.rs @@ -1,4 +1,4 @@ -use nalgebra::RealField; +use crate::Real; use crate::util::Interval; @@ -8,7 +8,7 @@ use itertools::izip; pub use crate::util::axis_aligned_bounding_box::BoundingBox; -impl IntersectP for BoundingBox { +impl IntersectP for BoundingBox { fn intersect(&self, ray: &Ray) -> bool { let mut t_interval_in_bounds = Interval::infinite(); for (&ray_origin, &ray_direction, bounds) in diff --git a/src/raycasting/mod.rs b/src/raycasting/mod.rs index 8da192f..ec0056c 100644 --- a/src/raycasting/mod.rs +++ b/src/raycasting/mod.rs @@ -1,6 +1,7 @@ -use nalgebra::{Point3, RealField, Vector3}; +use nalgebra::{Point3, Vector3}; use super::materials::Material; +use crate::Real; use std::sync::Arc; @@ -16,14 +17,13 @@ pub use triangle::Triangle; pub mod axis_aligned_bounding_box; pub use axis_aligned_bounding_box::BoundingBox; - #[derive(Clone, Debug)] -pub struct Ray { +pub struct Ray { pub origin: Point3, pub direction: Vector3, } -impl Ray { +impl Ray { pub fn new(origin: Point3, direction: Vector3) -> Ray { Ray { origin, @@ -41,7 +41,7 @@ impl Ray { } #[derive(Debug)] -pub struct IntersectionInfo { +pub struct IntersectionInfo { pub distance: T, pub location: Point3, pub normal: Vector3, @@ -51,21 +51,21 @@ pub struct IntersectionInfo { pub material: Arc>, } -pub trait Intersect: Send + Sync { +pub trait Intersect: Send + Sync { /// Test if the ray intersects the object, and return information about the object and intersection. fn intersect<'a>(&'a self, ray: &Ray) -> Option>; } -pub trait IntersectP: Send + Sync { +pub trait IntersectP: Send + Sync { /// Test if the ray intersects the object, without calculating any extra information. fn intersect(&self, ray: &Ray) -> bool; } -pub trait HasBoundingBox: Send + Sync { +pub trait HasBoundingBox: Send + Sync { fn bounding_box(&self) -> BoundingBox; } -pub trait Primitive: Intersect + HasBoundingBox {} +pub trait Primitive: Intersect + HasBoundingBox {} #[cfg(test)] mod tests { @@ -73,7 +73,7 @@ mod tests { use super::*; use quickcheck::{Arbitrary, Gen}; - impl Arbitrary for Ray { + impl Arbitrary for Ray { fn arbitrary(g: &mut G) -> Ray { let origin = as Arbitrary>::arbitrary(g); let direction = as Arbitrary>::arbitrary(g); @@ -98,9 +98,9 @@ mod tests { let p3 = ray.point_at(t3); let epsilon = [t1, t2, t3, ray.origin[0], ray.origin[1], ray.origin[2]] .iter() - .fold(0.0, |a, &b| a.max(b.abs())) + .fold(0.0f64, |a, &b| a.max(b.abs())) * std::f64::EPSILON - * 256.0; + * 256.0f64; (p2 - p1).cross(&(p3 - p2)).norm() < epsilon } diff --git a/src/raycasting/plane.rs b/src/raycasting/plane.rs index fd8ebda..7babf05 100644 --- a/src/raycasting/plane.rs +++ b/src/raycasting/plane.rs @@ -1,12 +1,13 @@ -use nalgebra::{convert, Point3, RealField, Vector3}; +use nalgebra::{convert, Point3, Vector3}; use crate::materials::Material; +use crate::Real; use super::{BoundingBox, HasBoundingBox, Intersect, IntersectionInfo, Primitive, Ray}; use std::sync::Arc; -pub struct Plane { +pub struct Plane { normal: Vector3, tangent: Vector3, cotangent: Vector3, @@ -14,7 +15,7 @@ pub struct Plane { material: Arc>, } -impl Plane { +impl Plane { pub fn new( normal: Vector3, distance_from_origin: T, @@ -35,7 +36,7 @@ impl Plane { } } -impl Intersect for Plane { +impl Intersect for Plane { fn intersect<'a>(&'a self, ray: &Ray) -> Option> { let ray_direction_dot_plane_normal = ray.direction.dot(&self.normal); let point_on_plane = self.normal * self.distance_from_origin; @@ -64,7 +65,7 @@ impl Intersect for Plane { } } -impl HasBoundingBox for Plane { +impl HasBoundingBox for Plane { fn bounding_box(&self) -> BoundingBox { let p0 = Point3::from(self.normal * self.distance_from_origin); let f = |v: Vector3| { @@ -87,7 +88,7 @@ impl HasBoundingBox for Plane { } } -impl Primitive for Plane {} +impl Primitive for Plane {} #[cfg(test)] mod tests { diff --git a/src/raycasting/sphere.rs b/src/raycasting/sphere.rs index 7fd7e3e..85b9701 100644 --- a/src/raycasting/sphere.rs +++ b/src/raycasting/sphere.rs @@ -1,18 +1,19 @@ -use nalgebra::{convert, Point3, RealField, Vector3}; +use nalgebra::{convert, Point3, Vector3}; use crate::materials::Material; +use crate::Real; use super::{BoundingBox, HasBoundingBox, Intersect, IntersectionInfo, Primitive, Ray}; use std::sync::Arc; -pub struct Sphere { +pub struct Sphere { centre: Point3, radius: T, material: Arc>, } -impl Sphere { +impl Sphere { pub fn new(centre: Point3, radius: T, material: Arc>) -> Sphere { Sphere { centre, @@ -22,7 +23,7 @@ impl Sphere { } } -impl Intersect for Sphere { +impl Intersect for Sphere { fn intersect<'a>(&'a self, ray: &Ray) -> Option> { let two: T = convert(2.0); let four: T = convert(4.0); @@ -77,14 +78,14 @@ impl Intersect for Sphere { } } -impl HasBoundingBox for Sphere { +impl HasBoundingBox for Sphere { fn bounding_box(&self) -> BoundingBox { let radius_xyz = Vector3::new(self.radius, self.radius, self.radius); BoundingBox::from_corners(self.centre + radius_xyz, self.centre - radius_xyz) } } -impl Primitive for Sphere {} +impl Primitive for Sphere {} #[cfg(test)] mod tests { diff --git a/src/raycasting/triangle.rs b/src/raycasting/triangle.rs index d38f92a..509e21d 100644 --- a/src/raycasting/triangle.rs +++ b/src/raycasting/triangle.rs @@ -1,18 +1,19 @@ use crate::materials::Material; +use crate::Real; use super::{BoundingBox, HasBoundingBox, Intersect, IntersectionInfo, Primitive, Ray}; -use nalgebra::{Point3, RealField, Vector2, Vector3}; +use nalgebra::{Point3, Vector2, Vector3}; use std::sync::Arc; #[derive(Debug)] -pub struct Triangle { +pub struct Triangle { pub vertices: [Point3; 3], pub normals: [Vector3; 3], pub material: Arc>, } -impl Intersect for Triangle { +impl Intersect for Triangle { fn intersect<'a>(&'a self, ray: &Ray) -> Option> { let translation = -ray.origin.coords; let indices = indices_with_index_of_largest_element_last(&ray.direction); @@ -77,15 +78,15 @@ impl Intersect for Triangle { } } -impl HasBoundingBox for Triangle { +impl HasBoundingBox for Triangle { fn bounding_box(&self) -> BoundingBox { BoundingBox::from_points(&self.vertices) } } -impl Primitive for Triangle {} +impl Primitive for Triangle {} -fn indices_with_index_of_largest_element_last(v: &Vector3) -> [usize; 3] { +fn indices_with_index_of_largest_element_last(v: &Vector3) -> [usize; 3] { if v.x > v.y { if v.z > v.x { [0, 1, 2] @@ -105,24 +106,24 @@ fn is_valid_permutation(indices: &[usize; 3]) -> bool { (0..2).all(|i: usize| indices.iter().any(|&j| j == i)) } -fn permute_vector_elements(v: &Vector3, indices: &[usize; 3]) -> Vector3 { +fn permute_vector_elements(v: &Vector3, indices: &[usize; 3]) -> Vector3 { debug_assert!(is_valid_permutation(&indices)); Vector3::new(v[indices[0]], v[indices[1]], v[indices[2]]) } -fn calculate_shear_to_z_axis(v: &Vector3) -> Vector2 { +fn calculate_shear_to_z_axis(v: &Vector3) -> Vector2 { Vector2::new(-v.x / v.z, -v.y / v.z) } -fn apply_shear_to_z_axis(v: &Vector3, s: &Vector2) -> Vector3 { +fn apply_shear_to_z_axis(v: &Vector3, s: &Vector2) -> Vector3 { Vector3::new(v.x + s.x * v.z, v.y + s.y * v.z, v.z) } -fn signed_edge_function(a: &Vector3, b: &Vector3) -> T { +fn signed_edge_function(a: &Vector3, b: &Vector3) -> T { a.x * b.y - b.x * a.y } -fn signed_edge_functions(vertices: &Vec>) -> Vector3 { +fn signed_edge_functions(vertices: &Vec>) -> Vector3 { // Iterate over the inputs in such a way that each output element is calculated // from the twoother elements of the input. ( (y,z) -> x, (z,x) -> y, (x,y) -> z ) Vector3::from_iterator( @@ -136,7 +137,7 @@ fn signed_edge_functions(vertices: &Vec>) -> Vector3 ) } -fn barycentric_coordinates_from_signed_edge_functions(e: Vector3) -> Vector3 { +fn barycentric_coordinates_from_signed_edge_functions(e: Vector3) -> Vector3 { e * (T::one() / e.iter().fold(T::zero(), |a, &b| a + b)) } diff --git a/src/realtype.rs b/src/realtype.rs new file mode 100644 index 0000000..1aa2f9d --- /dev/null +++ b/src/realtype.rs @@ -0,0 +1,6 @@ +use nalgebra::RealField; + +pub trait Real: RealField {} + +impl Real for f32 {} +impl Real for f64 {} diff --git a/src/sampler.rs b/src/sampler.rs index 172bcb6..06422a3 100644 --- a/src/sampler.rs +++ b/src/sampler.rs @@ -1,13 +1,13 @@ use super::raycasting::{IntersectionInfo, Ray}; use super::scene::Scene; -use nalgebra::RealField; +use crate::Real; -pub struct Sampler<'a, T: RealField> { +pub struct Sampler<'a, T: Real> { pub scene: &'a Scene, } -impl<'a, T: RealField> Sampler<'a, T> { +impl<'a, T: Real> Sampler<'a, T> { pub fn sample(&self, ray: &Ray) -> Option> { self.scene .objects diff --git a/src/scene.rs b/src/scene.rs index d11d826..18c1536 100644 --- a/src/scene.rs +++ b/src/scene.rs @@ -1,10 +1,11 @@ -use nalgebra::{Point3, RealField}; +use nalgebra::{Point3}; use crate::raycasting::Primitive; +use crate::Real; use std::sync::Arc; -pub struct Scene { +pub struct Scene { pub camera_location: Point3, pub objects: Vec>>, } diff --git a/src/util/algebra_utils.rs b/src/util/algebra_utils.rs index a504ef4..d4dc9f3 100644 --- a/src/util/algebra_utils.rs +++ b/src/util/algebra_utils.rs @@ -1,6 +1,8 @@ -use nalgebra::{Matrix3, RealField, Vector3}; +use nalgebra::{Matrix3, Vector3}; -pub fn try_change_of_basis_matrix( +use crate::Real; + +pub fn try_change_of_basis_matrix( x: &Vector3, y: &Vector3, z: &Vector3, diff --git a/src/util/axis_aligned_bounding_box.rs b/src/util/axis_aligned_bounding_box.rs index 02bce5f..0e55600 100644 --- a/src/util/axis_aligned_bounding_box.rs +++ b/src/util/axis_aligned_bounding_box.rs @@ -1,15 +1,16 @@ -use nalgebra::{Point3, RealField}; +use nalgebra::Point3; use crate::util::Interval; +use crate::Real; use itertools::izip; #[derive(Debug, Clone, Copy)] -pub struct BoundingBox { +pub struct BoundingBox { pub bounds: [Interval; 3], } -impl BoundingBox { +impl BoundingBox { pub fn from_corners(a: Point3, b: Point3) -> Self { let mut result = BoundingBox { bounds: [Interval::infinite(); 3], diff --git a/src/util/interval.rs b/src/util/interval.rs index 4389681..6f6b0bc 100644 --- a/src/util/interval.rs +++ b/src/util/interval.rs @@ -1,12 +1,14 @@ -use nalgebra::{convert, RealField}; +use nalgebra::convert; + +use crate::Real; #[derive(Debug, Clone, Copy)] -pub struct Interval { +pub struct Interval { min: T, max: T, } -impl Interval { +impl Interval { pub fn new(a: T, b: T) -> Self { if a > b { Interval { min: b, max: a } diff --git a/src/util/normalizer.rs b/src/util/normalizer.rs index 27e14cd..6c2dadf 100644 --- a/src/util/normalizer.rs +++ b/src/util/normalizer.rs @@ -1,17 +1,19 @@ use super::axis_aligned_bounding_box::BoundingBox; use super::Interval; -use nalgebra::{clamp, Point3, RealField}; +use crate::Real; + +use nalgebra::{clamp, Point3}; use itertools::izip; #[derive(Debug, Copy, Clone)] -pub struct RealFieldNormalizer { +pub struct RealNormalizer { min: T, range: T, } -impl RealFieldNormalizer { +impl RealNormalizer { pub fn new(interval: Interval) -> Self { let min = interval.get_min(); let range = interval.get_max() - min; @@ -28,21 +30,21 @@ impl RealFieldNormalizer { } #[derive(Debug)] -pub struct Point3Normalizer { - dimension_normalizers: [RealFieldNormalizer; 3], +pub struct Point3Normalizer { + dimension_normalizers: [RealNormalizer; 3], } -impl Point3Normalizer { +impl Point3Normalizer { pub fn new(bounds: BoundingBox) -> Self { let mut normalizer = Point3Normalizer { - dimension_normalizers: [RealFieldNormalizer::new(Interval::empty()); 3], + dimension_normalizers: [RealNormalizer::new(Interval::empty()); 3], }; for (normalizer, &bounds) in normalizer .dimension_normalizers .iter_mut() .zip(bounds.bounds.iter()) { - *normalizer = RealFieldNormalizer::new(bounds); + *normalizer = RealNormalizer::new(bounds); } normalizer } @@ -80,43 +82,43 @@ mod test { #[quickcheck] fn normalize_zero_to_one_yields_input(value: f64) -> bool { - let target = RealFieldNormalizer::new(Interval::new(0.0, 1.0)); + let target = RealNormalizer::new(Interval::new(0.0, 1.0)); target.normalize(value) == value } #[quickcheck] fn normalize_two_to_three_yields_input_minus_two(value: f64) -> bool { - let target = RealFieldNormalizer::new(Interval::new(2.0, 3.0)); + let target = RealNormalizer::new(Interval::new(2.0, 3.0)); target.normalize(value) == value - 2.0 } #[quickcheck] fn normalize_negative_three_to_negative_two_yields_input_plus_three(value: f64) -> bool { - let target = RealFieldNormalizer::new(Interval::new(-3.0, -2.0)); + let target = RealNormalizer::new(Interval::new(-3.0, -2.0)); target.normalize(value) == value + 3.0 } #[quickcheck] fn normalize_zero_to_two_yields_input_divided_by_two(value: f64) -> bool { - let target = RealFieldNormalizer::new(Interval::new(0.0, 2.0)); + let target = RealNormalizer::new(Interval::new(0.0, 2.0)); target.normalize(value) == value / 2.0 } #[test] fn normalize_two_to_four_yields_zero_when_input_is_two() { - let target = RealFieldNormalizer::new(Interval::new(2.0, 4.0)); + let target = RealNormalizer::new(Interval::new(2.0, 4.0)); assert!(target.normalize(2.0) == 0.0) } #[test] fn normalize_two_to_four_yields_one_when_input_is_four() { - let target = RealFieldNormalizer::new(Interval::new(2.0, 4.0)); + let target = RealNormalizer::new(Interval::new(2.0, 4.0)); assert!(target.normalize(4.0) == 1.0) } #[quickcheck] fn normalize_two_to_four_yields_input_divided_by_two_minus_one(value: f64) -> bool { - let target = RealFieldNormalizer::new(Interval::new(2.0, 4.0)); + let target = RealNormalizer::new(Interval::new(2.0, 4.0)); target.normalize(value) == (value - 2.0) / 2.0 } @@ -124,7 +126,7 @@ mod test { fn normalize_and_clamp_two_to_four_yields_zero_when_input_less_than_or_equal_two( value: f64, ) -> bool { - let target = RealFieldNormalizer::new(Interval::new(2.0, 4.0)); + let target = RealNormalizer::new(Interval::new(2.0, 4.0)); target.normalize_and_clamp(value) == 0.0 || value > 2.0 } @@ -132,7 +134,7 @@ mod test { fn normalize_and_clamp_two_to_four_yields_one_when_input_greater_than_or_equal_four( value: f64, ) -> bool { - let target = RealFieldNormalizer::new(Interval::new(2.0, 4.0)); + let target = RealNormalizer::new(Interval::new(2.0, 4.0)); target.normalize_and_clamp(value) == 1.0 || value < 4.0 } @@ -140,7 +142,7 @@ mod test { fn normalize_and_clamp_two_to_four_yields_same_value_as_normalize_when_in_range( value: f64, ) -> bool { - let target = RealFieldNormalizer::new(Interval::new(2.0, 4.0)); + let target = RealNormalizer::new(Interval::new(2.0, 4.0)); target.normalize_and_clamp(value) == target.normalize(value) || value < 2.0 || value > 4.0 } @@ -150,9 +152,9 @@ mod test { b: Point3, c: Point3, ) -> bool { - let x_normalizer = RealFieldNormalizer::new(Interval::new(a.x.min(b.x), a.x.max(b.x))); - let y_normalizer = RealFieldNormalizer::new(Interval::new(a.y.min(b.y), a.y.max(b.y))); - let z_normalizer = dbg!(RealFieldNormalizer::new(Interval::new( + let x_normalizer = RealNormalizer::new(Interval::new(a.x.min(b.x), a.x.max(b.x))); + let y_normalizer = RealNormalizer::new(Interval::new(a.y.min(b.y), a.y.max(b.y))); + let z_normalizer = dbg!(RealNormalizer::new(Interval::new( a.z.min(b.z), a.z.max(b.z) ))); @@ -169,15 +171,15 @@ mod test { b: Point3, c: Point3, ) -> bool { - let x_normalizer = dbg!(RealFieldNormalizer::new(Interval::new( + let x_normalizer = dbg!(RealNormalizer::new(Interval::new( a.x.min(b.x), a.x.max(b.x) ))); - let y_normalizer = dbg!(RealFieldNormalizer::new(Interval::new( + let y_normalizer = dbg!(RealNormalizer::new(Interval::new( a.y.min(b.y), a.y.max(b.y) ))); - let z_normalizer = dbg!(RealFieldNormalizer::new(Interval::new( + let z_normalizer = dbg!(RealNormalizer::new(Interval::new( a.z.min(b.z), a.z.max(b.z) )));