diff --git a/raytracing/src/matrix.cpp b/raytracing/src/matrix.cpp index d7c56aa..dfd2b3d 100644 --- a/raytracing/src/matrix.cpp +++ b/raytracing/src/matrix.cpp @@ -120,7 +120,7 @@ bool Matrix::operator==(const Matrix &a_matrix) const { if (!double_equal(*the_elem1, *the_elem2)) { - printf("Elem: %f != %f\n", *the_elem1, *the_elem2); + // printf("Elem: %f != %f\n", *the_elem1, *the_elem2); return false; } } @@ -262,7 +262,7 @@ double Matrix::cofactor(uint8_t a_row, uint8_t a_col) const bool Matrix::invertible(void) const { - if (determinant() == 0) + if (double_equal(determinant(), 0)) return false; return true; @@ -340,6 +340,48 @@ Matrix Matrix::scaling(double an_x, double an_y, double an_z) /* ------------------------------------------------------------------------- */ +Matrix Matrix::rotation_x(double a_radians) +{ + Matrix the_rotation = { + {1, 0, 0, 0}, + {0, cos(a_radians), -sin(a_radians), 0}, + {0, sin(a_radians), cos(a_radians), 0}, + {0, 0, 0, 1} + }; + + return the_rotation; +} + +/* ------------------------------------------------------------------------- */ + +Matrix Matrix::rotation_y(double a_radians) +{ + Matrix the_rotation = { + { cos(a_radians), 0, sin(a_radians), 0}, + { 0, 1, 0, 0}, + {-sin(a_radians), 0, cos(a_radians), 0}, + { 0, 0, 0, 1} + }; + + return the_rotation; +} + +/* ------------------------------------------------------------------------- */ + +Matrix Matrix::rotation_z(double a_radians) +{ + Matrix the_rotation = { + {cos(a_radians), -sin(a_radians), 0, 0}, + {sin(a_radians), cos(a_radians), 0, 0}, + { 0, 0, 1, 0}, + { 0, 0, 0, 1} + }; + + return the_rotation; +} + +/* ------------------------------------------------------------------------- */ + bool Matrix::validate_dimensions(const std::initializer_list> &a_values) const { for (const auto &the_row : a_values) diff --git a/raytracing/src/matrix.h b/raytracing/src/matrix.h index da797e4..3afa4ce 100644 --- a/raytracing/src/matrix.h +++ b/raytracing/src/matrix.h @@ -73,6 +73,9 @@ namespace Raytracer static Matrix identity(void); static Matrix translation(double an_x, double an_y, double an_z); static Matrix scaling(double an_x, double an_y, double an_z); + static Matrix rotation_x(double a_radians); + static Matrix rotation_y(double a_radians); + static Matrix rotation_z(double a_radians); private: bool validate_dimensions(const std::initializer_list> &a_values) const; diff --git a/tests/04_transformations.cpp b/tests/04_transformations.cpp index 77d0de1..7b75bd2 100644 --- a/tests/04_transformations.cpp +++ b/tests/04_transformations.cpp @@ -102,3 +102,52 @@ TEST_CASE("[04][TRANSFORMATION] Reflection is scaling by a negative value", "[Ma REQUIRE(transform * p == Tuple::Point(-2, 3, 4)); } + +/* ------------------------------------------------------------------------- */ + +TEST_CASE("[04][TRANSFORMATION] Rotating a point around the x axis", "[Matrix]") +{ + Tuple p = Tuple::Point(0, 1, 0); + Matrix half_quarter = Matrix::rotation_x(std::numbers::pi / 4); + Matrix full_quarter = Matrix::rotation_x(std::numbers::pi / 2); + + REQUIRE(half_quarter * p == Tuple::Point(0, sqrt(2) / 2, sqrt(2) / 2)); + REQUIRE(full_quarter * p == Tuple::Point(0, 0, 1)); +} + +/* ------------------------------------------------------------------------- */ + +TEST_CASE("[04][TRANSFORMATION] The inverse of an x-rotation rotates in the opposite direction", "[Matrix]") +{ + Tuple p = Tuple::Point(0, 1, 0); + Matrix half_quarter = Matrix::rotation_x(std::numbers::pi / 4); + Matrix inv = half_quarter.inverse(); + + REQUIRE(inv * p == Tuple::Point(0, sqrt(2) / 2, -sqrt(2) / 2)); +} + +/* ------------------------------------------------------------------------- */ + +TEST_CASE("[04][TRANSFORMATION] Rotating a point around the y axis", "[Matrix]") +{ + Tuple p = Tuple::Point(0, 0, 1); + Matrix half_quarter = Matrix::rotation_y(std::numbers::pi / 4); + Matrix full_quarter = Matrix::rotation_y(std::numbers::pi / 2); + + REQUIRE(half_quarter * p == Tuple::Point(sqrt(2) / 2, 0, sqrt(2) / 2)); + REQUIRE(full_quarter * p == Tuple::Point(1, 0, 0)); +} + +/* ------------------------------------------------------------------------- */ + +TEST_CASE("[04][TRANSFORMATION] Rotating a point around the z axis", "[Matrix]") +{ + Tuple p = Tuple::Point(0, 1, 0); + Matrix half_quarter = Matrix::rotation_z(std::numbers::pi / 4); + Matrix full_quarter = Matrix::rotation_z(std::numbers::pi / 2); + + Tuple z = half_quarter * p; + + REQUIRE(half_quarter * p == Tuple::Point(-sqrt(2) / 2, sqrt(2) / 2, 0)); + REQUIRE(full_quarter * p == Tuple::Point(-1, 0, 0)); +}