diff --git a/rtchallenge/Cargo.lock b/rtchallenge/Cargo.lock
index 5b8910d..f005268 100644
--- a/rtchallenge/Cargo.lock
+++ b/rtchallenge/Cargo.lock
@@ -212,15 +212,6 @@ version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
-[[package]]
-name = "float-cmp"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e1267f4ac4f343772758f7b1bdcbe767c218bbab93bb432acbf5162bbf85a6c4"
-dependencies = [
- "num-traits",
-]
-
[[package]]
name = "half"
version = "1.7.1"
@@ -449,7 +440,6 @@ version = "0.1.0"
dependencies = [
"anyhow",
"criterion",
- "float-cmp",
"png",
"thiserror",
]
diff --git a/rtchallenge/Cargo.toml b/rtchallenge/Cargo.toml
index a1dbdfa..4bc9440 100644
--- a/rtchallenge/Cargo.toml
+++ b/rtchallenge/Cargo.toml
@@ -9,11 +9,10 @@ edition = "2018"
[dependencies]
anyhow = "1.0.41"
criterion = "0.3.4"
-float-cmp = "0.8.0"
png = "0.16.8"
thiserror = "1.0.25"
[[bench]]
name = "matrices"
-harness = false
\ No newline at end of file
+harness = false
diff --git a/rtchallenge/src/matrices.rs b/rtchallenge/src/matrices.rs
index 834f261..5843ca9 100644
--- a/rtchallenge/src/matrices.rs
+++ b/rtchallenge/src/matrices.rs
@@ -1,18 +1,15 @@
use std::fmt;
use std::ops::{Index, IndexMut, Mul};
-use float_cmp::{ApproxEq, F32Margin};
+// Implement a PartialEq that does approx_eq internally.
+//use float_cmp::{ApproxEq, F32Margin};
use crate::tuples::Tuple;
-#[derive(Default, Clone, Copy)]
-/// Matrix4x4 represents a 4x4 matrix in row-major form. So, element `m[i][j]` corresponds to mi,j
-/// where `i` is the row number and `j` is the column number.
-pub struct Matrix4x4 {
- m: [[f32; 4]; 4],
-}
+/// Value considered close enough for PartialEq implementations.
+const EPSILON: f32 = 0.00001;
-#[derive(Debug, PartialEq)]
+#[derive(Debug)]
pub struct Matrix2x2 {
m: [[f32; 2]; 2],
}
@@ -44,8 +41,23 @@ impl Index<(usize, usize)> for Matrix2x2 {
&self.m[row][col]
}
}
+impl PartialEq for Matrix2x2 {
+ fn eq(&self, rhs: &Matrix2x2) -> bool {
+ let l = self.m;
+ let r = rhs.m;
+ for i in 0..2 {
+ for j in 0..2 {
+ let d = (l[i][j] - r[i][j]).abs();
+ if d > EPSILON {
+ return false;
+ }
+ }
+ }
+ true
+ }
+}
-#[derive(Debug, PartialEq)]
+#[derive(Debug)]
pub struct Matrix3x3 {
m: [[f32; 3]; 3],
}
@@ -139,6 +151,29 @@ impl Index<(usize, usize)> for Matrix3x3 {
}
}
+impl PartialEq for Matrix3x3 {
+ fn eq(&self, rhs: &Matrix3x3) -> bool {
+ let l = self.m;
+ let r = rhs.m;
+ for i in 0..3 {
+ for j in 0..3 {
+ let d = (l[i][j] - r[i][j]).abs();
+ if d > EPSILON {
+ return false;
+ }
+ }
+ }
+ true
+ }
+}
+
+#[derive(Copy, Clone, Default)]
+/// Matrix4x4 represents a 4x4 matrix in row-major form. So, element `m[i][j]` corresponds to mi,j
+/// where `i` is the row number and `j` is the column number.
+pub struct Matrix4x4 {
+ m: [[f32; 4]; 4],
+}
+
impl From<[f32; 16]> for Matrix4x4 {
fn from(t: [f32; 16]) -> Self {
Matrix4x4 {
@@ -152,44 +187,6 @@ impl From<[f32; 16]> for Matrix4x4 {
}
}
-impl<'a> ApproxEq for &'a Matrix4x4 {
- type Margin = F32Margin;
-
- /// Implement float_cmp::ApproxEq for Matrix4x4
- ///
- /// # Examples
- /// ```
- /// use float_cmp::approx_eq;
- /// use rtchallenge::matrices::Matrix4x4;
- ///
- /// assert!(!approx_eq!(
- /// &Matrix4x4,
- /// &Matrix4x4::default(),
- /// &Matrix4x4::identity(),
- /// ulps = 1
- /// ));
- ///
- /// assert!(approx_eq!(
- /// &Matrix4x4,
- /// &Matrix4x4::identity(),
- /// &Matrix4x4::identity(),
- /// ulps = 1
- /// ));
- /// ```
- fn approx_eq>(self, m2: Self, margin: T) -> bool {
- let m = self;
- let margin = margin.into();
- for row in 0..4 {
- for col in 0..4 {
- if !m[(row, col)].approx_eq(m2[(row, col)], margin) {
- return false;
- }
- }
- }
- true
- }
-}
-
impl Matrix4x4 {
/// Create a `Matrix4x4` containing the identity, all zeros with ones along the diagonal.
/// # Examples
@@ -290,8 +287,6 @@ impl Matrix4x4 {
/// ```
/// use std::f32::consts::PI;
///
- /// use float_cmp::approx_eq;
- ///
/// use rtchallenge::{matrices::Matrix4x4, tuples::Tuple};
///
/// // A scaling matrix applied to a point.
@@ -303,12 +298,7 @@ impl Matrix4x4 {
/// half_quarter * p,
/// Tuple::point(0., 2_f32.sqrt() / 2., 2_f32.sqrt() / 2.)
/// );
- /// assert!(approx_eq!(
- /// Tuple,
- /// full_quarter * p,
- /// Tuple::point(0., 0., 1.),
- /// epsilon = 0.0001
- /// ));
+ /// assert_eq!(full_quarter * p, Tuple::point(0., 0., 1.),);
/// ```
pub fn rotation_x(radians: f32) -> Matrix4x4 {
let r = radians;
@@ -327,8 +317,6 @@ impl Matrix4x4 {
/// ```
/// use std::f32::consts::PI;
///
- /// use float_cmp::approx_eq;
- ///
/// use rtchallenge::{matrices::Matrix4x4, tuples::Tuple};
///
/// // A scaling matrix applied to a point.
@@ -340,12 +328,7 @@ impl Matrix4x4 {
/// half_quarter * p,
/// Tuple::point(2_f32.sqrt() / 2., 0., 2_f32.sqrt() / 2.)
/// );
- /// assert!(approx_eq!(
- /// Tuple,
- /// full_quarter * p,
- /// Tuple::point(1., 0., 0.,),
- /// epsilon = 0.0001
- /// ));
+ /// assert_eq!(full_quarter * p, Tuple::point(1., 0., 0.,),);
/// ```
pub fn rotation_y(radians: f32) -> Matrix4x4 {
let r = radians;
@@ -364,8 +347,6 @@ impl Matrix4x4 {
/// ```
/// use std::f32::consts::PI;
///
- /// use float_cmp::approx_eq;
- ///
/// use rtchallenge::{matrices::Matrix4x4, tuples::Tuple};
///
/// // A scaling matrix applied to a point.
@@ -377,12 +358,7 @@ impl Matrix4x4 {
/// half_quarter * p,
/// Tuple::point(-2_f32.sqrt() / 2., 2_f32.sqrt() / 2., 0.)
/// );
- /// assert!(approx_eq!(
- /// Tuple,
- /// full_quarter * p,
- /// Tuple::point(-1., 0., 0.,),
- /// epsilon = 0.0001
- /// ));
+ /// assert_eq!(full_quarter * p, Tuple::point(-1., 0., 0.,),);
/// ```
pub fn rotation_z(radians: f32) -> Matrix4x4 {
let r = radians;
@@ -624,7 +600,6 @@ impl Matrix4x4 {
///
/// # Examples
/// ```
- /// use float_cmp::approx_eq;
/// use rtchallenge::matrices::Matrix4x4;
///
/// let a = Matrix4x4::new(
@@ -640,55 +615,49 @@ impl Matrix4x4 {
/// assert_eq!(b[(3, 2)], -160. / 532.);
/// assert_eq!(a.cofactor(3, 2), 105.);
/// assert_eq!(b[(2, 3)], 105. / 532.);
- /// assert!(approx_eq!(
- /// &Matrix4x4,
- /// &b,
- /// &Matrix4x4::new(
- /// [0.21805, 0.45113, 0.24060, -0.04511],
- /// [-0.80827, -1.45677, -0.44361, 0.52068],
- /// [-0.07895, -0.22368, -0.05263, 0.19737],
- /// [-0.52256, -0.81391, -0.30075, 0.30639],
- /// ),
- /// epsilon = 0.0001
- /// ));
+ /// assert_eq!(
+ /// b,
+ /// Matrix4x4::new(
+ /// [0.21804512, 0.45112783, 0.24060151, -0.04511278],
+ /// [-0.8082707, -1.456767, -0.44360903, 0.5206767],
+ /// [-0.078947365, -0.2236842, -0.05263158, 0.19736843],
+ /// [-0.52255636, -0.81390977, -0.30075186, 0.30639097]
+ /// )
+ /// );
///
/// // Second test case
- /// assert!(approx_eq!(
- /// &Matrix4x4,
- /// &Matrix4x4::new(
+ /// assert_eq!(
+ /// Matrix4x4::new(
/// [8., -5., 9., 2.],
/// [7., 5., 6., 1.],
/// [-6., 0., 9., 6.],
/// [-3., 0., -9., -4.],
/// )
/// .inverse(),
- /// &Matrix4x4::new(
- /// [-0.15385, -0.15385, -0.28205, -0.53846],
- /// [-0.07692, 0.12308, 0.02564, 0.03077],
- /// [0.35897, 0.35897, 0.43590, 0.92308],
- /// [-0.69231, -0.69241, -0.76923, -1.92308],
+ /// Matrix4x4::new(
+ /// [-0.15384616, -0.15384616, -0.2820513, -0.53846157],
+ /// [-0.07692308, 0.12307692, 0.025641026, 0.03076923],
+ /// [0.35897437, 0.35897437, 0.43589744, 0.9230769],
+ /// [-0.6923077, -0.6923077, -0.7692308, -1.9230769]
/// ),
- /// epsilon = 0.0005
- /// ));
+ /// );
///
/// // Third test case
- /// assert!(approx_eq!(
- /// &Matrix4x4,
- /// &Matrix4x4::new(
+ /// assert_eq!(
+ /// Matrix4x4::new(
/// [9., 3., 0., 9.],
/// [-5., -2., -6., -3.],
/// [-4., 9., 6., 4.],
/// [-7., 6., 6., 2.],
/// )
/// .inverse(),
- /// &Matrix4x4::new(
- /// [-0.04074, -0.07778, 0.14444, -0.22222],
- /// [-0.07778, 0.03333, 0.36667, -0.33333],
- /// [-0.02901, -0.14630, -0.10926, 0.12963],
- /// [0.17778, 0.06667, -0.26667, 0.33333],
+ /// Matrix4x4::new(
+ /// [-0.04074074, -0.07777778, 0.14444445, -0.22222222],
+ /// [-0.07777778, 0.033333335, 0.36666667, -0.33333334],
+ /// [-0.029012345, -0.14629629, -0.10925926, 0.12962963],
+ /// [0.17777778, 0.06666667, -0.26666668, 0.33333334]
/// ),
- /// epsilon = 0.0001
- /// ));
+ /// );
///
/// let a = Matrix4x4::new(
/// [3., -9., 7., 3.],
@@ -703,12 +672,7 @@ impl Matrix4x4 {
/// [6., -2., 0., 5.],
/// );
/// let c = a * b;
- /// assert!(approx_eq!(
- /// &Matrix4x4,
- /// &(c * b.inverse()),
- /// &a,
- /// epsilon = 0.0001
- /// ));
+ /// assert_eq!(c * b.inverse(), a);
/// ```
pub fn inverse(&self) -> Matrix4x4 {
let m = self;
@@ -813,7 +777,7 @@ impl PartialEq for Matrix4x4 {
for i in 0..4 {
for j in 0..4 {
let d = (l[i][j] - r[i][j]).abs();
- if d > f32::EPSILON {
+ if d > EPSILON {
return false;
}
}
diff --git a/rtchallenge/src/tuples.rs b/rtchallenge/src/tuples.rs
index efe9c7b..46379de 100644
--- a/rtchallenge/src/tuples.rs
+++ b/rtchallenge/src/tuples.rs
@@ -1,8 +1,6 @@
use std::ops::{Add, Div, Mul, Neg, Sub};
-use float_cmp::{ApproxEq, F32Margin};
-
-#[derive(Debug, PartialEq, Copy, Clone)]
+#[derive(Debug, Copy, Clone)]
pub struct Tuple {
pub x: f32,
pub y: f32,
@@ -45,40 +43,6 @@ impl Tuple {
}
}
-impl ApproxEq for Tuple {
- type Margin = F32Margin;
-
- /// Implement float_cmp::ApproxEq for Tuple
- ///
- /// # Examples
- /// ```
- /// use float_cmp::approx_eq;
- /// use rtchallenge::tuples::Tuple;
- ///
- /// assert!(approx_eq!(
- /// Tuple,
- /// Tuple::point(1., 1., 0.),
- /// Tuple::point(1., 1., 0.),
- /// ulps = 1
- /// ));
- ///
- /// assert!(approx_eq!(
- /// Tuple,
- /// Tuple::vector(1., 1., 0.),
- /// Tuple::vector(1., 1., 0.),
- /// ulps = 1
- /// ));
- /// ```
- fn approx_eq>(self, t2: Self, margin: T) -> bool {
- let t = self;
- let margin = margin.into();
- t.x.approx_eq(t2.x, margin)
- && t.y.approx_eq(t2.y, margin)
- && t.z.approx_eq(t2.z, margin)
- && t.w.approx_eq(t2.w, margin)
- }
-}
-
impl Add for Tuple {
type Output = Self;
fn add(self, other: Self) -> Self {
@@ -150,6 +114,14 @@ impl Sub for Tuple {
}
}
+impl PartialEq for Tuple {
+ fn eq(&self, rhs: &Tuple) -> bool {
+ ((self.x - rhs.x).abs() < f32::EPSILON)
+ && ((self.y - rhs.y).abs() < f32::EPSILON)
+ && ((self.z - rhs.z).abs() < f32::EPSILON)
+ && ((self.w - rhs.w).abs() < f32::EPSILON)
+ }
+}
pub fn dot(a: Tuple, b: Tuple) -> f32 {
a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w
}
@@ -249,8 +221,6 @@ impl Sub for Color {
#[cfg(test)]
mod tests {
- use float_cmp::approx_eq;
-
use super::{cross, dot, Color, Tuple};
#[test]
fn is_point() {
@@ -355,12 +325,8 @@ mod tests {
}
#[test]
fn vector_normalize_magnitude() {
- assert!(approx_eq!(
- f32,
- 1.,
- Tuple::vector(1., 2., 3.).normalize().magnitude(),
- ulps = 1
- ));
+ let len = Tuple::vector(1., 2., 3.).normalize().magnitude();
+ assert!((1. - len).abs() < f32::EPSILON);
}
#[test]
fn dot_two_tuples() {