From 221a1e01e3836d500dd9fecb6802ae367f14369f Mon Sep 17 00:00:00 2001 From: NADAL Jean-Baptiste Date: Thu, 1 Feb 2024 18:43:27 +0100 Subject: [PATCH] [FEAT] Add Matrix * Tuple --- raytracing/src/matrix.cpp | 47 ++++++++++++++++++++++++++- raytracing/src/matrix.h | 4 +++ raytracing/src/tuple.cpp | 67 ++++++++++++++++++++++++++++++++++----- raytracing/src/tuple.h | 10 ++++++ tests/01_tuples.cpp | 40 +++++++++++++++++++++++ tests/03_matrix.cpp | 42 ++++++++++++++++++++++++ 6 files changed, 201 insertions(+), 9 deletions(-) diff --git a/raytracing/src/matrix.cpp b/raytracing/src/matrix.cpp index 5e513bf..8e9f0b5 100644 --- a/raytracing/src/matrix.cpp +++ b/raytracing/src/matrix.cpp @@ -40,7 +40,6 @@ using namespace Raytracer; Matrix::Matrix(void) : m_rows(0), m_cols(0) { - m_data = std::vector>(m_rows, std::vector(m_cols)); } /* ------------------------------------------------------------------------- */ @@ -48,6 +47,13 @@ Matrix::Matrix(void) : m_rows(0), m_cols(0) Matrix::Matrix(uint8_t a_rows, uint8_t a_cols) : m_rows(a_rows), m_cols(a_cols) { m_data = std::vector>(m_rows, std::vector(m_cols)); + for (int i = 0; i < m_rows; i++) + { + for (int j = 0; j < m_cols; j++) + { + m_data[i][j] = 0; + } + } } /* ------------------------------------------------------------------------- */ @@ -122,6 +128,45 @@ bool Matrix::operator!=(const Matrix &a_matrix) const /* ------------------------------------------------------------------------- */ +const Matrix Matrix::operator*(const Matrix &a_matrix) const +{ + double the_cell_value; + Matrix the_result(m_rows, m_cols); + + for (int the_row = 0; the_row < m_rows; the_row++) + { + for (int the_col = 0; the_col < m_cols; the_col++) + { + the_cell_value = 0; + + for (int i = 0; i < m_rows; i++) + { + the_cell_value += m_data[the_row][i] * a_matrix.m_data[i][the_col]; + } + the_result[the_row][the_col] = the_cell_value; + } + } + + return the_result; +} + +/* ------------------------------------------------------------------------- */ + +const Tuple Matrix::operator*(const Tuple &a_tuple) const +{ + Tuple the_result, the_row_tuple; + + for (int i = 0; i < m_rows; i++) + { + Tuple the_row_tuple(m_data[i]); + the_result[i] = the_row_tuple.dot(a_tuple); + } + + return the_result; +} + +/* ------------------------------------------------------------------------- */ + 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 32caa36..17cdd4f 100644 --- a/raytracing/src/matrix.h +++ b/raytracing/src/matrix.h @@ -32,6 +32,8 @@ #include #include +#include "tuple.h" + /* ------------------------------------------------------------------------- */ namespace Raytracer @@ -51,6 +53,8 @@ namespace Raytracer bool operator==(const Matrix &a_matrix) const; bool operator!=(const Matrix &a_matrix) const; + const Matrix operator*(const Matrix &a_matrix) const; + const Tuple operator*(const Tuple &a_tuple) const; private: bool validate_dimensions(const std::initializer_list> &a_values) const; diff --git a/raytracing/src/tuple.cpp b/raytracing/src/tuple.cpp index 02f1ccc..4df0f86 100644 --- a/raytracing/src/tuple.cpp +++ b/raytracing/src/tuple.cpp @@ -46,24 +46,34 @@ Tuple::Tuple(void) : m_x(0.0), m_y(0.0), m_z(0.0), m_w(0.0) /* ------------------------------------------------------------------------- */ -Tuple::Tuple(const Tuple &a_copy) : - m_x(a_copy.m_x), m_y(a_copy.m_y), m_z(a_copy.m_z), m_w(a_copy.m_w) +Tuple::Tuple(const Tuple &a_copy) : m_x(a_copy.m_x), m_y(a_copy.m_y), m_z(a_copy.m_z), m_w(a_copy.m_w) { } /* ------------------------------------------------------------------------- */ -Tuple::Tuple(double a_x, double a_y, double a_z, double a_w) : - m_x(a_x), m_y(a_y), m_z(a_z), m_w(a_w) +Tuple::Tuple(double a_x, double a_y, double a_z, double a_w) : m_x(a_x), m_y(a_y), m_z(a_z), m_w(a_w) { } /* ------------------------------------------------------------------------- */ +Tuple::Tuple(std::vector a_data) +{ + int i = 0; + for (auto the_it1 = a_data.cbegin(); the_it1 != a_data.cend(); ++the_it1) + { + set_at_index(i, *the_it1); + i++; + } +} + +/* ------------------------------------------------------------------------- */ + bool Tuple::operator==(const Tuple &an_other) const { - if (double_equal(m_x, an_other.m_x) && double_equal(m_y, an_other.m_y) && - double_equal(m_z, an_other.m_z) && double_equal(m_w, an_other.m_w)) + if (double_equal(m_x, an_other.m_x) && double_equal(m_y, an_other.m_y) && double_equal(m_z, an_other.m_z) && + double_equal(m_w, an_other.m_w)) { return true; } @@ -178,6 +188,34 @@ const Tuple &Tuple::operator/=(double a_scalar) /* ------------------------------------------------------------------------- */ +double &Tuple::operator[](uint8_t an_index) +{ + if (an_index == 0) + return m_x; + else if (an_index == 1) + return m_y; + else if (an_index == 2) + return m_z; + else + return m_w; +} + +/* ------------------------------------------------------------------------- */ + +const double &Tuple::operator[](uint8_t an_index) const +{ + if (an_index == 0) + return m_x; + else if (an_index == 1) + return m_y; + else if (an_index == 2) + return m_z; + else + return m_w; +} + +/* ------------------------------------------------------------------------- */ + Tuple Tuple::Point(double an_x, double an_y, double an_z) { return Tuple(an_x, an_y, an_z, kRaytracerTuplePoint); @@ -245,8 +283,7 @@ Tuple Tuple::normalize(void) { double the_magnitude = magnitude(); - return Tuple(m_x / the_magnitude, m_y / the_magnitude, m_z / the_magnitude, - m_w / the_magnitude); + return Tuple(m_x / the_magnitude, m_y / the_magnitude, m_z / the_magnitude, m_w / the_magnitude); } /* ------------------------------------------------------------------------- */ @@ -263,3 +300,17 @@ Tuple Tuple::cross(const Tuple &a_tuple) return Vector(m_y * a_tuple.m_z - m_z * a_tuple.m_y, m_z * a_tuple.m_x - m_x * a_tuple.m_z, m_x * a_tuple.m_y - m_y * a_tuple.m_x); } + +/* ------------------------------------------------------------------------- */ + +void Tuple::set_at_index(uint8_t an_index, double a_value) +{ + if (an_index == 0) + m_x = a_value; + else if (an_index == 1) + m_y = a_value; + else if (an_index == 2) + m_z = a_value; + else + m_w = a_value; +} diff --git a/raytracing/src/tuple.h b/raytracing/src/tuple.h index a01a899..c700bf4 100644 --- a/raytracing/src/tuple.h +++ b/raytracing/src/tuple.h @@ -26,6 +26,9 @@ #ifndef _RAYTRACER_TUPLE_H #define _RAYTRACER_TUPLE_H +#include +#include + /* ------------------------------------------------------------------------- */ #define kRaytracerTuplePoint 1.0 @@ -41,6 +44,7 @@ namespace Raytracer Tuple(void); Tuple(const Tuple &a_copy); Tuple(double an_x, double an_y, double an_z, double an_w); + Tuple(std::vector a_data); bool operator==(const Tuple &an_other) const; const Tuple &operator=(const Tuple &an_other); @@ -57,6 +61,9 @@ namespace Raytracer const Tuple &operator*=(double a_scalar); const Tuple &operator/=(double a_scalar); + double &operator[](uint8_t an_index); + const double &operator[](uint8_t an_index) const; + static Tuple Point(double an_x, double an_y, double an_z); static Tuple Vector(double an_x, double an_y, double an_z); @@ -75,6 +82,9 @@ namespace Raytracer double dot(const Tuple &a_tuple); Tuple cross(const Tuple &a_tuple); + private: + void set_at_index(uint8_t an_index, double a_value); + private: double m_x; double m_y; diff --git a/tests/01_tuples.cpp b/tests/01_tuples.cpp index 47d60e6..b6cb314 100644 --- a/tests/01_tuples.cpp +++ b/tests/01_tuples.cpp @@ -64,6 +64,46 @@ TEST_CASE("[Tuple] a tuple with w=0 is a vector", "[Tuple]") /* ------------------------------------------------------------------------- */ +TEST_CASE("[Tuple] access of data with []", "[Tuple]") +{ + Tuple a(4.3, -4.2, 3.1, 0.0); + + REQUIRE(a[0] == 4.3); + REQUIRE(a[1] == -4.2); + REQUIRE(a[2] == 3.1); + REQUIRE(a[3] == 0.0); +} + +/* ------------------------------------------------------------------------- */ + +TEST_CASE("[Tuple] constructor with std::vector", "[Tuple]") +{ + std::vector v = {4.3, -4.2, 3.1, 0.0}; + Tuple a(v); + + REQUIRE(a[0] == 4.3); + REQUIRE(a[1] == -4.2); + REQUIRE(a[2] == 3.1); + REQUIRE(a[3] == 0.0); +} + +/* ------------------------------------------------------------------------- */ + +TEST_CASE("[Tuple] test copy constructor", "[Tuple]") +{ + Tuple a; + Tuple b(4.3, -4.2, 3.1, 0.0); + + a = b; + + REQUIRE(a[0] == 4.3); + REQUIRE(a[1] == -4.2); + REQUIRE(a[2] == 3.1); + REQUIRE(a[3] == 0.0); +} + +/* ------------------------------------------------------------------------- */ + TEST_CASE("[Tuple] Tuple could be copy", "[Tuple]") { Tuple p = Tuple::Point(4, -4, 3); diff --git a/tests/03_matrix.cpp b/tests/03_matrix.cpp index c607e98..5d383fa 100644 --- a/tests/03_matrix.cpp +++ b/tests/03_matrix.cpp @@ -28,6 +28,7 @@ #include #include "matrix.h" +#include "tuple.h" using namespace Raytracer; @@ -129,3 +130,44 @@ TEST_CASE("[Matrix] Matrix equality with different matrices", "[Matrix]") REQUIRE(a != b); } + +/* ------------------------------------------------------------------------- */ + +TEST_CASE("[Matrix] Multiplying two matrices", "[Matrix]") +{ + Matrix a = { + {1, 2, 3, 4}, + {5, 6, 7, 8}, + {9, 8, 7, 6}, + {5, 4, 3, 2} + }; + Matrix b = { + {-2, 1, 2, 3}, + { 3, 2, 1, -1}, + { 4, 3, 6, 5}, + { 1, 2, 7, 8} + }; + Matrix c = { + {20, 22, 50, 48}, + {44, 54, 114, 108}, + {40, 58, 110, 102}, + {16, 26, 46, 42} + }; + + REQUIRE((a * b) == c); +} + +/* ------------------------------------------------------------------------- */ + +TEST_CASE("[Matrix] a matrix multiplied by a tuple", "[Matrix]") +{ + Matrix a = { + {1, 2, 3, 4}, + {2, 4, 4, 2}, + {8, 6, 4, 1}, + {0, 0, 0, 1} + }; + Tuple b(1, 2, 3, 1); + + REQUIRE((a * b) == Tuple(18, 24, 33, 1)); +}