diff --git a/.gitignore b/.gitignore index eb5a316..79c6133 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ target +rusty-tags.vi diff --git a/structs/src/lib.rs b/structs/src/lib.rs index cc9cbe1..692dd67 100644 --- a/structs/src/lib.rs +++ b/structs/src/lib.rs @@ -62,6 +62,39 @@ impl Tuple { self.w == 0.0 } + fn magnitude(&self) -> f32 { + ( + (self.x * self.x) + + (self.y * self.y) + + (self.z * self.z) + + (self.w * self.w) + ).sqrt() + } + + fn normalize(&self) -> Tuple { + let m = self.magnitude(); + Tuple::new( + self.x / m, + self.y / m, + self.z / m, + self.w / m, + ) + } + + fn dot(&self, rhs: &Tuple) -> f32 { + self.x * rhs.x + + self.y * rhs.y + + self.z * rhs.z + + self.w * rhs.w + } + + fn cross(&self, rhs: &Tuple) -> Tuple { + Tuple::vector( + self.y * rhs.z - self.z * rhs.y, + self.z * rhs.x - self.x * rhs.z, + self.x * rhs.y - self.y * rhs.x + ) + } } impl PartialEq for Tuple { @@ -294,4 +327,84 @@ mod tests { assert_eq!(result, a / 2.0); } + + #[test] + fn magnitude_x() { + let v = Tuple::vector(1.0, 0.0, 0.0); + assert_eq!(1.0, v.magnitude()); + } + + #[test] + fn magnitude_y() { + let v = Tuple::vector(0.0, 1.0, 0.0); + assert_eq!(1.0, v.magnitude()); + } + + #[test] + fn magnitude_z() { + let v = Tuple::vector(0.0, 0.0, 1.0); + assert_eq!(1.0, v.magnitude()); + } + + #[test] + fn magnitude_123() { + let v = Tuple::vector(1.0, 2.0, 3.0); + assert_eq!(14.0_f32.sqrt(), v.magnitude()); + } + + #[test] + fn magnitude_123_neg() { + let v = Tuple::vector(-1.0, -2.0, -3.0); + assert_eq!(14.0_f32.sqrt(), v.magnitude()); + } + + #[test] + fn normalize_x() { + let v = Tuple::vector(4.0, 0.0, 0.0); + let norm = v.normalize(); + + let result = Tuple::vector(1.0, 0.0, 0.0); + assert_eq!(result, norm); + + } + + #[test] + fn normalize_123() { + let v = Tuple::vector(1.0, 2.0, 3.0); + let norm = v.normalize(); + + + let sqrt_of_14 = 14.0_f32.sqrt(); + assert_relative_eq!(norm.x, 1.0 / sqrt_of_14); + assert_relative_eq!(norm.y, 2.0 / sqrt_of_14); + assert_relative_eq!(norm.z, 3.0 / sqrt_of_14); + } + + #[test] + fn normalize_magnitude() { + let v = Tuple::vector(1.0, 2.0, 3.0); + let norm = v.normalize(); + let m = norm.magnitude(); + + assert_relative_eq!(1.0, m); + } + + #[test] + fn dot_product() { + let a = Tuple::vector(1.0, 2.0, 3.0); + let b = Tuple::vector(2.0, 3.0, 4.0); + + assert_eq!(20.0, a.dot(&b)); + } + + #[test] + fn cross_product() { + let a = Tuple::vector(1.0, 2.0, 3.0); + let b = Tuple::vector(2.0, 3.0, 4.0); + + let a_cross_b = Tuple::vector(-1.0, 2.0, -1.0); + assert_eq!(a_cross_b, a.cross(&b)); + let b_cross_a = Tuple::vector(1.0, -2.0, 1.0); + assert_eq!(b_cross_a, b.cross(&a)); + } } diff --git a/tuples/src/lib.rs b/tuples/src/lib.rs index 74115ae..1dea01a 100644 --- a/tuples/src/lib.rs +++ b/tuples/src/lib.rs @@ -9,7 +9,6 @@ fn point(x: f32, y: f32, z: f32) -> PointVector { (x, y, z, 1.0) } - fn vector(x: f32, y: f32, z: f32) -> PointVector { (x, y, z, 0.0) } @@ -42,30 +41,15 @@ fn tuple_equals(lhs: PointVector, rhs: PointVector) -> bool { } fn tuple_add(lhs: PointVector, rhs: PointVector) -> PointVector { - ( - lhs.0 + rhs.0, - lhs.1 + rhs.1, - lhs.2 + rhs.2, - lhs.3 + rhs.3 - ) + (lhs.0 + rhs.0, lhs.1 + rhs.1, lhs.2 + rhs.2, lhs.3 + rhs.3) } fn tuple_sub(lhs: PointVector, rhs: PointVector) -> PointVector { - ( - lhs.0 - rhs.0, - lhs.1 - rhs.1, - lhs.2 - rhs.2, - lhs.3 - rhs.3 - ) + (lhs.0 - rhs.0, lhs.1 - rhs.1, lhs.2 - rhs.2, lhs.3 - rhs.3) } fn tuple_neg(lhs: PointVector) -> PointVector { - ( - -lhs.0, - -lhs.1, - -lhs.2, - -lhs.3 - ) + (-lhs.0, -lhs.1, -lhs.2, -lhs.3) } fn tuple_mult(lhs: PointVector, scalar: f32) -> PointVector { @@ -74,7 +58,7 @@ fn tuple_mult(lhs: PointVector, scalar: f32) -> PointVector { lhs.1 * scalar, lhs.2 * scalar, lhs.3 * scalar, - ) + ) } fn tuple_div(lhs: PointVector, divisor: f32) -> PointVector { @@ -83,7 +67,40 @@ fn tuple_div(lhs: PointVector, divisor: f32) -> PointVector { lhs.1 / divisor, lhs.2 / divisor, lhs.3 / divisor, - ) + ) +} + +fn magnitude(vector: PointVector) -> f32 { + ( + (vector.0 * vector.0) + + (vector.1 * vector.1) + + (vector.2 * vector.2) + + (vector.3 * vector.3) + ).sqrt() +} + +fn normalize(vector: PointVector) -> PointVector { + let m = magnitude(vector); + (vector.0 / m, + vector.1 / m, + vector.2 / m, + vector.3 / m, + ) +} + +fn dot(lhs: PointVector, rhs: PointVector) -> f32 { + lhs.0 * rhs.0 + + lhs.1 * rhs.1 + + lhs.2 * rhs.2 + + lhs.3 * rhs.3 +} + +fn cross(lhs: PointVector, rhs: PointVector) -> PointVector { + vector( + lhs.1 * rhs.2 - lhs.2 * rhs.1, + lhs.2 * rhs.0 - lhs.0 * rhs.2, + lhs.0 * rhs.1 - lhs.1 * rhs.0 + ) } #[cfg(test)] @@ -94,10 +111,10 @@ mod tests { fn get_point() { let tuple = (4.3, -4.2, 3.1, 1.0); - assert_relative_eq!( 4.3, tuple_x(tuple)); - assert_relative_eq!(-4.2, tuple_y(tuple)); - assert_relative_eq!( 3.1, tuple_z(tuple)); - assert_eq!(true, tuple_is_point(tuple)); + assert_relative_eq!(4.3, tuple_x(tuple)); + assert_relative_eq!(-4.2, tuple_y(tuple)); + assert_relative_eq!(3.1, tuple_z(tuple)); + assert_eq!(true, tuple_is_point(tuple)); assert_eq!(false, tuple_is_vector(tuple)); } @@ -111,11 +128,11 @@ mod tests { fn get_vector() { let tuple = (4.3, -4.2, 3.1, 0.0); - assert_relative_eq!( 4.3, tuple_x(tuple)); - assert_relative_eq!(-4.2, tuple_y(tuple)); - assert_relative_eq!( 3.1, tuple_z(tuple)); + assert_relative_eq!(4.3, tuple_x(tuple)); + assert_relative_eq!(-4.2, tuple_y(tuple)); + assert_relative_eq!(3.1, tuple_z(tuple)); assert_eq!(false, tuple_is_point(tuple)); - assert_eq!(true, tuple_is_vector(tuple)); + assert_eq!(true, tuple_is_vector(tuple)); } #[test] @@ -221,4 +238,84 @@ mod tests { assert_eq!(true, tuple_equals(result, tuple_div(a, 2.0))); } + + #[test] + fn compute_magnitude_x() { + let v = vector(1.0, 0.0, 0.0); + + assert_eq!(1.0, magnitude(v)); + } + + #[test] + fn compute_magnitude_y() { + let v = vector(0.0, 1.0, 0.0); + + assert_eq!(1.0, magnitude(v)); + } + + #[test] + fn compute_magnitude_z() { + let v = vector(0.0, 0.0, 1.0); + + assert_eq!(1.0, magnitude(v)); + } + + #[test] + fn compute_magnitude_123() { + let v = vector(1.0, 2.0, 3.0); + + assert_relative_eq!(14.0_f32.sqrt(), magnitude(v)); + } + + #[test] + fn compute_magnitude_123_neg() { + let v = vector(-1.0, -2.0, -3.0); + + assert_relative_eq!(14.0_f32.sqrt(), magnitude(v)); + } + + #[test] + fn normalize_x() { + let v = vector(4.0, 0.0, 0.0); + let norm = normalize(v); + assert_eq!(vector(1.0, 0.0, 0.0), norm); + } + + #[test] + fn normalize_123() { + let v = vector(1.0, 2.0, 3.0); + let norm = normalize(v); + let sqrt_of_14 = 14.0_f32.sqrt(); + assert_relative_eq!(norm.0, 1.0 / sqrt_of_14); + assert_relative_eq!(norm.1, 2.0 / sqrt_of_14); + assert_relative_eq!(norm.2, 3.0 / sqrt_of_14); + } + + #[test] + fn magnitude_of_normalized_vector() { + let v = vector(1.0, 2.0, 3.0); + let norm = normalize(v); + let m = magnitude(norm); + assert_relative_eq!(1.0, m); + } + + #[test] + fn dot_product() { + let a = vector(1.0, 2.0, 3.0); + let b = vector(2.0, 3.0, 4.0); + + assert_eq!(20.0, dot(a, b)); + } + + #[test] + fn cross_product() { + let a = vector(1.0, 2.0, 3.0); + let b = vector(2.0, 3.0, 4.0); + + let a_cross_b = vector(-1.0, 2.0, -1.0); + assert_eq!(a_cross_b, cross(a, b)); + let b_cross_a = vector(1.0, -2.0, 1.0); + assert_eq!(b_cross_a, cross(b, a)); + + } }