Compare commits
4 Commits
462c90e8c8
...
b8df830460
| Author | SHA1 | Date | |
|---|---|---|---|
| b8df830460 | |||
| 245b02b443 | |||
| f792d1a626 | |||
| 117d7185e4 |
10
rtchallenge/Cargo.lock
generated
10
rtchallenge/Cargo.lock
generated
@ -212,15 +212,6 @@ version = "1.6.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
|
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]]
|
[[package]]
|
||||||
name = "half"
|
name = "half"
|
||||||
version = "1.7.1"
|
version = "1.7.1"
|
||||||
@ -449,7 +440,6 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"criterion",
|
"criterion",
|
||||||
"float-cmp",
|
|
||||||
"png",
|
"png",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|||||||
@ -9,7 +9,6 @@ edition = "2018"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.41"
|
anyhow = "1.0.41"
|
||||||
criterion = "0.3.4"
|
criterion = "0.3.4"
|
||||||
float-cmp = "0.8.0"
|
|
||||||
png = "0.16.8"
|
png = "0.16.8"
|
||||||
thiserror = "1.0.25"
|
thiserror = "1.0.25"
|
||||||
|
|
||||||
|
|||||||
@ -1,18 +1,15 @@
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ops::{Index, IndexMut, Mul};
|
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;
|
use crate::tuples::Tuple;
|
||||||
|
|
||||||
#[derive(Default, Clone, Copy)]
|
/// Value considered close enough for PartialEq implementations.
|
||||||
/// Matrix4x4 represents a 4x4 matrix in row-major form. So, element `m[i][j]` corresponds to m<sub>i,j</sub>
|
const EPSILON: f32 = 0.00001;
|
||||||
/// where `i` is the row number and `j` is the column number.
|
|
||||||
pub struct Matrix4x4 {
|
|
||||||
m: [[f32; 4]; 4],
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug)]
|
||||||
pub struct Matrix2x2 {
|
pub struct Matrix2x2 {
|
||||||
m: [[f32; 2]; 2],
|
m: [[f32; 2]; 2],
|
||||||
}
|
}
|
||||||
@ -44,8 +41,23 @@ impl Index<(usize, usize)> for Matrix2x2 {
|
|||||||
&self.m[row][col]
|
&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 {
|
pub struct Matrix3x3 {
|
||||||
m: [[f32; 3]; 3],
|
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 m<sub>i,j</sub>
|
||||||
|
/// 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 {
|
impl From<[f32; 16]> for Matrix4x4 {
|
||||||
fn from(t: [f32; 16]) -> Self {
|
fn from(t: [f32; 16]) -> Self {
|
||||||
Matrix4x4 {
|
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<T: Into<Self::Margin>>(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 {
|
impl Matrix4x4 {
|
||||||
/// Create a `Matrix4x4` containing the identity, all zeros with ones along the diagonal.
|
/// Create a `Matrix4x4` containing the identity, all zeros with ones along the diagonal.
|
||||||
/// # Examples
|
/// # Examples
|
||||||
@ -223,6 +220,156 @@ impl Matrix4x4 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a 4x4 matrix representing a translation of x,y,z.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rtchallenge::{matrices::Matrix4x4, tuples::Tuple};
|
||||||
|
///
|
||||||
|
/// let transform = Matrix4x4::translate(5., -3., 2.);
|
||||||
|
/// let p = Tuple::point(-3., 4., 5.);
|
||||||
|
/// assert_eq!(transform * p, Tuple::point(2., 1., 7.));
|
||||||
|
///
|
||||||
|
/// let inv = transform.inverse();
|
||||||
|
/// assert_eq!(inv * p, Tuple::point(-8., 7., 3.));
|
||||||
|
///
|
||||||
|
/// let v = Tuple::vector(-3., 4., 5.);
|
||||||
|
/// assert_eq!(transform * v, v);
|
||||||
|
/// ```
|
||||||
|
pub fn translate(x: f32, y: f32, z: f32) -> Matrix4x4 {
|
||||||
|
Matrix4x4::new(
|
||||||
|
[1., 0., 0., x],
|
||||||
|
[0., 1., 0., y],
|
||||||
|
[0., 0., 1., z],
|
||||||
|
[0., 0., 0., 1.],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a 4x4 matrix representing a scaling of x,y,z.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rtchallenge::{matrices::Matrix4x4, tuples::Tuple};
|
||||||
|
///
|
||||||
|
/// // A scaling matrix applied to a point.
|
||||||
|
/// let transform = Matrix4x4::scaling(2., 3., 4.);
|
||||||
|
/// let p = Tuple::point(-4., 6., 8.);
|
||||||
|
/// assert_eq!(transform * p, Tuple::point(-8., 18., 32.));
|
||||||
|
///
|
||||||
|
/// // A scaling matrix applied to a vector.
|
||||||
|
/// let v = Tuple::vector(-4., 6., 8.);
|
||||||
|
/// assert_eq!(transform * v, Tuple::vector(-8., 18., 32.));
|
||||||
|
///
|
||||||
|
/// // Multiplying by the inverse of a scaling matrix.
|
||||||
|
/// let inv = transform.inverse();
|
||||||
|
/// assert_eq!(inv * v, Tuple::vector(-2., 2., 2.));
|
||||||
|
///
|
||||||
|
/// // Reflection is scaling by a negative value.
|
||||||
|
/// let transform = Matrix4x4::scaling(-1., 1., 1.);
|
||||||
|
/// 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 {
|
||||||
|
Matrix4x4::new(
|
||||||
|
[x, 0., 0., 0.],
|
||||||
|
[0., y, 0., 0.],
|
||||||
|
[0., 0., z, 0.],
|
||||||
|
[0., 0., 0., 1.],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a 4x4 matrix representing a rotation around the x-axis.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::f32::consts::PI;
|
||||||
|
///
|
||||||
|
/// use rtchallenge::{matrices::Matrix4x4, tuples::Tuple};
|
||||||
|
///
|
||||||
|
/// // A scaling matrix applied to a point.
|
||||||
|
/// let p = Tuple::point(0., 1., 0.);
|
||||||
|
/// let half_quarter = Matrix4x4::rotation_x(PI / 4.);
|
||||||
|
/// let full_quarter = Matrix4x4::rotation_x(PI / 2.);
|
||||||
|
///
|
||||||
|
/// assert_eq!(
|
||||||
|
/// half_quarter * p,
|
||||||
|
/// Tuple::point(0., 2_f32.sqrt() / 2., 2_f32.sqrt() / 2.)
|
||||||
|
/// );
|
||||||
|
/// assert_eq!(full_quarter * p, Tuple::point(0., 0., 1.),);
|
||||||
|
/// ```
|
||||||
|
pub fn rotation_x(radians: f32) -> Matrix4x4 {
|
||||||
|
let r = radians;
|
||||||
|
Matrix4x4::new(
|
||||||
|
[1., 0., 0., 0.],
|
||||||
|
[0., r.cos(), -r.sin(), 0.],
|
||||||
|
[0., r.sin(), r.cos(), 0.],
|
||||||
|
[0., 0., 0., 1.],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a 4x4 matrix representing a rotation around the y-axis.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::f32::consts::PI;
|
||||||
|
///
|
||||||
|
/// use rtchallenge::{matrices::Matrix4x4, tuples::Tuple};
|
||||||
|
///
|
||||||
|
/// // A scaling matrix applied to a point.
|
||||||
|
/// let p = Tuple::point(0., 0., 1.);
|
||||||
|
/// let half_quarter = Matrix4x4::rotation_y(PI / 4.);
|
||||||
|
/// let full_quarter = Matrix4x4::rotation_y(PI / 2.);
|
||||||
|
///
|
||||||
|
/// assert_eq!(
|
||||||
|
/// half_quarter * p,
|
||||||
|
/// Tuple::point(2_f32.sqrt() / 2., 0., 2_f32.sqrt() / 2.)
|
||||||
|
/// );
|
||||||
|
/// assert_eq!(full_quarter * p, Tuple::point(1., 0., 0.,),);
|
||||||
|
/// ```
|
||||||
|
pub fn rotation_y(radians: f32) -> Matrix4x4 {
|
||||||
|
let r = radians;
|
||||||
|
Matrix4x4::new(
|
||||||
|
[r.cos(), 0., r.sin(), 0.],
|
||||||
|
[0., 1., 0., 0.],
|
||||||
|
[-r.sin(), 0., r.cos(), 0.],
|
||||||
|
[0., 0., 0., 1.],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a 4x4 matrix representing a rotation around the z-axis.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::f32::consts::PI;
|
||||||
|
///
|
||||||
|
/// use rtchallenge::{matrices::Matrix4x4, tuples::Tuple};
|
||||||
|
///
|
||||||
|
/// // A scaling matrix applied to a point.
|
||||||
|
/// let p = Tuple::point(0., 1., 0.);
|
||||||
|
/// let half_quarter = Matrix4x4::rotation_z(PI / 4.);
|
||||||
|
/// let full_quarter = Matrix4x4::rotation_z(PI / 2.);
|
||||||
|
///
|
||||||
|
/// assert_eq!(
|
||||||
|
/// half_quarter * p,
|
||||||
|
/// Tuple::point(-2_f32.sqrt() / 2., 2_f32.sqrt() / 2., 0.)
|
||||||
|
/// );
|
||||||
|
/// assert_eq!(full_quarter * p, Tuple::point(-1., 0., 0.,),);
|
||||||
|
/// ```
|
||||||
|
pub fn rotation_z(radians: f32) -> Matrix4x4 {
|
||||||
|
let r = radians;
|
||||||
|
Matrix4x4::new(
|
||||||
|
[r.cos(), -r.sin(), 0., 0.],
|
||||||
|
[r.sin(), r.cos(), 0., 0.],
|
||||||
|
[0., 0., 1., 0.],
|
||||||
|
[0., 0., 0., 1.],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// Transpose self, returning a new matrix that has been reflected across the diagonal.
|
/// Transpose self, returning a new matrix that has been reflected across the diagonal.
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
@ -453,7 +600,6 @@ impl Matrix4x4 {
|
|||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```
|
/// ```
|
||||||
/// use float_cmp::approx_eq;
|
|
||||||
/// use rtchallenge::matrices::Matrix4x4;
|
/// use rtchallenge::matrices::Matrix4x4;
|
||||||
///
|
///
|
||||||
/// let a = Matrix4x4::new(
|
/// let a = Matrix4x4::new(
|
||||||
@ -469,55 +615,49 @@ impl Matrix4x4 {
|
|||||||
/// assert_eq!(b[(3, 2)], -160. / 532.);
|
/// assert_eq!(b[(3, 2)], -160. / 532.);
|
||||||
/// assert_eq!(a.cofactor(3, 2), 105.);
|
/// assert_eq!(a.cofactor(3, 2), 105.);
|
||||||
/// assert_eq!(b[(2, 3)], 105. / 532.);
|
/// assert_eq!(b[(2, 3)], 105. / 532.);
|
||||||
/// assert!(approx_eq!(
|
/// assert_eq!(
|
||||||
/// &Matrix4x4,
|
/// b,
|
||||||
/// &b,
|
/// Matrix4x4::new(
|
||||||
/// &Matrix4x4::new(
|
/// [0.21804512, 0.45112783, 0.24060151, -0.04511278],
|
||||||
/// [0.21805, 0.45113, 0.24060, -0.04511],
|
/// [-0.8082707, -1.456767, -0.44360903, 0.5206767],
|
||||||
/// [-0.80827, -1.45677, -0.44361, 0.52068],
|
/// [-0.078947365, -0.2236842, -0.05263158, 0.19736843],
|
||||||
/// [-0.07895, -0.22368, -0.05263, 0.19737],
|
/// [-0.52255636, -0.81390977, -0.30075186, 0.30639097]
|
||||||
/// [-0.52256, -0.81391, -0.30075, 0.30639],
|
/// )
|
||||||
/// ),
|
/// );
|
||||||
/// epsilon = 0.0001
|
|
||||||
/// ));
|
|
||||||
///
|
///
|
||||||
/// // Second test case
|
/// // Second test case
|
||||||
/// assert!(approx_eq!(
|
/// assert_eq!(
|
||||||
/// &Matrix4x4,
|
/// Matrix4x4::new(
|
||||||
/// &Matrix4x4::new(
|
|
||||||
/// [8., -5., 9., 2.],
|
/// [8., -5., 9., 2.],
|
||||||
/// [7., 5., 6., 1.],
|
/// [7., 5., 6., 1.],
|
||||||
/// [-6., 0., 9., 6.],
|
/// [-6., 0., 9., 6.],
|
||||||
/// [-3., 0., -9., -4.],
|
/// [-3., 0., -9., -4.],
|
||||||
/// )
|
/// )
|
||||||
/// .inverse(),
|
/// .inverse(),
|
||||||
/// &Matrix4x4::new(
|
/// Matrix4x4::new(
|
||||||
/// [-0.15385, -0.15385, -0.28205, -0.53846],
|
/// [-0.15384616, -0.15384616, -0.2820513, -0.53846157],
|
||||||
/// [-0.07692, 0.12308, 0.02564, 0.03077],
|
/// [-0.07692308, 0.12307692, 0.025641026, 0.03076923],
|
||||||
/// [0.35897, 0.35897, 0.43590, 0.92308],
|
/// [0.35897437, 0.35897437, 0.43589744, 0.9230769],
|
||||||
/// [-0.69231, -0.69241, -0.76923, -1.92308],
|
/// [-0.6923077, -0.6923077, -0.7692308, -1.9230769]
|
||||||
/// ),
|
/// ),
|
||||||
/// epsilon = 0.0005
|
/// );
|
||||||
/// ));
|
|
||||||
///
|
///
|
||||||
/// // Third test case
|
/// // Third test case
|
||||||
/// assert!(approx_eq!(
|
/// assert_eq!(
|
||||||
/// &Matrix4x4,
|
/// Matrix4x4::new(
|
||||||
/// &Matrix4x4::new(
|
|
||||||
/// [9., 3., 0., 9.],
|
/// [9., 3., 0., 9.],
|
||||||
/// [-5., -2., -6., -3.],
|
/// [-5., -2., -6., -3.],
|
||||||
/// [-4., 9., 6., 4.],
|
/// [-4., 9., 6., 4.],
|
||||||
/// [-7., 6., 6., 2.],
|
/// [-7., 6., 6., 2.],
|
||||||
/// )
|
/// )
|
||||||
/// .inverse(),
|
/// .inverse(),
|
||||||
/// &Matrix4x4::new(
|
/// Matrix4x4::new(
|
||||||
/// [-0.04074, -0.07778, 0.14444, -0.22222],
|
/// [-0.04074074, -0.07777778, 0.14444445, -0.22222222],
|
||||||
/// [-0.07778, 0.03333, 0.36667, -0.33333],
|
/// [-0.07777778, 0.033333335, 0.36666667, -0.33333334],
|
||||||
/// [-0.02901, -0.14630, -0.10926, 0.12963],
|
/// [-0.029012345, -0.14629629, -0.10925926, 0.12962963],
|
||||||
/// [0.17778, 0.06667, -0.26667, 0.33333],
|
/// [0.17777778, 0.06666667, -0.26666668, 0.33333334]
|
||||||
/// ),
|
/// ),
|
||||||
/// epsilon = 0.0001
|
/// );
|
||||||
/// ));
|
|
||||||
///
|
///
|
||||||
/// let a = Matrix4x4::new(
|
/// let a = Matrix4x4::new(
|
||||||
/// [3., -9., 7., 3.],
|
/// [3., -9., 7., 3.],
|
||||||
@ -532,12 +672,7 @@ impl Matrix4x4 {
|
|||||||
/// [6., -2., 0., 5.],
|
/// [6., -2., 0., 5.],
|
||||||
/// );
|
/// );
|
||||||
/// let c = a * b;
|
/// let c = a * b;
|
||||||
/// assert!(approx_eq!(
|
/// assert_eq!(c * b.inverse(), a);
|
||||||
/// &Matrix4x4,
|
|
||||||
/// &(c * b.inverse()),
|
|
||||||
/// &a,
|
|
||||||
/// epsilon = 0.0001
|
|
||||||
/// ));
|
|
||||||
/// ```
|
/// ```
|
||||||
pub fn inverse(&self) -> Matrix4x4 {
|
pub fn inverse(&self) -> Matrix4x4 {
|
||||||
let m = self;
|
let m = self;
|
||||||
@ -642,7 +777,7 @@ impl PartialEq for Matrix4x4 {
|
|||||||
for i in 0..4 {
|
for i in 0..4 {
|
||||||
for j in 0..4 {
|
for j in 0..4 {
|
||||||
let d = (l[i][j] - r[i][j]).abs();
|
let d = (l[i][j] - r[i][j]).abs();
|
||||||
if d > f32::EPSILON {
|
if d > EPSILON {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use std::ops::{Add, Div, Mul, Neg, Sub};
|
use std::ops::{Add, Div, Mul, Neg, Sub};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct Tuple {
|
pub struct Tuple {
|
||||||
pub x: f32,
|
pub x: f32,
|
||||||
pub y: f32,
|
pub y: f32,
|
||||||
@ -114,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 {
|
pub fn dot(a: Tuple, b: Tuple) -> f32 {
|
||||||
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
|
||||||
}
|
}
|
||||||
@ -213,8 +221,6 @@ impl Sub for Color {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use float_cmp::approx_eq;
|
|
||||||
|
|
||||||
use super::{cross, dot, Color, Tuple};
|
use super::{cross, dot, Color, Tuple};
|
||||||
#[test]
|
#[test]
|
||||||
fn is_point() {
|
fn is_point() {
|
||||||
@ -319,12 +325,8 @@ mod tests {
|
|||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn vector_normalize_magnitude() {
|
fn vector_normalize_magnitude() {
|
||||||
assert!(approx_eq!(
|
let len = Tuple::vector(1., 2., 3.).normalize().magnitude();
|
||||||
f32,
|
assert!((1. - len).abs() < f32::EPSILON);
|
||||||
1.,
|
|
||||||
Tuple::vector(1., 2., 3.).normalize().magnitude(),
|
|
||||||
ulps = 1
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn dot_two_tuples() {
|
fn dot_two_tuples() {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user