[FEAT] Add Matrix * Tuple
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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));
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user