Files
INS-VN-200/vnproglib/cpp/include/vn/matrix.h
r.koeppe 2d22ccd2d6 initial
2024-05-14 02:14:13 +02:00

1678 lines
37 KiB
C++

/// \file
/// {COMMON_HEADER}
///
/// \section DESCRIPTION
/// This header file provides may types for working with matrices.
#ifndef _VN_MATH_MAT_H_
#define _VN_MATH_MAT_H_
#include <cassert>
#include <iostream>
#include "vector.h"
#include "exceptions.h"
namespace vn {
namespace math {
/// \brief Template for a matrix.
template <size_t m, size_t n = m, typename T = float>
struct mat
{
// Public Members /////////////////////////////////////////////////////////
public:
/// \brief The matrix's elements.
union
{
T e[m * n];
};
// Constructors ///////////////////////////////////////////////////////////
public:
/// \brief Creates a new matrix with uninitialized elements.
mat() { }
/// \brief Creates a new matrix with ints elements initialized to val.
///
/// \param[in] val The initialization value.
explicit mat(T val)
{
std::fill_n(e, m * n, val);
}
// Helper Methods /////////////////////////////////////////////////////////
public:
/// \brief Matrix with all of its elements set to 0.
///
/// \return The 0 matrix.
static mat zero()
{
return mat<m, n, T>(0);
}
/// \brief Matrix with all of its elements set to 1.
///
/// \return The 1 matrix.
static mat one()
{
return mat<m, n, T>(1);
}
/// \brief Identity matrix with its diagonal elements set to 1.
///
/// \return The identity matrix.
static mat<m, m, T> identity()
{
assert(m == n);
mat<m, m, T> nm(0);
for (size_t i = 0; i < m; i++)
nm.e[i * m + i] = 1;
return nm;
}
// Operator Overloads /////////////////////////////////////////////////////
public:
/// \brief Indexing into the matrix's elements.
///
/// \param[in] row The 0-based index row.
/// \param[in] col The 0-based index column.
/// \return The requested element.
T& operator()(size_t row, size_t col)
{
return const_cast<T&>(static_cast<const mat&>(*this)(row, col));
}
/// \brief Indexing into the matrix's elements.
///
/// \param[in] row The 0-based index row.
/// \param[in] col The 0-based index column.
/// \return The requested element.
const T& operator()(size_t row, size_t col) const
{
assert(row < m && col < n);
//return e[col * m + row];
return e[col + row * m];
}
/// \brief Negates the matrix.
///
/// \return The negated matrix.
mat operator-() const
{
return neg();
}
/// \brief Multiplies the matrix by a scalar.
///
/// \param[in] rhs The scalar.
/// \return The multiplied matrix.
template<typename S>
mat& operator*=(const S& rhs)
{
for (size_t i = 0; i < m*n; i++)
e[i] *= rhs;
return *this;
}
/// \brief Multiplies the matrix by another matrix
///
/// \param[in] rhs The other matrix.
/// \return The multiplied matrix.
template<size_t r, size_t s, typename S>
mat& operator*(const mat<r, s, S>& rhs)
{
// columns from the matrix must match rows of the input matrix
if (m != s)
{
return *this;
}
size_t row = 0;
size_t col = 0;
size_t cell = 0;
mat<r, n, T> return_mat = zero();
// Remember, this matrix is stored in column order
for (size_t row_index = 0; row_index < r; row_index++)
{
for (size_t col_index = 0; col_index < n; col_index++)
{
cell = row_index + (col_index * r);
for (size_t cell_index = 0; cell_index < m; cell_index++)
{
// calculated for the cell in the current row
row = (col_index * m) + cell_index;
// calculated for the cell in the current column
col = (cell_index * r) + row_index;
return_mat.e[cell] += this->e[row] * rhs.e[col];
}
}
}
return return_mat;
}
/// \brief Divides the matrix by a scalar.
///
/// \param[in] rhs The scalar.
/// \return The divided matrix.
template<typename S>
mat& operator/=(const T & rhs)
{
for (size_t i = 0; i < m*n; i++)
e[i] /= rhs;
return *this;
}
/// \brief Adds a matrix to this matrix.
///
/// \param[in] rhs The right-side vector.
/// \return The resulting vector.
template<typename S>
mat& operator+=(const mat<m, n, S>& rhs)
{
for (size_t i = 0; i < m*n; i++)
e[i] += rhs.e[i];
return *this;
}
/// \brief Subtracts a matrix from this matrix.
///
/// \param[in] rhs The right-side matrix.
/// \return The resulting matrix.
template<typename S>
mat& operator-=(const mat<m, n, S>& rhs)
{
for (size_t i = 0; i < m*n; i++)
e[i] -= rhs.e[i];
return *this;
}
// Public Methods /////////////////////////////////////////////////////////
public:
/// \brief The matrix's row dimension.
///
/// \return The matrix's row dimension.
size_t dimRow() const { return m; }
/// \brief The matrix's column dimension.
///
/// \return The matrix's column dimension.
size_t dimCol() const { return n; }
/// \brief Negates the matrix.
///
/// \return The negated matrix.
mat neg() const
{
mat nm;
for (size_t i = 0; i < m * n; i++)
nm.e[i] = -e[i];
return nm;
}
/// \brief Multiplies the matrix by a scalar.
///
/// \param[in] scalar The scalar value.
/// \return The multiplied matrix.
mat mult(const double& scalar) const
{
mat nm;
for (size_t i = 0; i < m*n; i++)
nm.e[i] = e[i] * scalar;
return nm;
}
/// \brief Divides the matrix by a scalar.
///
/// \param[in] scalar The scalar value.
/// \return The divided matrix.
mat div(const double& scalar) const
{
mat nm;
for (size_t i = 0; i < m*n; i++)
nm.e[i] = e[i] / scalar;
return nm;
}
/// \brief Adds a matrix to this matrix.
///
/// \param[in] toAdd The matrix to add.
/// \return The resulting matrix.
mat add(const mat& toAdd) const
{
mat nm;
for (size_t i = 0; i < m*n; i++)
nm.e[i] = e[i] + toAdd.e[i];
return nm;
}
/// \brief Subtracts a matrix from this matrix.
///
/// \param[in] toSub The matrix to subtract from this.
/// \return The resulting matrix.
mat sub(const mat& toSub) const
{
mat nm;
for (size_t i = 0; i < m*n; i++)
nm.e[i] = e[i] - toSub.e[i];
return nm;
}
/// \brief Transposes the matrix.
///
/// \return The computed transpose.
mat<n, m, T> transpose() const
{
mat<n, m, T> nm;
for (size_t row = 0; row < m; row++)
{
for (size_t col = 0; col < n; col++)
{
nm.e[row * n + col] = e[col * m + row];
}
}
return nm;
}
};
// Specializations ////////////////////////////////////////////////////////////
#if defined(_MSC_VER)
#pragma warning(push)
// Disable warning about 'nonstandard extension used : nameless struct/union'.
#pragma warning(disable:4201)
#endif
/// \brief 2x2 matrix specialization.
template <typename T>
struct mat<2, 2, T>
{
// Public Members /////////////////////////////////////////////////////////
public:
union
{
struct
{
/// \brief Element 0,0.
T e00;
/// \brief Element 1,0.
T e10;
/// \brief Element 0,1.
T e01;
/// \brief Element 1,1.
T e11;
};
/// \brief The matrix's elements.
T e[2 * 2];
};
// Constructors ///////////////////////////////////////////////////////////
public:
/// \brief Creates a new matrix with uninitialized elements.
mat() { }
/// \brief Creates a new matrix with its elements initialized to val.
///
/// \param[in] val The initialization value.
explicit mat(T val) :
e00(val), e10(val),
e01(val), e11(val)
{ }
/// \brief Creates a new matrix with its components initialized to the
/// provided values.
///
/// \param[in] e00v Element 0,0 value.
/// \param[in] e01v Element 0,1 value.
/// \param[in] e10v Element 1,0 value.
/// \param[in] e11v Element 1,1 value.
mat(T e00v, T e01v,
T e10v, T e11v) :
e00(e00v), e10(e10v),
e01(e01v), e11(e11v)
{ }
/// \brief Constructs a matrix from 4 column vectors.
///
/// \param[in] col0 The 0 column vector.
/// \param[in] col1 The 1 column vector.
/// \param[in] col2 The 2 column vector.
/// \param[in] col3 The 3 column vector.
mat(vec<2, T> col0, vec<2, T> col1) :
e00(col0.x), e10(col1.x),
e01(col0.y), e11(col1.y)
{}
// Helper Methods /////////////////////////////////////////////////////////
public:
/// \brief Matrix with all of its elements set to 0.
///
/// \return The 0 matrix.
static mat zero()
{
return mat<2, 2, T>(0);
}
/// \brief Matrix with all of its elements set to 1.
///
/// \return The 1 matrix.
static mat one()
{
return mat<2, 2, T>(1);
}
/// \brief Identity matrix with its diagonal elements set to 1.
///
/// \return The identity matrix.
static mat<2, 2, T> identity()
{
return mat<2, 2, T>(
1, 0,
0, 1);
}
// Operator Overloads /////////////////////////////////////////////////////
public:
/// \brief Indexing into the matrix's elements.
///
/// \param[in] row The 0-based index row.
/// \param[in] col The 0-based index column.
/// \return The requested element.
T& operator()(size_t row, size_t col)
{
return const_cast<T&>(static_cast<const mat&>(*this)(row, col));
}
/// \brief Indexing into the matrix's elements.
///
/// \param[in] row The 0-based index row.
/// \param[in] col The 0-based index column.
/// \return The requested element.
const T& operator()(size_t row, size_t col) const
{
assert(row < 2 && col < 2);
return e[col * 2 + row];
}
/// \brief Negates the matrix.
///
/// \return The negated matrix.
mat operator-() const
{
return neg();
}
/// \brief Multiplies the matrix by a scalar.
///
/// \param[in] rhs The scalar.
/// \return The multiplied matrix.
template<typename S>
mat& operator*=(const S& rhs)
{
#if defined(_MSC_VER)
#pragma warning(push)
// The operator*= throws a warning when a mat*f is multiplied by a mat*d.
#pragma warning(disable:4244)
#endif
for (size_t i = 0; i < 2 * 2; i++)
e[i] *= rhs;
#if defined (_MSC_VER)
#pragma warning(pop)
#endif
return *this;
}
/// \brief Multiplies the matrix by another matrix.
///
/// \param[in] rhs The other matrix.
/// \return The multiplied matrix.
template<typename S>
mat& operator*=(const mat<2, 2, S>& rhs)
{
size_t row = 0;
size_t col = 0;
size_t cell = 0;
mat<2, 2, T> return_mat = zero();
// Remember, this matrix is stored in column order
for (size_t row_index = 0; row_index < 2; row_index++)
{
for (size_t col_index = 0; col_index < 2; col_index++)
{
cell = row_index + (col_index * 2);
for (size_t cell_index = 0; cell_index < 2; cell_index++)
{
// calculated for the cell in the current row
row = row_index + (cell_index * 2);
// calculated for the cell in the current column
col = cell_index + (col_index * 2);
return_mat.e[cell] += this->e[row] * rhs.e[col];
}
}
}
*this = return_mat;
return *this;
}
/// \brief Divides the matrix by a scalar.
///
/// \param[in] rhs The scalar.
/// \return The divided matrix.
template<typename S>
mat& operator/=(const S& rhs)
{
#if defined(_MSC_VER)
#pragma warning(push)
// The operator/= throws a warning when a mat*f is divided by a double.
#pragma warning(disable:4244)
#endif
for (size_t i = 0; i < 2 * 2; i++)
e[i] /= rhs;
#if defined (_MSC_VER)
#pragma warning(pop)
#endif
return *this;
}
/// \brief Adds a matrix to this matrix.
///
/// \param[in] rhs The right-side vector.
/// \return The resulting vector.
template<typename S>
mat& operator+=(const mat<2, 2, S>& rhs)
{
for (size_t i = 0; i < 2 * 2; i++)
e[i] += rhs.e[i];
return *this;
}
/// \brief Subtracts a matrix from this matrix.
///
/// \param[in] rhs The right-side matrix.
/// \return The resulting matrix.
template<typename S>
mat& operator-=(const mat<2, 2, S>& rhs)
{
for (size_t i = 0; i < 2 * 2; i++)
e[i] -= rhs.e[i];
return *this;
}
// Public Methods /////////////////////////////////////////////////////////
public:
/// \brief The matrix's row dimension.
///
/// \return The matrix's row dimension.
size_t dimRow() const { return 2; }
/// \brief The matrix's column dimension.
///
/// \return The matrix's column dimension.
size_t dimCol() const { return 2; }
template<typename S>
void copy(const mat<2, 2, S> rhs)
{
*this = rhs;
}
/// \brief Negates the matrix.
///
/// \return The negated matrix.
mat neg() const
{
mat nm;
for (size_t i = 0; i < 2 * 2; i++)
nm.e[i] = -e[i];
return nm;
}
/// \brief Multiplies the matrix by a scalar.
///
/// \param[in] scalar The scalar value.
/// \return The multiplied matrix.
mat mult(const double& scalar) const
{
mat nm;
for (size_t i = 0; i < 2 * 2; i++)
nm.e[i] = e[i] * scalar;
return nm;
}
/// \brief Divides the matrix by a scalar.
///
/// \param[in] scalar The scalar value.
/// \return The divided matrix.
mat div(const double& scalar) const
{
mat nm;
for (size_t i = 0; i < 2 * 2; i++)
nm.e[i] = e[i] / scalar;
return nm;
}
/// \brief Adds a matrix to this matrix.
///
/// \param[in] toAdd The matrix to add.
/// \return The resulting matrix.
mat add(const mat& toAdd) const
{
mat nm;
for (size_t i = 0; i < 2 * 2; i++)
nm.e[i] = e[i] + toAdd.e[i];
return nm;
}
/// \brief Subtracts a matrix from this matrix.
///
/// \param[in] toSub The matrix to subtract from this.
/// \return The resulting matrix.
mat sub(const mat& toSub) const
{
mat nm;
for (size_t i = 0; i < 2 * 2; i++)
nm.e[i] = e[i] - toSub.e[i];
return nm;
}
/// \brief Transposes the matrix.
///
/// \return The computed transpose.
mat<2, 2, T> transpose() const
{
mat<2, 2, T> nm;
for (size_t row = 0; row < 2; row++)
{
for (size_t col = 0; col < 2; col++)
{
nm.e[row * 2 + col] = e[col * 2 + row];
}
}
return nm;
}
};
/// \brief 3x3 matrix specialization.
/// \brief matrix is column ordered in memory
template <typename T>
struct mat<3, 3, T>
{
// Public Members /////////////////////////////////////////////////////////
public:
union
{
struct
{
/// \brief Element 0,0.
T e00;
/// \brief Element 1,0.
T e10;
/// \brief Element 2,0.
T e20;
/// \brief Element 0,1.
T e01;
/// \brief Element 1,1.
T e11;
/// \brief Element 2,1.
T e21;
/// \brief Element 0,2.
T e02;
/// \brief Element 1,2.
T e12;
/// \brief Element 2,2.
T e22;
};
/// \brief The matrix's elements.
T e[3 * 3];
};
// Constructors ///////////////////////////////////////////////////////////
public:
/// \brief Creates a new matrix with uninitialized elements.
mat() { }
/// \brief Creates a new matrix with its elements initialized to val.
///
/// \param[in] val The initialization value.
explicit mat(T val) :
e00(val), e10(val), e20(val),
e01(val), e11(val), e21(val),
e02(val), e12(val), e22(val)
{ }
/// \brief Creates a new matrix with its components intialized to the
/// provided values.
///
/// \param[in] e00v Element 0,0 value.
/// \param[in] e01v Element 0,1 value.
/// \param[in] e02v Element 0,2 value.
/// \param[in] e10v Element 1,0 value.
/// \param[in] e11v Element 1,1 value.
/// \param[in] e12v Element 1,2 value.
/// \param[in] e20v Element 2,0 value.
/// \param[in] e21v Element 2,1 value.
/// \param[in] e22v Element 2,2 value.
mat(T e00v, T e01v, T e02v,
T e10v, T e11v, T e12v,
T e20v, T e21v, T e22v) :
e00(e00v), e10(e10v), e20(e20v),
e01(e01v), e11(e11v), e21(e21v),
e02(e02v), e12(e12v), e22(e22v)
{ }
/// \brief Constructs a matrix from 3 column vectors. Vectors are stored in column order
///
/// \param[in] col0 The 0 column vector.
/// \param[in] col1 The 1 column vector.
/// \param[in] col2 The 2 column vector.
mat(vec<3, T> col0, vec<3, T> col1, vec<3, T> col2) :
e00(col0.x), e10(col0.y), e20(col0.z),
e01(col1.x), e11(col1.y), e21(col1.z),
e02(col2.x), e12(col2.y), e22(col2.z)
{
}
// Helper Methods /////////////////////////////////////////////////////////
public:
/// \brief Matrix with all of its elements set to 0.
///
/// \return The 0 matrix.
static mat zero()
{
return mat<3, 3, T>(0);
}
/// \brief Matrix with all of its elements set to 1.
///
/// \return The 1 matrix.
static mat one()
{
return mat<3, 3, T>(1);
}
/// \brief Identity matrix with its diagonal elements set to 1.
///
/// \return The identity matrix.
static mat<3, 3, T> identity()
{
return mat<3, 3, T>(
1, 0, 0,
0, 1, 0,
0, 0, 1);
}
// Operator Overloads /////////////////////////////////////////////////////
public:
/// \brief Indexing into the matrix's elements.
///
/// \param[in] row The 0-based index row.
/// \param[in] col The 0-based index column.
/// \return The requested element.
T& operator()(size_t row, size_t col)
{
return const_cast<T&>(static_cast<const mat&>(*this)(row, col));
}
/// \brief Indexing into the matrix's elements.
///
/// \param[in] row The 0-based index row.
/// \param[in] col The 0-based index column.
/// \return The requested element.
const T& operator()(size_t row, size_t col) const
{
assert(row < 3 && col < 3);
return e[col * 3 + row];
}
/// \brief Negates the matrix.
///
/// \return The negated matrix.
mat operator-() const
{
return neg();
}
/// \brief Multiplies the matrix by a scalar.
///
/// \param[in] rhs The scalar.
/// \return The multiplied matrix.
template<typename S>
mat& operator*=(const S& rhs)
{
#if defined(_MSC_VER)
#pragma warning(push)
// The operator*= throws a warning when a mat*f is multiplied by a mat*d.
#pragma warning(disable:4244)
#endif
for (size_t i = 0; i < 3 * 3; i++)
e[i] *= rhs;
#if defined (_MSC_VER)
#pragma warning(pop)
#endif
return *this;
}
/// \brief Multiplies the matrix by another matrix.
///
/// \param[in] rhs The other matrix.
/// \return The multiplied matrix.
template<typename S>
mat& operator*=(const mat<3, 3, S>& rhs)
{
size_t counter = 0;
size_t row = 0;
size_t col = 0;
size_t cell = 0;
mat<3, 3, T> return_mat = zero();
// Remember, this matrix is stored in column order
for(size_t row_index = 0; row_index < 3; row_index++)
{
for(size_t col_index = 0; col_index < 3; col_index++)
{
cell = row_index + (col_index * 3);
for (size_t cell_index = 0; cell_index < 3; cell_index++)
{
// calculated for the cell in the current row
row = row_index + (cell_index * 3);
// calculated for the cell in the current column
col = cell_index + (col_index * 3);
return_mat.e[cell] += this->e[row] * rhs.e[col];
}
}
}
// std::copy(return_mat.e[0], return_mat.e[8], this->e[0]);
// std::copy(return_mat.e, return_mat.e + 7, this->e);
*this = return_mat;
return *this;
}
/// \brief Divides the matrix by a scalar.
///
/// \param[in] rhs The scalar.
/// \return The divided matrix.
template<typename S>
mat& operator/=(const S & rhs)
{
#if defined(_MSC_VER)
#pragma warning(push)
// The operator/= throws a warning when a mat*f is divided by a double.
#pragma warning(disable:4244)
#endif
for (size_t i = 0; i < 3 * 3; i++)
e[i] /= rhs;
#if defined (_MSC_VER)
#pragma warning(pop)
#endif
return *this;
}
/// \brief Adds a matrix to this matrix.
///
/// \param[in] rhs The right-side vector.
/// \return The resulting vector.
template<typename S>
mat& operator+=(const mat<3, 3, S>& rhs)
{
for (size_t i = 0; i < 3 * 3; i++)
e[i] += rhs.e[i];
return *this;
}
/// \brief Subtracts a matrix from this matrix.
///
/// \param[in] rhs The right-side matrix.
/// \return The resulting matrix.
template<typename S>
mat& operator-=(const mat<3, 3, S>& rhs)
{
for (size_t i = 0; i < 3 * 3; i++)
e[i] -= rhs.e[i];
return *this;
}
// Public Methods /////////////////////////////////////////////////////////
public:
/// \brief The matrix's row dimension.
///
/// \return The matrix's row dimension.
size_t dimRow() const { return 3; }
/// \brief The matrix's column dimension.
///
/// \return The matrix's column dimension.
size_t dimCol() const { return 3; }
size_t dimCols() const { return 3; }
template<typename S>
void copy(const mat<3, 3, S>& rhs)
{
*this = rhs;
}
/// \brief Negates the matrix.
///
/// \return The negated matrix.
mat neg() const
{
mat nm;
for (size_t i = 0; i < 3 * 3; i++)
nm.e[i] = -e[i];
return nm;
}
/// \brief Multiplies the matrix by a scalar.
///
/// \param[in] scalar The scalar value.
/// \return The multiplied matrix.
mat mult(const double& scalar) const
{
mat nm;
for (size_t i = 0; i < 3 * 3; i++)
nm.e[i] = e[i] * scalar;
return nm;
}
/// \brief Divides the matrix by a scalar.
///
/// \param[in] scalar The scalar value.
/// \return The divided matrix.
mat div(const double& scalar) const
{
mat nm;
for (size_t i = 0; i < 3 * 3; i++)
nm.e[i] = e[i] / scalar;
return nm;
}
/// \brief Adds a matrix to this matrix.
///
/// \param[in] toAdd The matrix to add.
/// \return The resulting matrix.
mat add(const mat& toAdd) const
{
mat nm;
for (size_t i = 0; i < 3 * 3; i++)
nm.e[i] = e[i] + toAdd.e[i];
return nm;
}
/// \brief Subtracts a matrix from this matrix.
///
/// \param[in] toSub The matrix to subtract from this.
/// \return The resulting matrix.
mat sub(const mat& toSub) const
{
mat nm;
for (size_t i = 0; i < 3 * 3; i++)
nm.e[i] = e[i] - toSub.e[i];
return nm;
}
/// \brief Transposes the matrix.
///
/// \return The computed transpose.
mat<3, 3, T> transpose() const
{
mat<3, 3, T> nm;
for (size_t row = 0; row < 3; row++)
{
for (size_t col = 0; col < 3; col++)
{
nm.e[row * 3 + col] = e[col * 3 + row];
}
}
return nm;
}
};
/// \brief 4x4 matrix specialization.
template <typename T>
struct mat<4, 4, T>
{
// Public Members /////////////////////////////////////////////////////////
public:
union
{
struct
{
/// \brief Element 0,0.
T e00;
/// \brief Element 1,0.
T e10;
/// \brief Element 2,0.
T e20;
/// \brief Element 3,0.
T e30;
/// \brief Element 0,1.
T e01;
/// \brief Element 1,1.
T e11;
/// \brief Element 2,1.
T e21;
/// \brief Element 3,1.
T e31;
/// \brief Element 0,2.
T e02;
/// \brief Element 1,2.
T e12;
/// \brief Element 2,2.
T e22;
/// \brief Element 3,2.
T e32;
/// \brief Element 0,3.
T e03;
/// \brief Element 1,3.
T e13;
/// \brief Element 2,3.
T e23;
/// \brief Element 3,3.
T e33;
};
/// \brief The matrix's elements.
T e[4*4];
};
// Constructors ///////////////////////////////////////////////////////////
public:
/// \brief Creates a new matrix with uninitialized elements.
mat() { }
/// \brief Creates a new matrix with its elements initialized to val.
///
/// \param[in] val The initialization value.
explicit mat(T val) :
e00(val), e01(val), e02(val), e03(val),
e10(val), e11(val), e12(val), e13(val),
e20(val), e21(val), e22(val), e23(val),
e30(val), e31(val), e32(val), e33(val)
{ }
/// \brief Creates a new matrix with its components intialized to the
/// provided values.
///
/// \param[in] e00v Element 0,0 value.
/// \param[in] e01v Element 0,1 value.
/// \param[in] e02v Element 0,2 value.
/// \param[in] e03v Element 0,3 value.
/// \param[in] e10v Element 1,0 value.
/// \param[in] e11v Element 1,1 value.
/// \param[in] e12v Element 1,2 value.
/// \param[in] e13v Element 1,3 value.
/// \param[in] e20v Element 2,0 value.
/// \param[in] e21v Element 2,1 value.
/// \param[in] e22v Element 2,2 value.
/// \param[in] e23v Element 2,3 value.
/// \param[in] e30v Element 3,0 value.
/// \param[in] e31v Element 3,1 value.
/// \param[in] e32v Element 3,2 value.
/// \param[in] e33v Element 3,3 value.
mat(T e00v, T e01v, T e02v, T e03v,
T e10v, T e11v, T e12v, T e13v,
T e20v, T e21v, T e22v, T e23v,
T e30v, T e31v, T e32v, T e33v) :
e00(e00v), e01(e01v), e02(e02v), e03(e03v),
e10(e10v), e11(e11v), e12(e12v), e13(e13v),
e20(e20v), e21(e21v), e22(e22v), e23(e23v),
e30(e30v), e31(e31v), e32(e32v), e33(e33v)
{ }
/// \brief Constructs a matrix from 4 column vectors.
///
/// \param[in] col0 The 0 column vector.
/// \param[in] col1 The 1 column vector.
/// \param[in] col2 The 2 column vector.
/// \param[in] col3 The 3 column vector.
mat(vec<4, T> col0, vec<4, T> col1, vec<4, T> col2, vec<4, T> col3) :
e00(col0.x), e10(col1.x), e20(col2.x), e30(col3.x),
e01(col0.y), e11(col1.y), e21(col2.y), e31(col3.y),
e02(col0.z), e12(col1.z), e22(col2.z), e32(col3.z),
e03(col0.w), e13(col1.w), e23(col2.w), e33(col3.w)
{
}
// Helper Methods /////////////////////////////////////////////////////////
public:
/// \brief Matrix with all of its elements set to 0.
///
/// \return The 0 matrix.
static mat zero()
{
return mat<4, 4, T>(0);
}
/// \brief Matrix with all of its elements set to 1.
///
/// \return The 1 matrix.
static mat one()
{
return mat<4, 4, T>(1);
}
/// \brief Identity matrix with its diagonal elements set to 1.
///
/// \return The identity matrix.
static mat<4, 4, T> identity()
{
return mat<4, 4, T>(1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1);
}
// Operator Overloads /////////////////////////////////////////////////////
public:
/// \brief Indexing into the matrix's elements.
///
/// \param[in] row The 0-based index row.
/// \param[in] col The 0-based index column.
/// \return The requested element.
T& operator()(size_t row, size_t col)
{
return const_cast<T&>(static_cast<const mat&>(*this)(row, col));
}
/// \brief Indexing into the matrix's elements.
///
/// \param[in] row The 0-based index row.
/// \param[in] col The 0-based index column.
/// \return The requested element.
const T& operator()(size_t row, size_t col) const
{
assert(row < 4 && col < 4);
return e[col * 4 + row];
}
/// \brief Negates the matrix.
///
/// \return The negated matrix.
mat operator-() const
{
return neg();
}
/// \brief Multiplies the matrix by a scalar.
///
/// \param[in] rhs The scalar.
/// \return The multiplied matrix.
template<typename S>
mat& operator*=(const S& rhs)
{
#if defined(_MSC_VER)
#pragma warning(push)
// The operator*= throws a warning when a mat*f is multiplied by a mat*d.
#pragma warning(disable:4244)
#endif
for (size_t i = 0; i < 4 * 4; i++)
e[i] *= rhs;
#if defined (_MSC_VER)
#pragma warning(pop)
#endif
return *this;
}
/// \brief Multiplies the matrix by another matrix.
///
/// \param[in] rhs The other matrix.
/// \return The multiplied matrix.
template<typename S>
mat& operator*=(const mat<4, 4, S>& rhs)
{
size_t row = 0;
size_t col = 0;
size_t cell = 0;
mat<4, 4, T> return_mat = zero();
// Remember, this matrix is stored in column order
for (size_t row_index = 0; row_index < 4; row_index++)
{
for (size_t col_index = 0; col_index < 4; col_index++)
{
cell = row_index + (col_index * 4);
for (size_t cell_index = 0; cell_index < 4; cell_index++)
{
// calculated for the cell in the current row
row = row_index + (cell_index * 4);
// calculated for the cell in the current column
col = cell_index + (col_index * 4);
return_mat.e[cell] += this->e[row] * rhs.e[col];
}
}
}
*this = return_mat;
return *this;
}
/// \brief Divides the matrix by a scalar.
///
/// \param[in] rhs The scalar.
/// \return The divided matrix.
template<typename S>
mat& operator/=(const S& rhs)
{
#if defined(_MSC_VER)
#pragma warning(push)
// The operator/= throws a warning when a mat*f is divided by a double.
#pragma warning(disable:4244)
#endif
for (size_t i = 0; i < 4 * 4; i++)
e[i] /= rhs;
#if defined (_MSC_VER)
#pragma warning(pop)
#endif
return *this;
}
/// \brief Adds a matrix to this matrix.
///
/// \param[in] rhs The right-side vector.
/// \return The resulting vector.
template<typename S>
mat& operator+=(const mat<4, 4, S>& rhs)
{
for (size_t i = 0; i < 4*4; i++)
e[i] += rhs.e[i];
return *this;
}
/// \brief Subtracts a matrix from this matrix.
///
/// \param[in] rhs The right-side matrix.
/// \return The resulting matrix.
template<typename S>
mat& operator-=(const mat<4, 4, S>& rhs)
{
for (size_t i = 0; i < 4*4; i++)
e[i] -= rhs.e[i];
return *this;
}
// Public Methods /////////////////////////////////////////////////////////
public:
/// \brief The matrix's row dimension.
///
/// \return The matrix's row dimension.
size_t dimRow() const { return 4; }
/// \brief The matrix's column dimension.
///
/// \return The matrix's column dimension.
size_t dimCol() const { return 4; }
template<typename S>
void copy(const mat<4, 4, S>& rhs)
{
*this = rhs;
}
/// \brief Negates the matrix.
///
/// \return The negated matrix.
mat neg() const
{
mat nm;
for (size_t i = 0; i < 4 * 4; i++)
nm.e[i] = -e[i];
return nm;
}
/// \brief Multiplies the matrix by a scalar.
///
/// \param[in] scalar The scalar value.
/// \return The multiplied matrix.
mat mult(const double& scalar) const
{
mat nm;
for (size_t i = 0; i < 4*4; i++)
nm.e[i] = e[i] * scalar;
return nm;
}
//mat mult(const mat& rhs)
/// \brief Divides the matrix by a scalar.
///
/// \param[in] scalar The scalar value.
/// \return The divided matrix.
mat div(const double& scalar) const
{
mat nm;
for (size_t i = 0; i < 4*4; i++)
nm.e[i] = e[i] / scalar;
return nm;
}
/// \brief Adds a matrix to this matrix.
///
/// \param[in] toAdd The matrix to add.
/// \return The resulting matrix.
mat add(const mat& toAdd) const
{
mat nm;
for (size_t i = 0; i < 4*4; i++)
nm.e[i] = e[i] + toAdd.e[i];
return nm;
}
/// \brief Subtracts a matrix from this matrix.
///
/// \param[in] toSub The matrix to subtract from this.
/// \return The resulting matrix.
mat sub(const mat& toSub) const
{
mat nm;
for (size_t i = 0; i < 4*4; i++)
nm.e[i] = e[i] - toSub.e[i];
return nm;
}
/// \brief Transposes the matrix.
///
/// \return The computed transpose.
mat<4, 4, T> transpose() const
{
mat<4, 4, T> nm;
for (size_t row = 0; row < 4; row++)
{
for (size_t col = 0; col < 4; col++)
{
nm.e[row * 4 + col] = e[col * 4 + row];
}
}
return nm;
}
};
#if defined (_MSC_VER)
#pragma warning(pop)
#endif
// Operator Overloads /////////////////////////////////////////////////////////
/// \brief Multiplies a matrix by a scalar.
///
/// \param[in] lhs The matrix.
/// \param[in] rhs The scalar.
/// \return The result.
template <size_t m, size_t n, typename T, typename S>
mat<m, n, T> operator*(mat<m, n, T> lhs, const S& rhs)
{
lhs *= rhs;
return lhs;
}
/// \brief Multiplies a matrix by a scalar.
///
/// \param[in] lhs The scalar.
/// \param[in] rhs The matrix.
/// \return The result.
template <size_t m, size_t n, typename T, typename S>
mat<m, n, T> operator*(const S& lhs, mat<m, n, T> rhs)
{
rhs *= lhs;
return rhs;
}
/// \brief Multiplies two matrices together.
///
/// \param[in] lhs The left-side matrix.
/// \param[in] rhs The right-side matrix.
/// \return The result.
template <size_t m, size_t n, typename T, size_t r, size_t s, typename S>
mat<m, n, T> operator*(mat<m, n, T>&lhs, const mat<r, s, S>& rhs)
{
mat<m, n, T> tmp = lhs;
tmp *= rhs;
return tmp;
}
/// \brief Divides a matrix by a scalar.
///
/// \param[in] lhs The matrix.
/// \param[in] rhs The scalar.
/// \return The result.
template <size_t m, size_t n, typename T, typename S>
mat<m, n, T> operator/(mat<m, n, T> lhs, const S& rhs)
{
lhs /= rhs;
return lhs;
}
/// \brief Adds two matrices together.
///
/// \param[in] lhs The left-side matrix.
/// \param[in] rhs The right-side matrix.
/// \return The resulting matrix.
template <size_t m, size_t n, typename T, typename S>
mat<m, n, T> operator+(mat<m, n, T> lhs, const mat<m, n, S>& rhs)
{
lhs += rhs;
return lhs;
}
/// \brief Subtracts a matrix from another matrix.
///
/// \param[in] lhs The left-side matrix.
/// \param[in] rhs The right-side matrix.
/// \return The resulting matrix.
template <size_t m, size_t n, typename T, typename S>
mat<m, n, T> operator-(mat<m, n, T> lhs, const mat<m, n, S>& rhs)
{
lhs -= rhs;
return lhs;
}
// Specific Typedefs //////////////////////////////////////////////////////////
/// \brief 2x2 matrix using <c>float</c> as its underlying data type.
typedef mat<2> mat2;
/// \brief 3x3 matrix using <c>float</c> as its underlying data type.
typedef mat<3> mat3;
/// \brief 4x4 matrix using <c>float</c> as its underlying data type.
typedef mat<4> mat4;
/// \brief 2x2 matrix using <c>float</c> as its underlying data type.
typedef mat<2> mat22;
/// \brief 3x3 matrix using <c>float</c> as its underlying data type.
typedef mat<3> mat33;
/// \brief 4x4 matrix using <c>float</c> as its underlying data type.
typedef mat<4> mat44;
/// \brief 2x2 matrix using <c>float</c> as its underlying data type.
typedef mat<2, 2, float> mat2f;
/// \brief 3x3 matrix using <c>float</c> as its underlying data type.
typedef mat<3, 3, float> mat3f;
/// \brief 4x4 matrix using <c>float</c> as its underlying data type.
typedef mat<4, 4, float> mat4f;
/// \brief 2x2 matrix using <c>double</c> as its underlying data type.
typedef mat<2, 2, double> mat2d;
/// \brief 3x3 matrix using <c>double</c> as its underlying data type.
typedef mat<3, 3, double> mat3d;
/// \brief 4x4 matrix using <c>double</c> as its underlying data type.
typedef mat<4, 4, double> mat4d;
/// \brief 2x2 matrix using <c>long double</c> as its underlying data type.
typedef mat<2, 2, long double> mat2ld;
/// \brief 3x3 matrix using <c>long double</c> as its underlying data type.
typedef mat<3, 3, long double> mat3ld;
/// \brief 4x4 matrix using <c>long double</c> as its underlying data type.
typedef mat<4, 4, long double> mat4ld;
/// \brief 2x2 matrix using <c>float</c> as its underlying data type.
typedef mat<2, 2, float> mat22f;
/// \brief 3x3 matrix using <c>float</c> as its underlying data type.
typedef mat<3, 3, float> mat33f;
/// \brief 4x4 matrix using <c>float</c> as its underlying data type.
typedef mat<4, 3, float> mat44f;
/// \brief 2x2 matrix using <c>double</c> as its underlying data type.
typedef mat<2, 2, double> mat22d;
/// \brief 3x3 matrix using <c>double</c> as its underlying data type.
typedef mat<3, 3, double> mat33d;
/// \brief 4x4 matrix using <c>double</c> as its underlying data type.
typedef mat<4, 4, double> mat44d;
/// \brief 2x2 matrix using <c>long double</c> as its underlying data type.
typedef mat<2, 2, long double> mat22ld;
/// \brief 3x3 matrix using <c>long double</c> as its underlying data type.
typedef mat<3, 3, long double> mat33ld;
/// \brief 4x4 matrix using <c>long double</c> as its underlying data type.
typedef mat<4, 4, long double> mat44ld;
// Common functions for working with matrices.
/// \brief Provides a method to generate a representable string from a provided
/// matrix.
///
/// \param[in] m The matrix to convert to string.
/// \return The string representation.
template <size_t mDim, size_t nDim, typename T> std::string str(mat<mDim, nDim, T> m)
{
std::stringstream ss;
ss << "[";
for (size_t row_index = 0; row_index < m.dimRow(); row_index++)
{
ss << "(";
for (size_t col_index = 0; col_index < m.dimCol(); col_index++)
{
ss << m(row_index, col_index);
if (col_index + 1 < m.dimCol())
ss << "; ";
}
ss << ")";
}
ss << "]";
return ss.str();
}
/// \brief Overloads the ostream << operator for easy usage in displaying
/// matrices.
///
/// \param[in] out The ostream being output to.
/// \param[in] m The matrix to output to ostream.
/// \return Reference to the current ostream.
template <size_t mDim, size_t nDim, typename T> std::ostream& operator<<(std::ostream& out, mat<mDim, nDim, T> m)
{
out << str(m);
return out;
}
}
}
#endif