From 334e2ef3ea5fe0ab157ec83de3711f964f0b3e48 Mon Sep 17 00:00:00 2001 From: Jon Janzen Date: Sat, 23 Jan 2021 20:13:34 -0700 Subject: [PATCH] create structs lib, mimics tuple lib, but implements Tuple. This allows for operator overloading. It will make it significantly easier to write code for Tuple objects. --- structs/Cargo.lock | 32 +++++ structs/Cargo.toml | 10 ++ structs/src/lib.rs | 297 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 339 insertions(+) create mode 100644 structs/Cargo.lock create mode 100644 structs/Cargo.toml create mode 100644 structs/src/lib.rs diff --git a/structs/Cargo.lock b/structs/Cargo.lock new file mode 100644 index 0000000..447c5ca --- /dev/null +++ b/structs/Cargo.lock @@ -0,0 +1,32 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "approx" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f2a05fd1bd10b2527e20a2cd32d8873d115b8b39fe219ee25f42a8aca6ba278" +dependencies = [ + "num-traits", +] + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + +[[package]] +name = "structs" +version = "0.1.0" +dependencies = [ + "approx", +] diff --git a/structs/Cargo.toml b/structs/Cargo.toml new file mode 100644 index 0000000..13fc612 --- /dev/null +++ b/structs/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "structs" +version = "0.1.0" +authors = ["Jon Janzen "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +approx = "0.4" diff --git a/structs/src/lib.rs b/structs/src/lib.rs new file mode 100644 index 0000000..cc9cbe1 --- /dev/null +++ b/structs/src/lib.rs @@ -0,0 +1,297 @@ +#[macro_use] +extern crate approx; + +use std::ops; + +#[derive(Debug)] +struct Tuple { + x: f32, + y: f32, + z: f32, + w: f32, +} + +impl Tuple { + fn new(x: f32, y: f32, z: f32, w: f32) -> Tuple { + Tuple { + x, + y, + z, + w, + } + } + + + fn point(x: f32, y: f32, z: f32) -> Tuple { + Tuple { + x, + y, + z, + w: 1.0, + } + } + + fn vector(x: f32, y: f32, z: f32) -> Tuple { + Tuple { + x, + y, + z, + w: 0.0, + } + } +} + +impl Tuple { + fn x(&self) -> f32 { + self.x + } + + fn y(&self) -> f32 { + self.y + } + + fn z(&self) -> f32 { + self.z + } + + fn is_point(&self) -> bool { + self.w == 1.0 + } + + fn is_vector(&self) -> bool { + self.w == 0.0 + } + +} + +impl PartialEq for Tuple { + fn eq(&self, _rhs: &Self) -> bool { + relative_eq!(self.x, _rhs.x) + && relative_eq!(self.y, _rhs.y) + && relative_eq!(self.z, _rhs.z) + && relative_eq!(self.w, _rhs.w) + } +} + +impl ops::Add for Tuple { + type Output = Tuple; + + fn add(self, _rhs: Tuple) -> Tuple { + Tuple::new( + self.x + _rhs.x, + self.y + _rhs.y, + self.z + _rhs.z, + self.w + _rhs.w, + ) + } +} + +impl ops::Sub for Tuple { + type Output = Tuple; + + fn sub(self, _rhs: Tuple) -> Tuple { + Tuple::new( + self.x - _rhs.x, + self.y - _rhs.y, + self.z - _rhs.z, + self.w - _rhs.w, + ) + } +} + +impl ops::Neg for Tuple { + type Output = Tuple; + + fn neg(self) -> Tuple { + Tuple::new( + -self.x, + -self.y, + -self.z, + -self.w, + ) + } +} + +impl ops::Mul for Tuple { + type Output = Tuple; + + fn mul(self, _rhs: f32) -> Tuple { + Tuple::new( + self.x * _rhs, + self.y * _rhs, + self.z * _rhs, + self.w * _rhs, + ) + } +} + +impl ops::Mul for f32 { + type Output = Tuple; + + fn mul(self, _rhs: Tuple) -> Tuple { + Tuple::new( + _rhs.x * self, + _rhs.y * self, + _rhs.z * self, + _rhs.w * self, + ) + } +} + +impl ops::Div for Tuple { + type Output = Tuple; + + fn div(self, _rhs: f32) -> Tuple { + Tuple::new( + self.x / _rhs, + self.y / _rhs, + self.z / _rhs, + self.w / _rhs, + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn get_point() { + let tuple = Tuple::new(4.3, -4.2, 3.1, 1.0); + + assert_relative_eq!( 4.3, tuple.x); + assert_relative_eq!(-4.2, tuple.y()); + assert_relative_eq!( 3.1, tuple.z()); + assert_eq!(true, tuple.is_point()); + assert_eq!(false, tuple.is_vector()); + } + + #[test] + fn create_point() { + let tuple = Tuple::point(4.3, -4.2, 3.1); + assert_eq!(true, tuple.is_point()); + } + + #[test] + fn get_vector() { + let tuple = Tuple::new(4.3, -4.2, 3.1, 0.0); + + assert_relative_eq!( 4.3, tuple.x()); + assert_relative_eq!(-4.2, tuple.y()); + assert_relative_eq!( 3.1, tuple.z()); + assert_eq!(false, tuple.is_point()); + assert_eq!(true, tuple.is_vector()); + } + + #[test] + fn create_vector() { + let vector = Tuple::vector(4.0, -4.0, 3.0); + assert_eq!(true, vector.is_vector()); + } + + #[test] + fn tuples_equal() { + let lhs = Tuple::point(1.0, 2.0, 3.0); + let rhs = Tuple::point(1.0, 2.0, 3.0); + assert_eq!(lhs, rhs); + } + + #[test] + fn tuples_relative_equal() { + let lhs = Tuple::point(1.0000001, 2.0, 3.0); + let rhs = Tuple::point(1.0, 2.0, 3.0); + assert_eq!(lhs, rhs); + } + + #[test] + fn tuples_not_equal() { + let lhs = Tuple::point(1.0, 2.0, 3.0); + let rhs = Tuple::vector(1.0, 2.0, 3.0); + assert_ne!(lhs, rhs); + } + + #[test] + fn add_two_tuples() { + let a1 = Tuple::point(3.0, -2.0, 5.0); + let a2 = Tuple::vector(-2.0, 3.0, 1.0); + + let result = Tuple::point(1.0, 1.0, 6.0); + assert_eq!(result, a1 + a2); + } + + #[test] + fn subtract_two_points() { + let a1 = Tuple::point(3.0, 2.0, 1.0); + let a2 = Tuple::point(5.0, 6.0, 7.0); + + let result = Tuple::vector(-2.0, -4.0, -6.0); + assert_eq!(result, a1 - a2); + } + + #[test] + fn subract_vector_from_point() { + let a1 = Tuple::point(3.0, 2.0, 1.0); + let a2 = Tuple::vector(5.0, 6.0, 7.0); + + let result = Tuple::point(-2.0, -4.0, -6.0); + assert_eq!(result, a1 - a2); + } + + #[test] + fn subract_vector_from_vector() { + let a1 = Tuple::vector(3.0, 2.0, 1.0); + let a2 = Tuple::vector(5.0, 6.0, 7.0); + + let result = Tuple::vector(-2.0, -4.0, -6.0); + assert_eq!(result, a1 - a2); + } + + #[test] + fn subtract_vector_from_zero_vector() { + let a1 = Tuple::vector(0.0, 0.0, 0.0); + let a2 = Tuple::vector(5.0, 6.0, 7.0); + + let result = Tuple::vector(-5.0, -6.0, -7.0); + assert_eq!(result, a1 - a2); + } + + #[test] + fn negate_tuple() { + let a = Tuple::new(1.0, -2.0, 3.0, -4.0); + let result = Tuple::new(-1.0, 2.0, -3.0, 4.0); + + assert_eq!(result, -a); + } + + #[test] + fn multiply_tuple_by_scalar() { + let a = Tuple::new(1.0, -2.0, 3.0, -4.0); + let result = Tuple::new(3.5, -7.0, 10.5, -14.0); + + assert_eq!(result, a * 3.5); + } + + #[test] + fn multiply_scalar_by_tuple() { + let a = Tuple::new(1.0, -2.0, 3.0, -4.0); + let result = Tuple::new(3.5, -7.0, 10.5, -14.0); + + assert_eq!(result, 3.5 * a); + } + + #[test] + fn multiply_tuple_by_fraction() { + let a = Tuple::new(1.0, -2.0, 3.0, -4.0); + let result = Tuple::new(0.5, -1.0, 1.5, -2.0); + + assert_eq!(result, a * 0.5); + } + + #[test] + fn divide_tuple() { + let a = Tuple::new(1.0, -2.0, 3.0, -4.0); + let result = Tuple::new(0.5, -1.0, 1.5, -2.0); + + assert_eq!(result, a / 2.0); + } +}