Added better support for casting vector3d to/from MAtrix

This commit is contained in:
2025-02-03 10:10:31 -05:00
parent a8c6e8360e
commit ae4806510b
7 changed files with 344 additions and 174 deletions

View File

@@ -70,7 +70,8 @@
"thread": "cpp", "thread": "cpp",
"typeinfo": "cpp", "typeinfo": "cpp",
"variant": "cpp", "variant": "cpp",
"shared_mutex": "cpp" "shared_mutex": "cpp",
"charconv": "cpp"
}, },
"clangd.enable": false, "clangd.enable": false,
"C_Cpp.dimInactiveRegions": false "C_Cpp.dimInactiveRegions": false

View File

@@ -7,34 +7,51 @@ set(CMAKE_CXX_STANDARD 11)
add_compile_options(-fdiagnostics-color=always) add_compile_options(-fdiagnostics-color=always)
# Vector 3D Interface
add_library(vector-3d-intf
INTERFACE
)
target_include_directories(vector-3d-intf
INTERFACE
.
)
# Matrix
add_library(matrix
STATIC
Matrix.cpp
)
target_link_libraries(matrix
PUBLIC
vector-3d-intf
PRIVATE
)
set_target_properties(matrix
PROPERTIES
LINKER_LANGUAGE CXX
)
# Vector3d # Vector3d
add_library(Vector3D add_library(vector-3d
STATIC STATIC
Vector3D.hpp Vector3D.hpp
) )
set_target_properties(Vector3D target_include_directories(vector-3d
PROPERTIES
LINKER_LANGUAGE CXX
)
target_include_directories(Vector3D PUBLIC
include
)
# Matrix
add_library(Matrix
STATIC
Matrix.hpp
Matrix.cpp
)
set_target_properties(Matrix
PROPERTIES
LINKER_LANGUAGE CXX
)
target_include_directories(Matrix
PUBLIC PUBLIC
. .
) )
target_link_libraries(vector-3d
PUBLIC
vector-3d-intf
PRIVATE
)
set_target_properties(vector-3d
PROPERTIES
LINKER_LANGUAGE CXX
)

View File

@@ -8,18 +8,21 @@
#include <type_traits> #include <type_traits>
template <uint8_t rows, uint8_t columns> template <uint8_t rows, uint8_t columns>
Matrix<rows, columns>::Matrix(float value) { Matrix<rows, columns>::Matrix(float value)
{
this->Fill(value); this->Fill(value);
} }
template <uint8_t rows, uint8_t columns> template <uint8_t rows, uint8_t columns>
Matrix<rows, columns>::Matrix(const std::array<float, rows * columns> &array) { Matrix<rows, columns>::Matrix(const std::array<float, rows * columns> &array)
{
this->setMatrixToArray(array); this->setMatrixToArray(array);
} }
template <uint8_t rows, uint8_t columns> template <uint8_t rows, uint8_t columns>
template <typename... Args> template <typename... Args>
Matrix<rows, columns>::Matrix(Args... args) { Matrix<rows, columns>::Matrix(Args... args)
{
constexpr uint16_t arraySize{static_cast<uint16_t>(rows) * constexpr uint16_t arraySize{static_cast<uint16_t>(rows) *
static_cast<uint16_t>(columns)}; static_cast<uint16_t>(columns)};
@@ -31,9 +34,12 @@ Matrix<rows, columns>::Matrix(Args... args) {
} }
template <uint8_t rows, uint8_t columns> template <uint8_t rows, uint8_t columns>
Matrix<rows, columns>::Matrix(const Matrix<rows, columns> &other) { Matrix<rows, columns>::Matrix(const Matrix<rows, columns> &other)
for (uint8_t row_idx{0}; row_idx < rows; row_idx++) { {
for (uint8_t column_idx{0}; column_idx < columns; column_idx++) { for (uint8_t row_idx{0}; row_idx < rows; row_idx++)
{
for (uint8_t column_idx{0}; column_idx < columns; column_idx++)
{
this->matrix[row_idx * columns + column_idx] = this->matrix[row_idx * columns + column_idx] =
other.Get(row_idx, column_idx); other.Get(row_idx, column_idx);
} }
@@ -42,15 +48,21 @@ Matrix<rows, columns>::Matrix(const Matrix<rows, columns> &other) {
template <uint8_t rows, uint8_t columns> template <uint8_t rows, uint8_t columns>
void Matrix<rows, columns>::setMatrixToArray( void Matrix<rows, columns>::setMatrixToArray(
const std::array<float, rows * columns> &array) { const std::array<float, rows * columns> &array)
for (uint8_t row_idx{0}; row_idx < rows; row_idx++) { {
for (uint8_t column_idx{0}; column_idx < columns; column_idx++) { for (uint8_t row_idx{0}; row_idx < rows; row_idx++)
{
for (uint8_t column_idx{0}; column_idx < columns; column_idx++)
{
uint16_t array_idx = uint16_t array_idx =
static_cast<uint16_t>(row_idx) * static_cast<uint16_t>(columns) + static_cast<uint16_t>(row_idx) * static_cast<uint16_t>(columns) +
static_cast<uint16_t>(column_idx); static_cast<uint16_t>(column_idx);
if (array_idx < array.size()) { if (array_idx < array.size())
{
this->matrix[row_idx * columns + column_idx] = array[array_idx]; this->matrix[row_idx * columns + column_idx] = array[array_idx];
} else { }
else
{
this->matrix[row_idx * columns + column_idx] = 0; this->matrix[row_idx * columns + column_idx] = 0;
} }
} }
@@ -60,9 +72,12 @@ void Matrix<rows, columns>::setMatrixToArray(
template <uint8_t rows, uint8_t columns> template <uint8_t rows, uint8_t columns>
Matrix<rows, columns> & Matrix<rows, columns> &
Matrix<rows, columns>::Add(const Matrix<rows, columns> &other, Matrix<rows, columns>::Add(const Matrix<rows, columns> &other,
Matrix<rows, columns> &result) const { Matrix<rows, columns> &result) const
for (uint8_t row_idx{0}; row_idx < rows; row_idx++) { {
for (uint8_t column_idx{0}; column_idx < columns; column_idx++) { for (uint8_t row_idx{0}; row_idx < rows; row_idx++)
{
for (uint8_t column_idx{0}; column_idx < columns; column_idx++)
{
result[row_idx][column_idx] = result[row_idx][column_idx] =
this->Get(row_idx, column_idx) + other.Get(row_idx, column_idx); this->Get(row_idx, column_idx) + other.Get(row_idx, column_idx);
} }
@@ -73,9 +88,12 @@ Matrix<rows, columns>::Add(const Matrix<rows, columns> &other,
template <uint8_t rows, uint8_t columns> template <uint8_t rows, uint8_t columns>
Matrix<rows, columns> & Matrix<rows, columns> &
Matrix<rows, columns>::Sub(const Matrix<rows, columns> &other, Matrix<rows, columns>::Sub(const Matrix<rows, columns> &other,
Matrix<rows, columns> &result) const { Matrix<rows, columns> &result) const
for (uint8_t row_idx{0}; row_idx < rows; row_idx++) { {
for (uint8_t column_idx{0}; column_idx < columns; column_idx++) { for (uint8_t row_idx{0}; row_idx < rows; row_idx++)
{
for (uint8_t column_idx{0}; column_idx < columns; column_idx++)
{
result[row_idx][column_idx] = result[row_idx][column_idx] =
this->Get(row_idx, column_idx) - other.Get(row_idx, column_idx); this->Get(row_idx, column_idx) - other.Get(row_idx, column_idx);
} }
@@ -88,16 +106,19 @@ template <uint8_t rows, uint8_t columns>
template <uint8_t other_columns> template <uint8_t other_columns>
Matrix<rows, columns> & Matrix<rows, columns> &
Matrix<rows, columns>::Mult(const Matrix<columns, other_columns> &other, Matrix<rows, columns>::Mult(const Matrix<columns, other_columns> &other,
Matrix<rows, other_columns> &result) const { Matrix<rows, other_columns> &result) const
{
// allocate some buffers for all of our dot products // allocate some buffers for all of our dot products
Matrix<1, columns> this_row; Matrix<1, columns> this_row;
Matrix<rows, 1> other_column; Matrix<rows, 1> other_column;
Matrix<1, rows> other_column_t; Matrix<1, rows> other_column_t;
for (uint8_t row_idx{0}; row_idx < rows; row_idx++) { for (uint8_t row_idx{0}; row_idx < rows; row_idx++)
{
// get our row // get our row
this->GetRow(row_idx, this_row); this->GetRow(row_idx, this_row);
for (uint8_t column_idx{0}; column_idx < columns; column_idx++) { for (uint8_t column_idx{0}; column_idx < columns; column_idx++)
{
// get the other matrix'ss column // get the other matrix'ss column
other.GetColumn(column_idx, other_column); other.GetColumn(column_idx, other_column);
// transpose the other matrix's column // transpose the other matrix's column
@@ -114,9 +135,12 @@ Matrix<rows, columns>::Mult(const Matrix<columns, other_columns> &other,
template <uint8_t rows, uint8_t columns> template <uint8_t rows, uint8_t columns>
Matrix<rows, columns> & Matrix<rows, columns> &
Matrix<rows, columns>::Mult(float scalar, Matrix<rows, columns> &result) const { Matrix<rows, columns>::Mult(float scalar, Matrix<rows, columns> &result) const
for (uint8_t row_idx{0}; row_idx < rows; row_idx++) { {
for (uint8_t column_idx{0}; column_idx < columns; column_idx++) { for (uint8_t row_idx{0}; row_idx < rows; row_idx++)
{
for (uint8_t column_idx{0}; column_idx < columns; column_idx++)
{
result[row_idx][column_idx] = this->Get(row_idx, column_idx) * scalar; result[row_idx][column_idx] = this->Get(row_idx, column_idx) * scalar;
} }
} }
@@ -126,7 +150,8 @@ Matrix<rows, columns>::Mult(float scalar, Matrix<rows, columns> &result) const {
template <uint8_t rows, uint8_t columns> template <uint8_t rows, uint8_t columns>
Matrix<rows, columns> & Matrix<rows, columns> &
Matrix<rows, columns>::Invert(Matrix<rows, columns> &result) const { Matrix<rows, columns>::Invert(Matrix<rows, columns> &result) const
{
// since all matrix sizes have to be statically specified at compile time we // since all matrix sizes have to be statically specified at compile time we
// can do this // can do this
static_assert(rows == columns, static_assert(rows == columns,
@@ -135,7 +160,8 @@ Matrix<rows, columns>::Invert(Matrix<rows, columns> &result) const {
// unfortunately we can't calculate this at compile time so we'll just reurn // unfortunately we can't calculate this at compile time so we'll just reurn
// zeros // zeros
float determinant{this->Det()}; float determinant{this->Det()};
if (determinant == 0) { if (determinant == 0)
{
// you can't invert a matrix with a negative determinant // you can't invert a matrix with a negative determinant
result.Fill(0); result.Fill(0);
return result; return result;
@@ -161,9 +187,12 @@ Matrix<rows, columns>::Invert(Matrix<rows, columns> &result) const {
template <uint8_t rows, uint8_t columns> template <uint8_t rows, uint8_t columns>
Matrix<columns, rows> & Matrix<columns, rows> &
Matrix<rows, columns>::Transpose(Matrix<columns, rows> &result) const { Matrix<rows, columns>::Transpose(Matrix<columns, rows> &result) const
for (uint8_t column_idx{0}; column_idx < rows; column_idx++) { {
for (uint8_t row_idx{0}; row_idx < columns; row_idx++) { for (uint8_t column_idx{0}; column_idx < rows; column_idx++)
{
for (uint8_t row_idx{0}; row_idx < columns; row_idx++)
{
result[row_idx][column_idx] = this->Get(column_idx, row_idx); result[row_idx][column_idx] = this->Get(column_idx, row_idx);
} }
} }
@@ -173,20 +202,26 @@ Matrix<rows, columns>::Transpose(Matrix<columns, rows> &result) const {
// explicitly define the determinant for a 2x2 matrix because it is definitely // explicitly define the determinant for a 2x2 matrix because it is definitely
// the fastest way to calculate a 2x2 matrix determinant // the fastest way to calculate a 2x2 matrix determinant
template <> float Matrix<0, 0>::Det() const { return 1e+6; } template <>
template <> float Matrix<1, 1>::Det() const { return this->matrix[0]; } float Matrix<0, 0>::Det() const { return 1e+6; }
template <> float Matrix<2, 2>::Det() const { template <>
float Matrix<1, 1>::Det() const { return this->matrix[0]; }
template <>
float Matrix<2, 2>::Det() const
{
return this->matrix[0] * this->matrix[3] - this->matrix[1] * this->matrix[2]; return this->matrix[0] * this->matrix[3] - this->matrix[1] * this->matrix[2];
} }
template <uint8_t rows, uint8_t columns> template <uint8_t rows, uint8_t columns>
float Matrix<rows, columns>::Det() const { float Matrix<rows, columns>::Det() const
{
static_assert(rows == columns, static_assert(rows == columns,
"You can't take the determinant of a non-square matrix."); "You can't take the determinant of a non-square matrix.");
Matrix<rows - 1, columns - 1> MinorMatrix{}; Matrix<rows - 1, columns - 1> MinorMatrix{};
float determinant{0}; float determinant{0};
for (uint8_t column_idx{0}; column_idx < columns; column_idx++) { for (uint8_t column_idx{0}; column_idx < columns; column_idx++)
{
// for odd indices the sign is negative // for odd indices the sign is negative
float sign = (column_idx % 2 == 0) ? 1 : -1; float sign = (column_idx % 2 == 0) ? 1 : -1;
determinant += sign * this->matrix[column_idx] * determinant += sign * this->matrix[column_idx] *
@@ -199,9 +234,12 @@ float Matrix<rows, columns>::Det() const {
template <uint8_t rows, uint8_t columns> template <uint8_t rows, uint8_t columns>
Matrix<rows, columns> & Matrix<rows, columns> &
Matrix<rows, columns>::ElementMultiply(const Matrix<rows, columns> &other, Matrix<rows, columns>::ElementMultiply(const Matrix<rows, columns> &other,
Matrix<rows, columns> &result) const { Matrix<rows, columns> &result) const
for (uint8_t row_idx{0}; row_idx < rows; row_idx++) { {
for (uint8_t column_idx{0}; column_idx < columns; column_idx++) { for (uint8_t row_idx{0}; row_idx < rows; row_idx++)
{
for (uint8_t column_idx{0}; column_idx < columns; column_idx++)
{
result[row_idx][column_idx] = result[row_idx][column_idx] =
this->Get(row_idx, column_idx) * other.Get(row_idx, column_idx); this->Get(row_idx, column_idx) * other.Get(row_idx, column_idx);
} }
@@ -213,9 +251,12 @@ Matrix<rows, columns>::ElementMultiply(const Matrix<rows, columns> &other,
template <uint8_t rows, uint8_t columns> template <uint8_t rows, uint8_t columns>
Matrix<rows, columns> & Matrix<rows, columns> &
Matrix<rows, columns>::ElementDivide(const Matrix<rows, columns> &other, Matrix<rows, columns>::ElementDivide(const Matrix<rows, columns> &other,
Matrix<rows, columns> &result) const { Matrix<rows, columns> &result) const
for (uint8_t row_idx{0}; row_idx < rows; row_idx++) { {
for (uint8_t column_idx{0}; column_idx < columns; column_idx++) { for (uint8_t row_idx{0}; row_idx < rows; row_idx++)
{
for (uint8_t column_idx{0}; column_idx < columns; column_idx++)
{
result[row_idx][column_idx] = result[row_idx][column_idx] =
this->Get(row_idx, column_idx) / other.Get(row_idx, column_idx); this->Get(row_idx, column_idx) / other.Get(row_idx, column_idx);
} }
@@ -226,8 +267,10 @@ Matrix<rows, columns>::ElementDivide(const Matrix<rows, columns> &other,
template <uint8_t rows, uint8_t columns> template <uint8_t rows, uint8_t columns>
float Matrix<rows, columns>::Get(uint8_t row_index, float Matrix<rows, columns>::Get(uint8_t row_index,
uint8_t column_index) const { uint8_t column_index) const
if (row_index > rows - 1 || column_index > columns - 1) { {
if (row_index > rows - 1 || column_index > columns - 1)
{
return 1e+10; // TODO: We should throw something here instead of failing return 1e+10; // TODO: We should throw something here instead of failing
// quietly // quietly
} }
@@ -237,7 +280,8 @@ float Matrix<rows, columns>::Get(uint8_t row_index,
template <uint8_t rows, uint8_t columns> template <uint8_t rows, uint8_t columns>
Matrix<1, columns> & Matrix<1, columns> &
Matrix<rows, columns>::GetRow(uint8_t row_index, Matrix<rows, columns>::GetRow(uint8_t row_index,
Matrix<1, columns> &row) const { Matrix<1, columns> &row) const
{
memcpy(&(row[0]), this->matrix.begin() + row_index * columns, memcpy(&(row[0]), this->matrix.begin() + row_index * columns,
columns * sizeof(float)); columns * sizeof(float));
@@ -247,8 +291,10 @@ Matrix<rows, columns>::GetRow(uint8_t row_index,
template <uint8_t rows, uint8_t columns> template <uint8_t rows, uint8_t columns>
Matrix<rows, 1> & Matrix<rows, 1> &
Matrix<rows, columns>::GetColumn(uint8_t column_index, Matrix<rows, columns>::GetColumn(uint8_t column_index,
Matrix<rows, 1> &column) const { Matrix<rows, 1> &column) const
for (uint8_t row_idx{0}; row_idx < rows; row_idx++) { {
for (uint8_t row_idx{0}; row_idx < rows; row_idx++)
{
column[row_idx][0] = this->Get(row_idx, column_index); column[row_idx][0] = this->Get(row_idx, column_index);
} }
@@ -256,13 +302,17 @@ Matrix<rows, columns>::GetColumn(uint8_t column_index,
} }
template <uint8_t rows, uint8_t columns> template <uint8_t rows, uint8_t columns>
void Matrix<rows, columns>::ToString(std::string &stringBuffer) const { void Matrix<rows, columns>::ToString(std::string &stringBuffer) const
for (uint8_t row_idx{0}; row_idx < rows; row_idx++) { {
for (uint8_t row_idx{0}; row_idx < rows; row_idx++)
{
stringBuffer += "|"; stringBuffer += "|";
for (uint8_t column_idx{0}; column_idx < columns; column_idx++) { for (uint8_t column_idx{0}; column_idx < columns; column_idx++)
{
stringBuffer += stringBuffer +=
std::to_string(this->matrix[row_idx * columns + column_idx]); std::to_string(this->matrix[row_idx * columns + column_idx]);
if (column_idx != columns - 1) { if (column_idx != columns - 1)
{
stringBuffer += "\t"; stringBuffer += "\t";
} }
} }
@@ -272,8 +322,10 @@ void Matrix<rows, columns>::ToString(std::string &stringBuffer) const {
template <uint8_t rows, uint8_t columns> template <uint8_t rows, uint8_t columns>
std::array<float, columns> &Matrix<rows, columns>:: std::array<float, columns> &Matrix<rows, columns>::
operator[](uint8_t row_index) { operator[](uint8_t row_index)
if (row_index > rows - 1) { {
if (row_index > rows - 1)
{
// TODO: We should throw something here instead of failing quietly. // TODO: We should throw something here instead of failing quietly.
row_index = 0; row_index = 0;
} }
@@ -285,9 +337,12 @@ operator[](uint8_t row_index) {
template <uint8_t rows, uint8_t columns> template <uint8_t rows, uint8_t columns>
Matrix<rows, columns> &Matrix<rows, columns>:: Matrix<rows, columns> &Matrix<rows, columns>::
operator=(const Matrix<rows, columns> &other) { operator=(const Matrix<rows, columns> &other)
for (uint8_t row_idx{0}; row_idx < rows; row_idx++) { {
for (uint8_t column_idx{0}; column_idx < columns; column_idx++) { for (uint8_t row_idx{0}; row_idx < rows; row_idx++)
{
for (uint8_t column_idx{0}; column_idx < columns; column_idx++)
{
this->matrix[row_idx * columns + column_idx] = this->matrix[row_idx * columns + column_idx] =
other.Get(row_idx, column_idx); other.Get(row_idx, column_idx);
} }
@@ -298,7 +353,8 @@ operator=(const Matrix<rows, columns> &other) {
template <uint8_t rows, uint8_t columns> template <uint8_t rows, uint8_t columns>
Matrix<rows, columns> Matrix<rows, columns>:: Matrix<rows, columns> Matrix<rows, columns>::
operator+(const Matrix<rows, columns> &other) const { operator+(const Matrix<rows, columns> &other) const
{
Matrix<rows, columns> buffer{}; Matrix<rows, columns> buffer{};
this->Add(other, buffer); this->Add(other, buffer);
return buffer; return buffer;
@@ -306,7 +362,8 @@ operator+(const Matrix<rows, columns> &other) const {
template <uint8_t rows, uint8_t columns> template <uint8_t rows, uint8_t columns>
Matrix<rows, columns> Matrix<rows, columns>:: Matrix<rows, columns> Matrix<rows, columns>::
operator-(const Matrix<rows, columns> &other) const { operator-(const Matrix<rows, columns> &other) const
{
Matrix<rows, columns> buffer{}; Matrix<rows, columns> buffer{};
this->Sub(other, buffer); this->Sub(other, buffer);
return buffer; return buffer;
@@ -314,14 +371,16 @@ operator-(const Matrix<rows, columns> &other) const {
template <uint8_t rows, uint8_t columns> template <uint8_t rows, uint8_t columns>
Matrix<rows, columns> Matrix<rows, columns>:: Matrix<rows, columns> Matrix<rows, columns>::
operator*(const Matrix<rows, columns> &other) const { operator*(const Matrix<rows, columns> &other) const
{
Matrix<rows, columns> buffer{}; Matrix<rows, columns> buffer{};
this->Mult(other, buffer); this->Mult(other, buffer);
return buffer; return buffer;
} }
template <uint8_t rows, uint8_t columns> template <uint8_t rows, uint8_t columns>
Matrix<rows, columns> Matrix<rows, columns>::operator*(float scalar) const { Matrix<rows, columns> Matrix<rows, columns>::operator*(float scalar) const
{
Matrix<rows, columns> buffer{}; Matrix<rows, columns> buffer{};
this->Mult(scalar, buffer); this->Mult(scalar, buffer);
return buffer; return buffer;
@@ -330,9 +389,11 @@ Matrix<rows, columns> Matrix<rows, columns>::operator*(float scalar) const {
template <uint8_t rows, uint8_t columns> template <uint8_t rows, uint8_t columns>
template <uint8_t vector_size> template <uint8_t vector_size>
float Matrix<rows, columns>::dotProduct(const Matrix<1, vector_size> &vec1, float Matrix<rows, columns>::dotProduct(const Matrix<1, vector_size> &vec1,
const Matrix<1, vector_size> &vec2) { const Matrix<1, vector_size> &vec2)
{
float sum{0}; float sum{0};
for (uint8_t i{0}; i < vector_size; i++) { for (uint8_t i{0}; i < vector_size; i++)
{
sum += vec1.Get(0, i) * vec2.Get(0, i); sum += vec1.Get(0, i) * vec2.Get(0, i);
} }
@@ -342,9 +403,11 @@ float Matrix<rows, columns>::dotProduct(const Matrix<1, vector_size> &vec1,
template <uint8_t rows, uint8_t columns> template <uint8_t rows, uint8_t columns>
template <uint8_t vector_size> template <uint8_t vector_size>
float Matrix<rows, columns>::dotProduct(const Matrix<vector_size, 1> &vec1, float Matrix<rows, columns>::dotProduct(const Matrix<vector_size, 1> &vec1,
const Matrix<vector_size, 1> &vec2) { const Matrix<vector_size, 1> &vec2)
{
float sum{0}; float sum{0};
for (uint8_t i{0}; i < vector_size; i++) { for (uint8_t i{0}; i < vector_size; i++)
{
sum += vec1.Get(i, 0) * vec2.Get(i, 0); sum += vec1.Get(i, 0) * vec2.Get(i, 0);
} }
@@ -352,9 +415,12 @@ float Matrix<rows, columns>::dotProduct(const Matrix<vector_size, 1> &vec1,
} }
template <uint8_t rows, uint8_t columns> template <uint8_t rows, uint8_t columns>
void Matrix<rows, columns>::Fill(float value) { void Matrix<rows, columns>::Fill(float value)
for (uint8_t row_idx{0}; row_idx < rows; row_idx++) { {
for (uint8_t column_idx{0}; column_idx < columns; column_idx++) { for (uint8_t row_idx{0}; row_idx < rows; row_idx++)
{
for (uint8_t column_idx{0}; column_idx < columns; column_idx++)
{
this->matrix[row_idx * columns + column_idx] = value; this->matrix[row_idx * columns + column_idx] = value;
} }
} }
@@ -362,11 +428,14 @@ void Matrix<rows, columns>::Fill(float value) {
template <uint8_t rows, uint8_t columns> template <uint8_t rows, uint8_t columns>
Matrix<rows, columns> & Matrix<rows, columns> &
Matrix<rows, columns>::MatrixOfMinors(Matrix<rows, columns> &result) const { Matrix<rows, columns>::MatrixOfMinors(Matrix<rows, columns> &result) const
{
Matrix<rows - 1, columns - 1> MinorMatrix{}; Matrix<rows - 1, columns - 1> MinorMatrix{};
for (uint8_t row_idx{0}; row_idx < rows; row_idx++) { for (uint8_t row_idx{0}; row_idx < rows; row_idx++)
for (uint8_t column_idx{0}; column_idx < columns; column_idx++) { {
for (uint8_t column_idx{0}; column_idx < columns; column_idx++)
{
this->MinorMatrix(MinorMatrix, row_idx, column_idx); this->MinorMatrix(MinorMatrix, row_idx, column_idx);
result[row_idx][column_idx] = MinorMatrix.Det(); result[row_idx][column_idx] = MinorMatrix.Det();
} }
@@ -378,15 +447,20 @@ Matrix<rows, columns>::MatrixOfMinors(Matrix<rows, columns> &result) const {
template <uint8_t rows, uint8_t columns> template <uint8_t rows, uint8_t columns>
Matrix<rows - 1, columns - 1> & Matrix<rows - 1, columns - 1> &
Matrix<rows, columns>::MinorMatrix(Matrix<rows - 1, columns - 1> &result, Matrix<rows, columns>::MinorMatrix(Matrix<rows - 1, columns - 1> &result,
uint8_t row_idx, uint8_t column_idx) const { uint8_t row_idx, uint8_t column_idx) const
{
std::array<float, (rows - 1) * (columns - 1)> subArray{}; std::array<float, (rows - 1) * (columns - 1)> subArray{};
uint16_t array_idx{0}; uint16_t array_idx{0};
for (uint8_t row_iter{0}; row_iter < rows; row_iter++) { for (uint8_t row_iter{0}; row_iter < rows; row_iter++)
if (row_iter == row_idx) { {
if (row_iter == row_idx)
{
continue; continue;
} }
for (uint8_t column_iter{0}; column_iter < columns; column_iter++) { for (uint8_t column_iter{0}; column_iter < columns; column_iter++)
if (column_iter == column_idx) { {
if (column_iter == column_idx)
{
continue; continue;
} }
subArray[array_idx] = this->Get(row_iter, column_iter); subArray[array_idx] = this->Get(row_iter, column_iter);
@@ -400,9 +474,12 @@ Matrix<rows, columns>::MinorMatrix(Matrix<rows - 1, columns - 1> &result,
template <uint8_t rows, uint8_t columns> template <uint8_t rows, uint8_t columns>
Matrix<rows, columns> & Matrix<rows, columns> &
Matrix<rows, columns>::adjugate(Matrix<rows, columns> &result) const { Matrix<rows, columns>::adjugate(Matrix<rows, columns> &result) const
for (uint8_t row_iter{0}; row_iter < rows; row_iter++) { {
for (uint8_t column_iter{0}; column_iter < columns; column_iter++) { for (uint8_t row_iter{0}; row_iter < rows; row_iter++)
{
for (uint8_t column_iter{0}; column_iter < columns; column_iter++)
{
float sign = ((row_iter + 1) % 2) == 0 ? -1 : 1; float sign = ((row_iter + 1) % 2) == 0 ? -1 : 1;
sign *= ((column_iter + 1) % 2) == 0 ? -1 : 1; sign *= ((column_iter + 1) % 2) == 0 ? -1 : 1;
result[column_iter][row_iter] = this->Get(row_iter, column_iter) * sign; result[column_iter][row_iter] = this->Get(row_iter, column_iter) * sign;
@@ -414,16 +491,20 @@ Matrix<rows, columns>::adjugate(Matrix<rows, columns> &result) const {
template <uint8_t rows, uint8_t columns> template <uint8_t rows, uint8_t columns>
Matrix<rows, columns> & Matrix<rows, columns> &
Matrix<rows, columns>::Normalize(Matrix<rows, columns> &result) const { Matrix<rows, columns>::Normalize(Matrix<rows, columns> &result) const
{
float sum{0}; float sum{0};
for (uint8_t row_idx{0}; row_idx < rows; row_idx++) { for (uint8_t row_idx{0}; row_idx < rows; row_idx++)
for (uint8_t column_idx{0}; column_idx < columns; column_idx++) { {
for (uint8_t column_idx{0}; column_idx < columns; column_idx++)
{
float val{this->Get(row_idx, column_idx)}; float val{this->Get(row_idx, column_idx)};
sum += val * val; sum += val * val;
} }
} }
if (sum == 0) { if (sum == 0)
{
// this wouldn't do anything anyways // this wouldn't do anything anyways
result.Fill(1e+6); result.Fill(1e+6);
return result; return result;
@@ -431,8 +512,10 @@ Matrix<rows, columns>::Normalize(Matrix<rows, columns> &result) const {
sum = sqrt(sum); sum = sqrt(sum);
for (uint8_t row_idx{0}; row_idx < rows; row_idx++) { for (uint8_t row_idx{0}; row_idx < rows; row_idx++)
for (uint8_t column_idx{0}; column_idx < columns; column_idx++) { {
for (uint8_t column_idx{0}; column_idx < columns; column_idx++)
{
result[row_idx][column_idx] = this->Get(row_idx, column_idx) / sum; result[row_idx][column_idx] = this->Get(row_idx, column_idx) / sum;
} }
} }

View File

@@ -9,7 +9,9 @@
// TODO: Add a function for SVD decomposition // TODO: Add a function for SVD decomposition
// TODO: Add a function for LQ decomposition // TODO: Add a function for LQ decomposition
template <uint8_t rows, uint8_t columns> class Matrix { template <uint8_t rows, uint8_t columns>
class Matrix
{
public: public:
/** /**
* @brief create a matrix but leave all of its values unitialized * @brief create a matrix but leave all of its values unitialized
@@ -34,7 +36,8 @@ public:
/** /**
* @brief Initialize a matrix directly with any number of arguments * @brief Initialize a matrix directly with any number of arguments
*/ */
template <typename... Args> Matrix(Args... args); template <typename... Args>
Matrix(Args... args);
/** /**
* @brief Set all elements in this to value * @brief Set all elements in this to value
*/ */

103
Vector3D.cpp Normal file
View File

@@ -0,0 +1,103 @@
#ifdef MATRIX_H_ // since the .cpp file has to be included by the .hpp file this
// will evaluate to true
#include "Vector3D.hpp"
template <typename Type>
constexpr V3D<type>::V3D(const Matrix<1, 3> &other) : x(other[0][0]), y(other[0][1]), z(other[0][2]) {}
template <typename Type>
constexpr V3D<type>::V3D(const Matrix<3, 1> &other) : x(other[0][0]), y(other[1][0]), z(other[2][0]) {}
template <typename Type>
constexpr V3D<type>::V3D(const V3D &other) : x(other.x),
y(other.y),
z(other.z)
{
static_assert(std::is_arithmetic<Type>::value, "Type must be a number");
}
template <typename Type>
constexpr V3D<type>::V3D(Type x = 0, Type y = 0, Type z = 0) : x(x),
y(y),
z(z)
{
static_assert(std::is_arithmetic<Type>::value, "Type must be a number");
}
template <typename Type, typename OtherType>
constexpr V3D<type>::V3D(const V3D<OtherType> other) : x(static_cast<Type>(other.x)),
y(static_cast<Type>(other.y)),
z(static_cast<Type>(other.z))
{
static_assert(std::is_arithmetic<Type>::value, "Type must be a number");
static_assert(std::is_arithmetic<OtherType>::value, "OtherType must be a number");
}
template <typename Type>
std::array<Type, 3> V3D<type>::ToArray()
{
return {this->x, this->y, this->z};
}
template <typename Type>
V3D &V3D<type>::operator=(const V3D &other)
{
this->x = other.x;
this->y = other.y;
this->z = other.z;
return *this;
}
template <typename Type>
V3D &V3D<type>::operator+=(const V3D &other)
{
this->x += other.x;
this->y += other.y;
this->z += other.z;
return *this;
}
template <typename Type>
V3D &V3D<type>::operator-=(const V3D &other)
{
this->x -= other.x;
this->y -= other.y;
this->z -= other.z;
return *this;
}
template <typename Type>
V3D &V3D<type>::operator/=(const Type scalar)
{
if (scalar == 0)
{
return *this;
}
this->x /= scalar;
this->y /= scalar;
this->z /= scalar;
return *this;
}
template <typename Type>
V3D &V3D<type>::operator*=(const Type scalar)
{
this->x *= scalar;
this->y *= scalar;
this->z *= scalar;
return *this;
}
template <typename Type>
bool V3D<type>::operator==(const V3D &other)
{
return this->x == other.x && this->y == other.y && this->z == other.z;
}
template <typename Type>
float V3D<type>::magnitude()
{
return std::sqrt(static_cast<float>(this->x * this->x + this->y * this->y + this->z * this->z));
}
#endif // MATRIX_H_

View File

@@ -1,81 +1,44 @@
#pragma once #ifndef VECTOR3D_H_
#define VECTOR3D_H_
#include <cstdint> #include <cstdint>
#include <cmath> #include <cmath>
#include <type_traits> #include <type_traits>
template <typename Type> #include "Matrix.hpp"
class V3D{
public:
constexpr V3D(const V3D& other):
x(other.x),
y(other.y),
z(other.z){
static_assert(std::is_arithmetic<Type>::value, "Type must be a number");
}
constexpr V3D(Type x=0, Type y=0, Type z=0): template <typename Type>
x(x), class V3D
y(y), {
z(z){ public:
static_assert(std::is_arithmetic<Type>::value, "Type must be a number"); constexpr V3D(const Matrix<1, 3> &other);
} constexpr V3D(const Matrix<3, 1> &other);
constexpr V3D(const V3D &other);
constexpr V3D(Type x = 0, Type y = 0, Type z = 0);
template <typename OtherType> template <typename OtherType>
constexpr V3D(const V3D<OtherType> other): constexpr V3D(const V3D<OtherType> other);
x(static_cast<Type>(other.x)),
y(static_cast<Type>(other.y)),
z(static_cast<Type>(other.z)){
static_assert(std::is_arithmetic<Type>::value, "Type must be a number");
static_assert(std::is_arithmetic<OtherType>::value, "OtherType must be a number");
}
V3D& operator=(const V3D &other){ std::array<Type, 3> ToArray();
this->x = other.x;
this->y = other.y;
this->z = other.z;
return *this;
}
V3D& operator+=(const V3D &other){ V3D &operator=(const V3D &other);
this->x += other.x;
this->y += other.y;
this->z += other.z;
return *this;
}
V3D& operator-=(const V3D &other){ V3D &operator+=(const V3D &other);
this->x -= other.x;
this->y -= other.y;
this->z -= other.z;
return *this;
}
V3D& operator/=(const Type scalar){ V3D &operator-=(const V3D &other);
if(scalar == 0){
return *this;
}
this->x /= scalar;
this->y /= scalar;
this->z /= scalar;
return *this;
}
V3D& operator*=(const Type scalar){ V3D &operator/=(const Type scalar);
this->x *= scalar;
this->y *= scalar;
this->z *= scalar;
return *this;
}
bool operator==(const V3D &other){ V3D &operator*=(const Type scalar);
return this->x == other.x && this->y == other.y && this->z == other.z;
}
float magnitude(){ bool operator==(const V3D &other);
return std::sqrt(static_cast<float>(this->x * this->x + this->y * this->y + this->z * this->z));
} float magnitude();
Type x; Type x;
Type y; Type y;
Type z; Type z;
}; };
#endif // VECTOR3D_H_

View File

@@ -7,7 +7,7 @@ include(FetchContent)
FetchContent_Declare( FetchContent_Declare(
Catch2 Catch2
GIT_REPOSITORY https://github.com/catchorg/Catch2.git GIT_REPOSITORY https://github.com/catchorg/Catch2.git
GIT_TAG v3.0.1 # or a later release GIT_TAG v3.8.0 # or a later release
) )
FetchContent_MakeAvailable(Catch2) FetchContent_MakeAvailable(Catch2)
@@ -16,6 +16,6 @@ add_executable(matrix-tests matrix-tests.cpp)
target_link_libraries(matrix-tests target_link_libraries(matrix-tests
PRIVATE PRIVATE
Matrix vector-3d-intf
Catch2::Catch2WithMain Catch2::Catch2WithMain
) )