/// \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 #include #include "vector.h" #include "exceptions.h" namespace vn { namespace math { /// \brief Template for a matrix. template 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(0); } /// \brief Matrix with all of its elements set to 1. /// /// \return The 1 matrix. static mat one() { return mat(1); } /// \brief Identity matrix with its diagonal elements set to 1. /// /// \return The identity matrix. static mat identity() { assert(m == n); mat 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(static_cast(*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 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 mat& operator*(const mat& 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 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 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 mat& operator+=(const mat& 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 mat& operator-=(const mat& 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 transpose() const { mat 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 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(static_cast(*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 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 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 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 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 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 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 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(static_cast(*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 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 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 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 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 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 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 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(static_cast(*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 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 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 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 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 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 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 mat operator*(mat 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 mat operator*(const S& lhs, mat 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 mat operator*(mat&lhs, const mat& rhs) { mat 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 mat operator/(mat 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 mat operator+(mat lhs, const mat& 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 mat operator-(mat lhs, const mat& rhs) { lhs -= rhs; return lhs; } // Specific Typedefs ////////////////////////////////////////////////////////// /// \brief 2x2 matrix using float as its underlying data type. typedef mat<2> mat2; /// \brief 3x3 matrix using float as its underlying data type. typedef mat<3> mat3; /// \brief 4x4 matrix using float as its underlying data type. typedef mat<4> mat4; /// \brief 2x2 matrix using float as its underlying data type. typedef mat<2> mat22; /// \brief 3x3 matrix using float as its underlying data type. typedef mat<3> mat33; /// \brief 4x4 matrix using float as its underlying data type. typedef mat<4> mat44; /// \brief 2x2 matrix using float as its underlying data type. typedef mat<2, 2, float> mat2f; /// \brief 3x3 matrix using float as its underlying data type. typedef mat<3, 3, float> mat3f; /// \brief 4x4 matrix using float as its underlying data type. typedef mat<4, 4, float> mat4f; /// \brief 2x2 matrix using double as its underlying data type. typedef mat<2, 2, double> mat2d; /// \brief 3x3 matrix using double as its underlying data type. typedef mat<3, 3, double> mat3d; /// \brief 4x4 matrix using double as its underlying data type. typedef mat<4, 4, double> mat4d; /// \brief 2x2 matrix using long double as its underlying data type. typedef mat<2, 2, long double> mat2ld; /// \brief 3x3 matrix using long double as its underlying data type. typedef mat<3, 3, long double> mat3ld; /// \brief 4x4 matrix using long double as its underlying data type. typedef mat<4, 4, long double> mat4ld; /// \brief 2x2 matrix using float as its underlying data type. typedef mat<2, 2, float> mat22f; /// \brief 3x3 matrix using float as its underlying data type. typedef mat<3, 3, float> mat33f; /// \brief 4x4 matrix using float as its underlying data type. typedef mat<4, 3, float> mat44f; /// \brief 2x2 matrix using double as its underlying data type. typedef mat<2, 2, double> mat22d; /// \brief 3x3 matrix using double as its underlying data type. typedef mat<3, 3, double> mat33d; /// \brief 4x4 matrix using double as its underlying data type. typedef mat<4, 4, double> mat44d; /// \brief 2x2 matrix using long double as its underlying data type. typedef mat<2, 2, long double> mat22ld; /// \brief 3x3 matrix using long double as its underlying data type. typedef mat<3, 3, long double> mat33ld; /// \brief 4x4 matrix using long double 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 std::string str(mat 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 std::ostream& operator<<(std::ostream& out, mat m) { out << str(m); return out; } } } #endif