Extract the types into separate files
Not for any reason other than clarity. The number of operations that are declared for each type is making it difficult to find operations and difficult to keep the order consistent.
This commit is contained in:
parent
39c947b461
commit
2a38ca38e1
|
@ -33,5 +33,11 @@ fn main() {
|
||||||
p = tick(&e, &p);
|
p = tick(&e, &p);
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("distance travelled: [{}] {} {} {}", (p.position - start.position).magnitude(), p.position.x, p.position.y, p.position.z);
|
println!(
|
||||||
|
"distance travelled: [{}] {} {} {}",
|
||||||
|
(p.position - start.position).magnitude(),
|
||||||
|
p.position.x,
|
||||||
|
p.position.y,
|
||||||
|
p.position.z
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,2 +1 @@
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
|
||||||
|
|
|
@ -1,407 +0,0 @@
|
||||||
const EPSILON: f64 = 0.00001;
|
|
||||||
|
|
||||||
fn eq_f64(l: f64, r: f64) -> bool {
|
|
||||||
(l - r).abs() < EPSILON
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub struct Tuple {
|
|
||||||
pub x: f64,
|
|
||||||
pub y: f64,
|
|
||||||
pub z: f64,
|
|
||||||
pub w: f64, // Used for very low-level math. w = 1.0 indicates a point, w = 0.0 indicates a vector.
|
|
||||||
// Theoretically the type system should make this redundant, so operations on points
|
|
||||||
// and vectors can always assert the correct value.
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Tuple {
|
|
||||||
fn dot(&self, r: &Tuple) -> f64 {
|
|
||||||
self.x * r.x + self.y * r.y + self.z * r.z + self.w * r.w
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq for Tuple {
|
|
||||||
fn eq(&self, r: &Tuple) -> bool {
|
|
||||||
eq_f64(self.x, r.x) && eq_f64(self.y, r.y) && eq_f64(self.z, r.z) && eq_f64(self.w, r.w)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::ops::Add for Tuple {
|
|
||||||
type Output = Tuple;
|
|
||||||
fn add(self, r: Tuple) -> Self::Output {
|
|
||||||
return Self::Output {
|
|
||||||
x: self.x + r.x,
|
|
||||||
y: self.y + r.y,
|
|
||||||
z: self.z + r.z,
|
|
||||||
w: self.w + r.w,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::ops::Sub for Tuple {
|
|
||||||
type Output = Tuple;
|
|
||||||
fn sub(self, r: Tuple) -> Self::Output {
|
|
||||||
return Self::Output {
|
|
||||||
x: self.x - r.x,
|
|
||||||
y: self.y - r.y,
|
|
||||||
z: self.z - r.z,
|
|
||||||
w: self.w - r.w,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::ops::Neg for Tuple {
|
|
||||||
type Output = Tuple;
|
|
||||||
fn neg(self) -> Self::Output {
|
|
||||||
return Self::Output {
|
|
||||||
x: -self.x,
|
|
||||||
y: -self.y,
|
|
||||||
z: -self.z,
|
|
||||||
w: -self.w,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::ops::Mul<f64> for Tuple {
|
|
||||||
type Output = Tuple;
|
|
||||||
fn mul(self, scalar: f64) -> Self::Output {
|
|
||||||
return Self::Output {
|
|
||||||
x: self.x * scalar,
|
|
||||||
y: self.y * scalar,
|
|
||||||
z: self.z * scalar,
|
|
||||||
w: self.w * scalar,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::ops::Div<f64> for Tuple {
|
|
||||||
type Output = Tuple;
|
|
||||||
fn div(self, scalar: f64) -> Self::Output {
|
|
||||||
return Self::Output {
|
|
||||||
x: self.x / scalar,
|
|
||||||
y: self.y / scalar,
|
|
||||||
z: self.z / scalar,
|
|
||||||
w: self.w / scalar,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
|
||||||
pub struct Point(Tuple);
|
|
||||||
|
|
||||||
impl Point {
|
|
||||||
pub fn new(x: f64, y: f64, z: f64) -> Self {
|
|
||||||
Self(Tuple { x, y, z, w: 1.0 })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::ops::Deref for Point {
|
|
||||||
type Target = Tuple;
|
|
||||||
fn deref(&self) -> &Tuple {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Tuple> for Point {
|
|
||||||
fn from(tuple: Tuple) -> Self {
|
|
||||||
assert_eq!(tuple.w, 1.0);
|
|
||||||
Self(tuple)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Point {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new(0., 0., 0.)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::ops::Add<Vector> for Point {
|
|
||||||
type Output = Point;
|
|
||||||
fn add(self, r: Vector) -> Self::Output {
|
|
||||||
Point::from(self.0 + r.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::ops::Sub for Point {
|
|
||||||
type Output = Vector;
|
|
||||||
fn sub(self, r: Point) -> Self::Output {
|
|
||||||
Vector::from(self.0 - r.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::ops::Sub<Vector> for Point {
|
|
||||||
type Output = Point;
|
|
||||||
fn sub(self, r: Vector) -> Self::Output {
|
|
||||||
Point::from(self.0 - r.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::ops::Neg for Point {
|
|
||||||
type Output = Point;
|
|
||||||
fn neg(self) -> Self::Output {
|
|
||||||
let mut t = -self.0;
|
|
||||||
t.w = 1.;
|
|
||||||
Point::from(t)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
|
||||||
pub struct Vector(Tuple);
|
|
||||||
|
|
||||||
impl Vector {
|
|
||||||
pub fn new(x: f64, y: f64, z: f64) -> Self {
|
|
||||||
Self(Tuple { x, y, z, w: 0.0 })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn magnitude(&self) -> f64 {
|
|
||||||
(self.x * self.x + self.y * self.y + self.z * self.z).sqrt()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn normalize(&self) -> Self {
|
|
||||||
let mag = self.magnitude();
|
|
||||||
Self::new(self.x / mag, self.y / mag, self.z / mag)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn dot(&self, r: &Vector) -> f64 {
|
|
||||||
self.0.dot(r)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn cross(&self, r: &Vector) -> Self {
|
|
||||||
let x = self.y * r.z - self.z * r.y;
|
|
||||||
let y = self.z * r.x - self.x * r.z;
|
|
||||||
let z = self.x * r.y - self.y * r.x;
|
|
||||||
Self::new(x, y, z)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::ops::Deref for Vector {
|
|
||||||
type Target = Tuple;
|
|
||||||
fn deref(&self) -> &Tuple {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Vector {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new(0., 0., 0.)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Tuple> for Vector {
|
|
||||||
fn from(tuple: Tuple) -> Self {
|
|
||||||
assert_eq!(tuple.w, 0.0);
|
|
||||||
Self(tuple)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::ops::Add for Vector {
|
|
||||||
type Output = Vector;
|
|
||||||
fn add(self, r: Self) -> Self {
|
|
||||||
Vector::from(self.0 + r.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::ops::Sub for Vector {
|
|
||||||
type Output = Vector;
|
|
||||||
fn sub(self, r: Self) -> Self {
|
|
||||||
Vector::from(self.0 - r.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::ops::Mul<f64> for Vector {
|
|
||||||
type Output = Vector;
|
|
||||||
fn mul(self, r: f64) -> Self {
|
|
||||||
Vector::from(self.0 * r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl std::ops::Neg for Vector {
|
|
||||||
type Output = Vector;
|
|
||||||
fn neg(self) -> Self::Output {
|
|
||||||
let mut t = -self.0;
|
|
||||||
t.w = 0.;
|
|
||||||
Vector::from(t)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn eq_f64_compares_values() {
|
|
||||||
assert!(eq_f64(1.0, 1.0));
|
|
||||||
assert!(eq_f64(0.9994, 0.9994));
|
|
||||||
assert!(eq_f64(0.9999994, 0.9999995));
|
|
||||||
assert!(!eq_f64(0.9995, 0.9994));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn add_two_tuples() {
|
|
||||||
let a = Tuple {
|
|
||||||
x: 3.,
|
|
||||||
y: -2.,
|
|
||||||
z: 5.,
|
|
||||||
w: 1.,
|
|
||||||
};
|
|
||||||
let b = Tuple {
|
|
||||||
x: -2.,
|
|
||||||
y: 3.,
|
|
||||||
z: 1.,
|
|
||||||
w: 0.,
|
|
||||||
};
|
|
||||||
assert_eq!(
|
|
||||||
a + b,
|
|
||||||
Tuple {
|
|
||||||
x: 1.,
|
|
||||||
y: 1.,
|
|
||||||
z: 6.,
|
|
||||||
w: 1.
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn subtracts_two_tuples() {
|
|
||||||
let a = Tuple {
|
|
||||||
x: 3.,
|
|
||||||
y: 2.,
|
|
||||||
z: 1.,
|
|
||||||
w: 1.,
|
|
||||||
};
|
|
||||||
let b = Tuple {
|
|
||||||
x: 5.,
|
|
||||||
y: 6.,
|
|
||||||
z: 7.,
|
|
||||||
w: 1.,
|
|
||||||
};
|
|
||||||
assert_eq!(
|
|
||||||
a - b,
|
|
||||||
Tuple {
|
|
||||||
x: -2.,
|
|
||||||
y: -4.,
|
|
||||||
z: -6.,
|
|
||||||
w: 0.
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn adds_point_and_vector() {
|
|
||||||
let a = Point::new(3., -2., 5.);
|
|
||||||
let b = Vector::new(-2., 3., 1.);
|
|
||||||
assert_eq!(a + b, Point::new(1., 1., 6.,));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn subtracts_two_points() {
|
|
||||||
let a = Point::new(3., 2., 1.);
|
|
||||||
let b = Point::new(5., 6., 7.);
|
|
||||||
assert_eq!(a - b, Vector::new(-2., -4., -6.,));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn subtracts_vector_from_point() {
|
|
||||||
let a = Point::new(3., 2., 1.);
|
|
||||||
let b = Vector::new(5., 6., 7.);
|
|
||||||
assert_eq!(a - b, Point::new(-2., -4., -6.));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn subtracts_two_vectors() {
|
|
||||||
let a = Vector::new(3., 2., 1.);
|
|
||||||
let b = Vector::new(5., 6., 7.);
|
|
||||||
assert_eq!(a - b, Vector::new(-2., -4., -6.));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn it_negates_primitives() {
|
|
||||||
assert_eq!(
|
|
||||||
-Tuple {
|
|
||||||
x: 1.,
|
|
||||||
y: 2.,
|
|
||||||
z: 3.,
|
|
||||||
w: 4.
|
|
||||||
},
|
|
||||||
Tuple {
|
|
||||||
x: -1.,
|
|
||||||
y: -2.,
|
|
||||||
z: -3.,
|
|
||||||
w: -4.
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn multiply_tuple_by_scalar() {
|
|
||||||
assert_eq!(
|
|
||||||
Tuple {
|
|
||||||
x: 1.,
|
|
||||||
y: -2.,
|
|
||||||
z: 3.,
|
|
||||||
w: -4.
|
|
||||||
} * 3.5,
|
|
||||||
Tuple {
|
|
||||||
x: 3.5,
|
|
||||||
y: -7.,
|
|
||||||
z: 10.5,
|
|
||||||
w: -14.
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn divide_tuple_by_scalar() {
|
|
||||||
assert_eq!(
|
|
||||||
Tuple {
|
|
||||||
x: 1.,
|
|
||||||
y: -2.,
|
|
||||||
z: 3.,
|
|
||||||
w: -4.
|
|
||||||
} / 2.,
|
|
||||||
Tuple {
|
|
||||||
x: 0.5,
|
|
||||||
y: -1.,
|
|
||||||
z: 1.5,
|
|
||||||
w: -2.
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn magnitude_of_vector() {
|
|
||||||
assert_eq!(Vector::new(1., 0., 0.).magnitude(), 1.);
|
|
||||||
assert_eq!(Vector::new(0., 1., 0.).magnitude(), 1.);
|
|
||||||
assert_eq!(Vector::new(0., 0., 1.).magnitude(), 1.);
|
|
||||||
assert_eq!(Vector::new(1., 2., 3.).magnitude(), 14_f64.sqrt());
|
|
||||||
assert_eq!(Vector::new(-1., -2., -3.).magnitude(), 14_f64.sqrt());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn normalize_vector() {
|
|
||||||
assert_eq!(Vector::new(4., 0., 0.).normalize(), Vector::new(1., 0., 0.));
|
|
||||||
assert_eq!(
|
|
||||||
Vector::new(1., 2., 3.).normalize(),
|
|
||||||
Vector::new(0.26726, 0.53452, 0.80178)
|
|
||||||
);
|
|
||||||
assert_eq!(Vector::new(1., 2., 3.).normalize().magnitude(), 1.);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn dot_product() {
|
|
||||||
assert_eq!(Vector::new(1., 2., 3.).dot(&Vector::new(2., 3., 4.)), 20.);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn cross_product() {
|
|
||||||
assert_eq!(
|
|
||||||
Vector::new(1., 2., 3.).cross(&Vector::new(2., 3., 4.)),
|
|
||||||
Vector::new(-1., 2., -1.)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
Vector::new(2., 3., 4.).cross(&Vector::new(1., 2., 3.)),
|
|
||||||
Vector::new(1., -2., 1.)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,194 @@
|
||||||
|
mod point;
|
||||||
|
mod tuple;
|
||||||
|
mod vector;
|
||||||
|
|
||||||
|
pub use point::Point;
|
||||||
|
pub use tuple::Tuple;
|
||||||
|
pub use vector::Vector;
|
||||||
|
|
||||||
|
const EPSILON: f64 = 0.00001;
|
||||||
|
|
||||||
|
fn eq_f64(l: f64, r: f64) -> bool {
|
||||||
|
(l - r).abs() < EPSILON
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn eq_f64_compares_values() {
|
||||||
|
assert!(eq_f64(1.0, 1.0));
|
||||||
|
assert!(eq_f64(0.9994, 0.9994));
|
||||||
|
assert!(eq_f64(0.9999994, 0.9999995));
|
||||||
|
assert!(!eq_f64(0.9995, 0.9994));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_two_tuples() {
|
||||||
|
let a = Tuple {
|
||||||
|
x: 3.,
|
||||||
|
y: -2.,
|
||||||
|
z: 5.,
|
||||||
|
w: 1.,
|
||||||
|
};
|
||||||
|
let b = Tuple {
|
||||||
|
x: -2.,
|
||||||
|
y: 3.,
|
||||||
|
z: 1.,
|
||||||
|
w: 0.,
|
||||||
|
};
|
||||||
|
assert_eq!(
|
||||||
|
a + b,
|
||||||
|
Tuple {
|
||||||
|
x: 1.,
|
||||||
|
y: 1.,
|
||||||
|
z: 6.,
|
||||||
|
w: 1.
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn subtracts_two_tuples() {
|
||||||
|
let a = Tuple {
|
||||||
|
x: 3.,
|
||||||
|
y: 2.,
|
||||||
|
z: 1.,
|
||||||
|
w: 1.,
|
||||||
|
};
|
||||||
|
let b = Tuple {
|
||||||
|
x: 5.,
|
||||||
|
y: 6.,
|
||||||
|
z: 7.,
|
||||||
|
w: 1.,
|
||||||
|
};
|
||||||
|
assert_eq!(
|
||||||
|
a - b,
|
||||||
|
Tuple {
|
||||||
|
x: -2.,
|
||||||
|
y: -4.,
|
||||||
|
z: -6.,
|
||||||
|
w: 0.
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn adds_point_and_vector() {
|
||||||
|
let a = Point::new(3., -2., 5.);
|
||||||
|
let b = Vector::new(-2., 3., 1.);
|
||||||
|
assert_eq!(a + b, Point::new(1., 1., 6.,));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn subtracts_two_points() {
|
||||||
|
let a = Point::new(3., 2., 1.);
|
||||||
|
let b = Point::new(5., 6., 7.);
|
||||||
|
assert_eq!(a - b, Vector::new(-2., -4., -6.,));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn subtracts_vector_from_point() {
|
||||||
|
let a = Point::new(3., 2., 1.);
|
||||||
|
let b = Vector::new(5., 6., 7.);
|
||||||
|
assert_eq!(a - b, Point::new(-2., -4., -6.));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn subtracts_two_vectors() {
|
||||||
|
let a = Vector::new(3., 2., 1.);
|
||||||
|
let b = Vector::new(5., 6., 7.);
|
||||||
|
assert_eq!(a - b, Vector::new(-2., -4., -6.));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn it_negates_primitives() {
|
||||||
|
assert_eq!(
|
||||||
|
-Tuple {
|
||||||
|
x: 1.,
|
||||||
|
y: 2.,
|
||||||
|
z: 3.,
|
||||||
|
w: 4.
|
||||||
|
},
|
||||||
|
Tuple {
|
||||||
|
x: -1.,
|
||||||
|
y: -2.,
|
||||||
|
z: -3.,
|
||||||
|
w: -4.
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn multiply_tuple_by_scalar() {
|
||||||
|
assert_eq!(
|
||||||
|
Tuple {
|
||||||
|
x: 1.,
|
||||||
|
y: -2.,
|
||||||
|
z: 3.,
|
||||||
|
w: -4.
|
||||||
|
} * 3.5,
|
||||||
|
Tuple {
|
||||||
|
x: 3.5,
|
||||||
|
y: -7.,
|
||||||
|
z: 10.5,
|
||||||
|
w: -14.
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn divide_tuple_by_scalar() {
|
||||||
|
assert_eq!(
|
||||||
|
Tuple {
|
||||||
|
x: 1.,
|
||||||
|
y: -2.,
|
||||||
|
z: 3.,
|
||||||
|
w: -4.
|
||||||
|
} / 2.,
|
||||||
|
Tuple {
|
||||||
|
x: 0.5,
|
||||||
|
y: -1.,
|
||||||
|
z: 1.5,
|
||||||
|
w: -2.
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn magnitude_of_vector() {
|
||||||
|
assert_eq!(Vector::new(1., 0., 0.).magnitude(), 1.);
|
||||||
|
assert_eq!(Vector::new(0., 1., 0.).magnitude(), 1.);
|
||||||
|
assert_eq!(Vector::new(0., 0., 1.).magnitude(), 1.);
|
||||||
|
assert_eq!(Vector::new(1., 2., 3.).magnitude(), 14_f64.sqrt());
|
||||||
|
assert_eq!(Vector::new(-1., -2., -3.).magnitude(), 14_f64.sqrt());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn normalize_vector() {
|
||||||
|
assert_eq!(Vector::new(4., 0., 0.).normalize(), Vector::new(1., 0., 0.));
|
||||||
|
assert_eq!(
|
||||||
|
Vector::new(1., 2., 3.).normalize(),
|
||||||
|
Vector::new(0.26726, 0.53452, 0.80178)
|
||||||
|
);
|
||||||
|
assert_eq!(Vector::new(1., 2., 3.).normalize().magnitude(), 1.);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn dot_product() {
|
||||||
|
assert_eq!(Vector::new(1., 2., 3.).dot(&Vector::new(2., 3., 4.)), 20.);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cross_product() {
|
||||||
|
assert_eq!(
|
||||||
|
Vector::new(1., 2., 3.).cross(&Vector::new(2., 3., 4.)),
|
||||||
|
Vector::new(-1., 2., -1.)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Vector::new(2., 3., 4.).cross(&Vector::new(1., 2., 3.)),
|
||||||
|
Vector::new(1., -2., 1.)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
use crate::types::{Tuple, Vector};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub struct Point(Tuple);
|
||||||
|
|
||||||
|
impl Point {
|
||||||
|
pub fn new(x: f64, y: f64, z: f64) -> Self {
|
||||||
|
Self(Tuple { x, y, z, w: 1.0 })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Point {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new(0., 0., 0.)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Tuple> for Point {
|
||||||
|
fn from(tuple: Tuple) -> Self {
|
||||||
|
assert_eq!(tuple.w, 1.0);
|
||||||
|
Self(tuple)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Deref for Point {
|
||||||
|
type Target = Tuple;
|
||||||
|
fn deref(&self) -> &Tuple {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Add<Vector> for Point {
|
||||||
|
type Output = Point;
|
||||||
|
fn add(self, r: Vector) -> Self::Output {
|
||||||
|
Point::from(self.0 + *r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Sub for Point {
|
||||||
|
type Output = Vector;
|
||||||
|
fn sub(self, r: Point) -> Self::Output {
|
||||||
|
Vector::from(self.0 - r.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Sub<Vector> for Point {
|
||||||
|
type Output = Point;
|
||||||
|
fn sub(self, r: Vector) -> Self::Output {
|
||||||
|
Point::from(self.0 - *r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Neg for Point {
|
||||||
|
type Output = Point;
|
||||||
|
fn neg(self) -> Self::Output {
|
||||||
|
let mut t = -self.0;
|
||||||
|
t.w = 1.;
|
||||||
|
Point::from(t)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,83 @@
|
||||||
|
use crate::types::eq_f64;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct Tuple {
|
||||||
|
pub x: f64,
|
||||||
|
pub y: f64,
|
||||||
|
pub z: f64,
|
||||||
|
pub w: f64, // Used for very low-level math. w = 1.0 indicates a point, w = 0.0 indicates a vector.
|
||||||
|
// Theoretically the type system should make this redundant, so operations on points
|
||||||
|
// and vectors can always assert the correct value.
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Tuple {
|
||||||
|
pub fn dot(&self, r: &Tuple) -> f64 {
|
||||||
|
self.x * r.x + self.y * r.y + self.z * r.z + self.w * r.w
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Tuple {
|
||||||
|
fn eq(&self, r: &Tuple) -> bool {
|
||||||
|
eq_f64(self.x, r.x) && eq_f64(self.y, r.y) && eq_f64(self.z, r.z) && eq_f64(self.w, r.w)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Add for Tuple {
|
||||||
|
type Output = Tuple;
|
||||||
|
fn add(self, r: Tuple) -> Self::Output {
|
||||||
|
return Self::Output {
|
||||||
|
x: self.x + r.x,
|
||||||
|
y: self.y + r.y,
|
||||||
|
z: self.z + r.z,
|
||||||
|
w: self.w + r.w,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Sub for Tuple {
|
||||||
|
type Output = Tuple;
|
||||||
|
fn sub(self, r: Tuple) -> Self::Output {
|
||||||
|
return Self::Output {
|
||||||
|
x: self.x - r.x,
|
||||||
|
y: self.y - r.y,
|
||||||
|
z: self.z - r.z,
|
||||||
|
w: self.w - r.w,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Neg for Tuple {
|
||||||
|
type Output = Tuple;
|
||||||
|
fn neg(self) -> Self::Output {
|
||||||
|
return Self::Output {
|
||||||
|
x: -self.x,
|
||||||
|
y: -self.y,
|
||||||
|
z: -self.z,
|
||||||
|
w: -self.w,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Mul<f64> for Tuple {
|
||||||
|
type Output = Tuple;
|
||||||
|
fn mul(self, scalar: f64) -> Self::Output {
|
||||||
|
return Self::Output {
|
||||||
|
x: self.x * scalar,
|
||||||
|
y: self.y * scalar,
|
||||||
|
z: self.z * scalar,
|
||||||
|
w: self.w * scalar,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Div<f64> for Tuple {
|
||||||
|
type Output = Tuple;
|
||||||
|
fn div(self, scalar: f64) -> Self::Output {
|
||||||
|
return Self::Output {
|
||||||
|
x: self.x / scalar,
|
||||||
|
y: self.y / scalar,
|
||||||
|
z: self.z / scalar,
|
||||||
|
w: self.w / scalar,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
use crate::types::Tuple;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub struct Vector(Tuple);
|
||||||
|
|
||||||
|
impl Vector {
|
||||||
|
pub fn new(x: f64, y: f64, z: f64) -> Self {
|
||||||
|
Self(Tuple { x, y, z, w: 0.0 })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn magnitude(&self) -> f64 {
|
||||||
|
(self.x * self.x + self.y * self.y + self.z * self.z).sqrt()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn normalize(&self) -> Self {
|
||||||
|
let mag = self.magnitude();
|
||||||
|
Self::new(self.x / mag, self.y / mag, self.z / mag)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dot(&self, r: &Vector) -> f64 {
|
||||||
|
self.0.dot(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cross(&self, r: &Vector) -> Self {
|
||||||
|
let x = self.y * r.z - self.z * r.y;
|
||||||
|
let y = self.z * r.x - self.x * r.z;
|
||||||
|
let z = self.x * r.y - self.y * r.x;
|
||||||
|
Self::new(x, y, z)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Vector {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new(0., 0., 0.)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Tuple> for Vector {
|
||||||
|
fn from(tuple: Tuple) -> Self {
|
||||||
|
assert_eq!(tuple.w, 0.0);
|
||||||
|
Self(tuple)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Deref for Vector {
|
||||||
|
type Target = Tuple;
|
||||||
|
fn deref(&self) -> &Tuple {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Add for Vector {
|
||||||
|
type Output = Vector;
|
||||||
|
fn add(self, r: Self) -> Self {
|
||||||
|
Vector::from(self.0 + r.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Sub for Vector {
|
||||||
|
type Output = Vector;
|
||||||
|
fn sub(self, r: Self) -> Self {
|
||||||
|
Vector::from(self.0 - r.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Neg for Vector {
|
||||||
|
type Output = Vector;
|
||||||
|
fn neg(self) -> Self::Output {
|
||||||
|
let mut t = -self.0;
|
||||||
|
t.w = 0.;
|
||||||
|
Vector::from(t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Mul<f64> for Vector {
|
||||||
|
type Output = Vector;
|
||||||
|
fn mul(self, r: f64) -> Self {
|
||||||
|
Vector::from(self.0 * r)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue