[FEAT] Add Matrix * Tuple

This commit is contained in:
NADAL Jean-Baptiste
2024-02-01 18:43:27 +01:00
parent 7201bfdf4c
commit 221a1e01e3
6 changed files with 201 additions and 9 deletions

View File

@@ -40,7 +40,6 @@ using namespace Raytracer;
Matrix::Matrix(void) : m_rows(0), m_cols(0) Matrix::Matrix(void) : m_rows(0), m_cols(0)
{ {
m_data = std::vector<std::vector<double>>(m_rows, std::vector<double>(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) Matrix::Matrix(uint8_t a_rows, uint8_t a_cols) : m_rows(a_rows), m_cols(a_cols)
{ {
m_data = std::vector<std::vector<double>>(m_rows, std::vector<double>(m_cols)); m_data = std::vector<std::vector<double>>(m_rows, std::vector<double>(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<std::initializer_list<double>> &a_values) const bool Matrix::validate_dimensions(const std::initializer_list<std::initializer_list<double>> &a_values) const
{ {
for (const auto &the_row : a_values) for (const auto &the_row : a_values)

View File

@@ -32,6 +32,8 @@
#include <initializer_list> #include <initializer_list>
#include <vector> #include <vector>
#include "tuple.h"
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
namespace Raytracer namespace Raytracer
@@ -51,6 +53,8 @@ namespace Raytracer
bool operator==(const Matrix &a_matrix) const; bool operator==(const Matrix &a_matrix) const;
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: private:
bool validate_dimensions(const std::initializer_list<std::initializer_list<double>> &a_values) const; bool validate_dimensions(const std::initializer_list<std::initializer_list<double>> &a_values) const;

View File

@@ -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) : 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)
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) : 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)
m_x(a_x), m_y(a_y), m_z(a_z), m_w(a_w)
{ {
} }
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
Tuple::Tuple(std::vector<double> 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 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) && 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_z, an_other.m_z) && double_equal(m_w, an_other.m_w)) double_equal(m_w, an_other.m_w))
{ {
return true; 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) Tuple Tuple::Point(double an_x, double an_y, double an_z)
{ {
return Tuple(an_x, an_y, an_z, kRaytracerTuplePoint); return Tuple(an_x, an_y, an_z, kRaytracerTuplePoint);
@@ -245,8 +283,7 @@ Tuple Tuple::normalize(void)
{ {
double the_magnitude = magnitude(); double the_magnitude = magnitude();
return Tuple(m_x / the_magnitude, m_y / the_magnitude, m_z / the_magnitude, return Tuple(m_x / the_magnitude, m_y / the_magnitude, m_z / the_magnitude, m_w / 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, 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); 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;
}

View File

@@ -26,6 +26,9 @@
#ifndef _RAYTRACER_TUPLE_H #ifndef _RAYTRACER_TUPLE_H
#define _RAYTRACER_TUPLE_H #define _RAYTRACER_TUPLE_H
#include <cstdint>
#include <vector>
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
#define kRaytracerTuplePoint 1.0 #define kRaytracerTuplePoint 1.0
@@ -41,6 +44,7 @@ namespace Raytracer
Tuple(void); Tuple(void);
Tuple(const Tuple &a_copy); Tuple(const Tuple &a_copy);
Tuple(double an_x, double an_y, double an_z, double an_w); Tuple(double an_x, double an_y, double an_z, double an_w);
Tuple(std::vector<double> a_data);
bool operator==(const Tuple &an_other) const; bool operator==(const Tuple &an_other) const;
const Tuple &operator=(const Tuple &an_other); 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);
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 Point(double an_x, double an_y, double an_z);
static Tuple Vector(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); double dot(const Tuple &a_tuple);
Tuple cross(const Tuple &a_tuple); Tuple cross(const Tuple &a_tuple);
private:
void set_at_index(uint8_t an_index, double a_value);
private: private:
double m_x; double m_x;
double m_y; double m_y;

View File

@@ -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<double> 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]") TEST_CASE("[Tuple] Tuple could be copy", "[Tuple]")
{ {
Tuple p = Tuple::Point(4, -4, 3); Tuple p = Tuple::Point(4, -4, 3);

View File

@@ -28,6 +28,7 @@
#include <catch.hpp> #include <catch.hpp>
#include "matrix.h" #include "matrix.h"
#include "tuple.h"
using namespace Raytracer; using namespace Raytracer;
@@ -129,3 +130,44 @@ TEST_CASE("[Matrix] Matrix equality with different matrices", "[Matrix]")
REQUIRE(a != b); 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));
}