/* * Copyright (C) 2021 Christopher J. Howard * * This file is part of Antkeeper source code. * * Antkeeper source code is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Antkeeper source code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Antkeeper source code. If not, see . */ #ifndef ANTKEEPER_MATH_MATRIX_HPP #define ANTKEEPER_MATH_MATRIX_HPP #include "math/vector.hpp" #include #include #include #include #include #include namespace math { /** * *n* by *m* column-major matrix. * * @tparam T Matrix element data type. * @tparam N Number of columns. * @tparam M Number of rows. * * @see https://en.wikipedia.org/wiki/Row-_and_column-major_order */ template struct matrix { /// Matrix element data type. typedef T element_type; /// Number of matrix columns. static constexpr std::size_t column_count = N; /// Number of matrix rows. static constexpr std::size_t row_count = M; /// Number of matrix elements. static constexpr std::size_t element_count = column_count * row_count; /// Matrix column vector data type. typedef vector column_vector_type; /// Matrix row vector data type. typedef vector row_vector_type; /// Array of matrix column vectors. column_vector_type columns[column_count]; /** * Returns a reference to the column vector at a given index. * * @param i Index of a column vector. * * @return Reference to the column vector at index @p i. */ /// @{ constexpr inline column_vector_type& operator[](std::size_t i) noexcept { return columns[i]; } constexpr inline const column_vector_type& operator[](std::size_t i) const noexcept { return columns[i]; } constexpr inline column_vector_type& column(std::size_t i) noexcept { return columns[i]; } constexpr inline const column_vector_type& column(std::size_t i) const noexcept { return columns[i]; } /// @} /** * Returns a reference to the element at a given column-major index. * * @param i Column-major index of a matrix element. * * @return Reference to the element at column-major index @p i. */ /// @{ constexpr inline T& element(std::size_t i) noexcept { return columns[i / row_count][i % row_count]; } constexpr inline const T& element(std::size_t i) const noexcept { return columns[i / row_count][i % row_count]; } /// @} /// Returns a reference to the first column vector. /// @{ constexpr inline column_vector_type& front() noexcept { return columns[0]; } constexpr inline const column_vector_type& front() const noexcept { return columns[0]; } /// @} /// Returns a reference to the last column vector. /// @{ constexpr inline column_vector_type& back() noexcept { return elements[column_count - 1]; } constexpr inline const column_vector_type& back() const noexcept { return elements[column_count - 1]; } /// @} /** * Returns a pointer to the first element. * * @warning If matrix::element_type is not a POD type, elements may not be stored contiguously. */ /// @{ constexpr inline element_type* data() noexcept { return &columns[0][0]; }; constexpr inline const element_type* data() const noexcept { return &columns[0][0]; }; /// @} /// Returns an iterator to the first column vector. /// @{ constexpr inline column_vector_type* begin() noexcept { return columns; } constexpr inline const column_vector_type* begin() const noexcept { return columns; } constexpr inline const column_vector_type* cbegin() const noexcept { return columns; } /// @} /// Returns an iterator to the column vector following the last column vector. /// @{ constexpr inline column_vector_type* end() noexcept { return columns + column_count; } constexpr inline const column_vector_type* end() const noexcept { return columns + column_count; } constexpr inline const column_vector_type* cend() const noexcept { return columns + column_count; } /// @} /// Returns a reverse iterator to the first column vector of the reversed matrix. /// @{ constexpr inline std::reverse_iterator rbegin() noexcept { return std::reverse_iterator(columns + column_count); } constexpr inline std::reverse_iterator rbegin() const noexcept { return std::reverse_iterator(columns + column_count); } constexpr inline std::reverse_iterator crbegin() const noexcept { return std::reverse_iterator(columns + column_count); } /// @} /// Returns a reverse iterator to the column vector following the last column vector of the reversed matrix. /// @{ constexpr inline std::reverse_iterator rend() noexcept { return std::reverse_iterator(columns); } constexpr inline std::reverse_iterator rend() const noexcept { return std::reverse_iterator(columns); } constexpr inline std::reverse_iterator crend() const noexcept { return std::reverse_iterator(columns); } /// @} /// Returns the number of elements in the matrix. constexpr inline std::size_t size() const noexcept { return element_count; }; /// @private template constexpr inline matrix type_cast(std::index_sequence) const noexcept { return {vector(columns[I])...}; } /** * Type-casts the elements of this matrix using `static_cast`. * * @tparam U Target element type. * * @return Matrix containing the type-casted elements. */ template constexpr inline explicit operator matrix() const noexcept { return type_cast(std::make_index_sequence{}); } /// @private template constexpr inline matrix size_cast(std::index_sequence) const noexcept { if constexpr (O == M) return {((I < N) ? columns[I] : matrix::identity()[I]) ...}; else return {((I < N) ? vector(columns[I]) : matrix::identity()[I]) ...}; } /** * Size-casts this matrix to a matrix with different dimensions. Casting to greater dimensions causes new elements to be set to identity matrix elements. * * @tparam P Target number of columns. * @tparam O Target number of rows. * * @return *p* by *o* matrix. */ template constexpr inline explicit operator matrix() const noexcept { return size_cast(std::make_index_sequence

{}); } /// Returns a zero matrix, where every element is equal to zero. static constexpr matrix zero() noexcept { return {}; } /// @private template static constexpr inline matrix one(std::index_sequence) noexcept { //return {column_vector_type::one() ...}; // MSVC bug workaround (I must be referenced for parameter pack expansion) return {(I ? column_vector_type::one() : column_vector_type::one()) ...}; } /// Returns a matrix of ones, where every element is equal to one. static constexpr matrix one() noexcept { return one(std::make_index_sequence{}); } /// @private template static constexpr inline column_vector_type identity_column(std::size_t i, std::index_sequence) noexcept { return {(I == i ? T{1} : T{0}) ...}; } /// @private template static constexpr inline matrix identity(std::index_sequence) noexcept { return {identity_column(I, std::make_index_sequence{}) ...}; } /// Returns an identity matrix, with ones on the main diagonal and zeros elsewhere. static constexpr matrix identity() noexcept { return identity(std::make_index_sequence{}); } }; /// 2x2 matrix. template using matrix2 = matrix; /// 2x2 matrix. template using matrix2x2 = matrix; /// 3x3 matrix. template using matrix3 = matrix; /// 3x3 matrix. template using matrix3x3 = matrix; /// 4x4 matrix. template using matrix4 = matrix; /// 4x4 matrix. template using matrix4x4 = matrix; /** * Adds two matrices. * * @param a First matrix. * @param b Second matrix. * * @return Sum of the two matrices. */ template constexpr matrix add(const matrix& a, const matrix& b) noexcept; /** * Adds a matrix and a scalar. * * @param a Matrix. * @param b scalar. * * @return Sum of the matrix and scalar. */ template constexpr matrix add(const matrix& a, T b) noexcept; /** * Calculates the determinant of a square matrix. * * @param m Matrix of which to take the determinant. * * @return Determinant of @p m. * * @warning Currently only implemented for 2x2, 3x3, and 4x4 matrices. */ template constexpr T determinant(const matrix& m) noexcept; /** * Calculates the inverse of a square matrix. * * @param m Matrix of which to take the inverse. * * @return Inverse of matrix @p m. * * @warning Currently only implemented for 2x2, 3x3, and 4x4 matrices. */ template constexpr matrix inverse(const matrix& m) noexcept; /** * Performs a component-wise multiplication of two matrices. * * @param x First matrix multiplicand. * @param y Second matrix multiplicand. */ template constexpr matrix componentwise_mul(const matrix& a, const matrix& b) noexcept; /** * Divides a matrix by a matrix. * * @param a First matrix. * @param b Second matrix. * @return Result of the division. */ template constexpr matrix div(const matrix& a, const matrix& b) noexcept; /** * Divides a matrix by a scalar. * * @param a Matrix. * @param b Scalar. * @return Result of the division. */ template constexpr matrix div(const matrix& a, T b) noexcept; /** * Divides a scalar by a matrix. * * @param a Scalar. * @param b Matrix. * @return Result of the division. */ template constexpr matrix div(T a, const matrix& b) noexcept; /** * Creates a viewing transformation matrix. * * @param position Position of the view point. * @param target Position of the target. * @param up Normalized direction of the up vector. * @return Viewing transformation matrix. */ template constexpr matrix look_at(const vector& position, const vector& target, vector up); /** * Multiplies two matrices * * @tparam T Matrix element type. * @tparam N Number of columns in matrix @p a, and rows in matrix @p b. * @tparam M Number of rows in matrix @p a. * @tparam P Number of columns in matrix @p b. * * @param a First matrix. * @param b Second matrix. * * @return Product of `a * b`. */ template constexpr matrix mul(const matrix& a, const matrix& b) noexcept; /** * Multiplies a matrix by a scalar. * * @param a Matrix. * @param b Scalar. * @return Product of the matrix and the scalar. */ template constexpr matrix mul(const matrix& a, T b) noexcept; /** * Calculates the product of a matrix and a row vector. * * @param a Matrix. * @param b Row vector * * @return Product of the matrix and the row vector. */ template constexpr typename matrix::column_vector_type mul(const matrix& a, const typename matrix::row_vector_type& b) noexcept; /** * Calculates the product of a column vector and a matrix. * * @param a Column vector. * @param b Matrix. * * @return Product of the column vector and the matrix. */ template constexpr typename matrix::row_vector_type mul(const typename matrix::column_vector_type& a, const matrix& b) noexcept; /** * Constructs a rotation matrix. * * @param angle Angle of rotation, in radians. * @param axis Axis of rotation * @return Rotation matrix. */ template matrix rotate(T angle, const vector& axis); /** * Produces a matrix which rotates Cartesian coordinates about the x-axis by a given angle. * * @param angle Angle of rotation, in radians. * @return Rotation matrix. */ template matrix3 rotate_x(T angle); /** * Produces a matrix which rotates Cartesian coordinates about the y-axis by a given angle. * * @param angle Angle of rotation, in radians. * @return Rotation matrix. */ template matrix3 rotate_y(T angle); /** * Produces a matrix which rotates Cartesian coordinates about the z-axis by a given angle. * * @param angle Angle of rotation, in radians. * @return Rotation matrix. */ template matrix3 rotate_z(T angle); /** * Scales a matrix. * * @param m Matrix to scale. * @param v Scale vector. * @return Scaled matrix. */ template constexpr matrix scale(const matrix& m, const vector& v); /** * Subtracts a matrix from another matrix. * * @param a First matrix. * @param b Second matrix. * * @return Difference between the two matrices. */ template constexpr matrix sub(const matrix& a, const matrix& b) noexcept; /** * Subtracts a scalar from matrix. * * @param a Matrix. * @param b Scalar. * * @return Difference between the matrix and scalar. */ template constexpr matrix sub(const matrix& a, T b) noexcept; /** * Subtracts a matrix from a scalar. * * @param a Scalar. * @param b Matrix. * * @return Difference between the scalar and matrix. */ template constexpr matrix sub(T a, const matrix& b) noexcept; /** * Translates a matrix. * * @param m Matrix to translate. * @param v Translation vector. * @return Translated matrix. */ template constexpr matrix translate(const matrix& m, const vector& v); /** * Calculates the transpose of a matrix. * * @param m Matrix to transpose. * * @return Transposed matrix. */ template constexpr matrix transpose(const matrix& m) noexcept; /// @private template constexpr inline matrix add(const matrix& a, const matrix& b, std::index_sequence) noexcept { return {(a[I] + b[I]) ...}; } template constexpr matrix add(const matrix& a, const matrix& b) noexcept { return add(a, b, std::make_index_sequence{}); } /// @private template constexpr inline matrix add(const matrix& a, T b, std::index_sequence) noexcept { return {(a[I] + b) ...}; } template constexpr matrix add(const matrix& a, T b) noexcept { return add(a, b, std::make_index_sequence{}); } template constexpr T determinant(const matrix& m) noexcept { return m[0][0] * m[1][1] - m[0][1] * m[1][0]; } template constexpr T determinant(const matrix& m) noexcept { return m[0][0] * m[1][1] * m[2][2] + m[0][1] * m[1][2] * m[2][0] + m[0][2] * m[1][0] * m[2][1] - m[0][0] * m[1][2] * m[2][1] - m[0][1] * m[1][0] * m[2][2] - m[0][2] * m[1][1] * m[2][0]; } template constexpr T determinant(const matrix& m) noexcept { return m[0][3] * m[1][2] * m[2][1] * m[3][0] - m[0][2] * m[1][3] * m[2][1] * m[3][0] - m[0][3] * m[1][1] * m[2][2] * m[3][0] + m[0][1] * m[1][3] * m[2][2] * m[3][0] + m[0][2] * m[1][1] * m[2][3] * m[3][0] - m[0][1] * m[1][2] * m[2][3] * m[3][0] - m[0][3] * m[1][2] * m[2][0] * m[3][1] + m[0][2] * m[1][3] * m[2][0] * m[3][1] + m[0][3] * m[1][0] * m[2][2] * m[3][1] - m[0][0] * m[1][3] * m[2][2] * m[3][1] - m[0][2] * m[1][0] * m[2][3] * m[3][1] + m[0][0] * m[1][2] * m[2][3] * m[3][1] + m[0][3] * m[1][1] * m[2][0] * m[3][2] - m[0][1] * m[1][3] * m[2][0] * m[3][2] - m[0][3] * m[1][0] * m[2][1] * m[3][2] + m[0][0] * m[1][3] * m[2][1] * m[3][2] + m[0][1] * m[1][0] * m[2][3] * m[3][2] - m[0][0] * m[1][1] * m[2][3] * m[3][2] - m[0][2] * m[1][1] * m[2][0] * m[3][3] + m[0][1] * m[1][2] * m[2][0] * m[3][3] + m[0][2] * m[1][0] * m[2][1] * m[3][3] - m[0][0] * m[1][2] * m[2][1] * m[3][3] - m[0][1] * m[1][0] * m[2][2] * m[3][3] + m[0][0] * m[1][1] * m[2][2] * m[3][3]; } template constexpr matrix inverse(const matrix& m) noexcept { const T inv_det = T{1} / determinant(m); return { m[1][1] * inv_det, -m[0][1] * inv_det, -m[1][0] * inv_det, m[0][0] * inv_det }; } template constexpr matrix inverse(const matrix& m) noexcept { const T inv_det = T{1} / determinant(m); return { (m[1][1] * m[2][2] - m[1][2] * m[2][1]) * inv_det, (m[0][2] * m[2][1] - m[0][1] * m[2][2]) * inv_det, (m[0][1] * m[1][2] - m[0][2] * m[1][1]) * inv_det, (m[1][2] * m[2][0] - m[1][0] * m[2][2]) * inv_det, (m[0][0] * m[2][2] - m[0][2] * m[2][0]) * inv_det, (m[0][2] * m[1][0] - m[0][0] * m[1][2]) * inv_det, (m[1][0] * m[2][1] - m[1][1] * m[2][0]) * inv_det, (m[0][1] * m[2][0] - m[0][0] * m[2][1]) * inv_det, (m[0][0] * m[1][1] - m[0][1] * m[1][0]) * inv_det }; } template constexpr matrix inverse(const matrix& m) noexcept { const T inv_det = T{1} / determinant(m); return { (m[1][2] * m[2][3] * m[3][1] - m[1][3] * m[2][2] * m[3][1] + m[1][3] * m[2][1] * m[3][2] - m[1][1] * m[2][3] * m[3][2] - m[1][2] * m[2][1] * m[3][3] + m[1][1] * m[2][2] * m[3][3]) * inv_det, (m[0][3] * m[2][2] * m[3][1] - m[0][2] * m[2][3] * m[3][1] - m[0][3] * m[2][1] * m[3][2] + m[0][1] * m[2][3] * m[3][2] + m[0][2] * m[2][1] * m[3][3] - m[0][1] * m[2][2] * m[3][3]) * inv_det, (m[0][2] * m[1][3] * m[3][1] - m[0][3] * m[1][2] * m[3][1] + m[0][3] * m[1][1] * m[3][2] - m[0][1] * m[1][3] * m[3][2] - m[0][2] * m[1][1] * m[3][3] + m[0][1] * m[1][2] * m[3][3]) * inv_det, (m[0][3] * m[1][2] * m[2][1] - m[0][2] * m[1][3] * m[2][1] - m[0][3] * m[1][1] * m[2][2] + m[0][1] * m[1][3] * m[2][2] + m[0][2] * m[1][1] * m[2][3] - m[0][1] * m[1][2] * m[2][3]) * inv_det, (m[1][3] * m[2][2] * m[3][0] - m[1][2] * m[2][3] * m[3][0] - m[1][3] * m[2][0] * m[3][2] + m[1][0] * m[2][3] * m[3][2] + m[1][2] * m[2][0] * m[3][3] - m[1][0] * m[2][2] * m[3][3]) * inv_det, (m[0][2] * m[2][3] * m[3][0] - m[0][3] * m[2][2] * m[3][0] + m[0][3] * m[2][0] * m[3][2] - m[0][0] * m[2][3] * m[3][2] - m[0][2] * m[2][0] * m[3][3] + m[0][0] * m[2][2] * m[3][3]) * inv_det, (m[0][3] * m[1][2] * m[3][0] - m[0][2] * m[1][3] * m[3][0] - m[0][3] * m[1][0] * m[3][2] + m[0][0] * m[1][3] * m[3][2] + m[0][2] * m[1][0] * m[3][3] - m[0][0] * m[1][2] * m[3][3]) * inv_det, (m[0][2] * m[1][3] * m[2][0] - m[0][3] * m[1][2] * m[2][0] + m[0][3] * m[1][0] * m[2][2] - m[0][0] * m[1][3] * m[2][2] - m[0][2] * m[1][0] * m[2][3] + m[0][0] * m[1][2] * m[2][3]) * inv_det, (m[1][1] * m[2][3] * m[3][0] - m[1][3] * m[2][1] * m[3][0] + m[1][3] * m[2][0] * m[3][1] - m[1][0] * m[2][3] * m[3][1] - m[1][1] * m[2][0] * m[3][3] + m[1][0] * m[2][1] * m[3][3]) * inv_det, (m[0][3] * m[2][1] * m[3][0] - m[0][1] * m[2][3] * m[3][0] - m[0][3] * m[2][0] * m[3][1] + m[0][0] * m[2][3] * m[3][1] + m[0][1] * m[2][0] * m[3][3] - m[0][0] * m[2][1] * m[3][3]) * inv_det, (m[0][1] * m[1][3] * m[3][0] - m[0][3] * m[1][1] * m[3][0] + m[0][3] * m[1][0] * m[3][1] - m[0][0] * m[1][3] * m[3][1] - m[0][1] * m[1][0] * m[3][3] + m[0][0] * m[1][1] * m[3][3]) * inv_det, (m[0][3] * m[1][1] * m[2][0] - m[0][1] * m[1][3] * m[2][0] - m[0][3] * m[1][0] * m[2][1] + m[0][0] * m[1][3] * m[2][1] + m[0][1] * m[1][0] * m[2][3] - m[0][0] * m[1][1] * m[2][3]) * inv_det, (m[1][2] * m[2][1] * m[3][0] - m[1][1] * m[2][2] * m[3][0] - m[1][2] * m[2][0] * m[3][1] + m[1][0] * m[2][2] * m[3][1] + m[1][1] * m[2][0] * m[3][2] - m[1][0] * m[2][1] * m[3][2]) * inv_det, (m[0][1] * m[2][2] * m[3][0] - m[0][2] * m[2][1] * m[3][0] + m[0][2] * m[2][0] * m[3][1] - m[0][0] * m[2][2] * m[3][1] - m[0][1] * m[2][0] * m[3][2] + m[0][0] * m[2][1] * m[3][2]) * inv_det, (m[0][2] * m[1][1] * m[3][0] - m[0][1] * m[1][2] * m[3][0] - m[0][2] * m[1][0] * m[3][1] + m[0][0] * m[1][2] * m[3][1] + m[0][1] * m[1][0] * m[3][2] - m[0][0] * m[1][1] * m[3][2]) * inv_det, (m[0][1] * m[1][2] * m[2][0] - m[0][2] * m[1][1] * m[2][0] + m[0][2] * m[1][0] * m[2][1] - m[0][0] * m[1][2] * m[2][1] - m[0][1] * m[1][0] * m[2][2] + m[0][0] * m[1][1] * m[2][2]) * inv_det }; } /// @private template constexpr inline matrix componentwise_mul(const matrix& a, const matrix& b, std::index_sequence) noexcept { return {(a[I] * b[I]) ...}; } template constexpr matrix componentwise_mul(const matrix& a, const matrix& b) noexcept { return componentwise_mul(a, b, std::make_index_sequence{}); } /// @private template constexpr inline matrix div(const matrix& a, const matrix& b, std::index_sequence) noexcept { return {(a[I] / b[I]) ...}; } template constexpr matrix div(const matrix& a, const matrix& b) noexcept { return div(a, b, std::make_index_sequence{}); } /// @private template constexpr inline matrix div(const matrix& a, T b, std::index_sequence) noexcept { return {(a[I] / b) ...}; } template constexpr matrix div(const matrix& a, T b) noexcept { return div(a, b, std::make_index_sequence{}); } /// @private template constexpr inline matrix div(T a, const matrix& b, std::index_sequence) noexcept { return {(a / b[I]) ...}; } template constexpr matrix div(T a, const matrix& b) noexcept { return div(a, b, std::make_index_sequence{}); } template constexpr matrix look_at(const vector& position, const vector& target, vector up) { vector forward = normalize(sub(target, position)); vector right = normalize(cross(forward, up)); up = cross(right, forward); matrix m = {{ {right[0], up[0], -forward[0], T(0)}, {right[1], up[1], -forward[1], T(0)}, {right[2], up[2], -forward[2], T(0)}, {T(0), T(0), T(0), T(1)} }}; return translate(m, negate(position)); } template constexpr matrix mul(const matrix& a, const matrix& b) noexcept { matrix c = matrix::zero(); for (std::size_t i = 0; i < P; ++i) { for (std::size_t j = 0; j < M; ++j) { for (std::size_t k = 0; k < N; ++k) { c[i][j] += a[k][j] * b[i][k]; } } } return c; } /// @private template constexpr inline matrix mul(const matrix& a, T b, std::index_sequence) noexcept { return {(a[I] * b) ...}; } template constexpr matrix mul(const matrix& a, T b) noexcept { return mul(a, b, std::make_index_sequence{}); } /// @private template constexpr inline typename matrix::column_vector_type mul(const matrix& a, const typename matrix::row_vector_type& b, std::index_sequence) noexcept { return ((a[I] * b[I]) + ...); } template constexpr typename matrix::column_vector_type mul(const matrix& a, const typename matrix::row_vector_type& b) noexcept { return mul(a, b, std::make_index_sequence{}); } /// @private template constexpr inline typename matrix::row_vector_type mul(const typename matrix::column_vector_type& a, const matrix& b, std::index_sequence) noexcept { return {dot(a, b[I]) ...}; } template constexpr typename matrix::row_vector_type mul(const typename matrix::column_vector_type& a, const matrix& b) noexcept { return mul(a, b, std::make_index_sequence{}); } template matrix rotate(T angle, const vector& axis) { const T c = std::cos(angle); const T s = std::sin(angle); const vector temp = mul(axis, T(1) - c); matrix rotation; rotation[0][0] = axis[0] * temp[0] + c; rotation[0][1] = axis[1] * temp[0] + axis[2] * s; rotation[0][2] = axis[2] * temp[0] - axis[1] * s; rotation[1][0] = axis[0] * temp[1] - axis[2] * s; rotation[1][1] = axis[1] * temp[1] + c; rotation[1][2] = axis[2] * temp[1] + axis[0] * s; rotation[2][0] = axis[0] * temp[2] + axis[1] * s; rotation[2][1] = axis[1] * temp[2] - axis[0] * s; rotation[2][2] = axis[2] * temp[2] + c; return rotation; } template matrix3 rotate_x(T angle) { const T c = std::cos(angle); const T s = std::sin(angle); return matrix3 { T(1), T(0), T(0), T(0), c, s, T(0), -s, c }; } template matrix3 rotate_y(T angle) { const T c = std::cos(angle); const T s = std::sin(angle); return matrix3 { c, T(0), -s, T(0), T(1), T(0), s, T(0), c }; } template matrix3 rotate_z(T angle) { const T c = std::cos(angle); const T s = std::sin(angle); return matrix3 { c, s, T(0), -s, c, T(0), T(0), T(0), T(1) }; } template constexpr matrix scale(const matrix& m, const vector& v) { return mul(m, matrix {{ {v[0], T(0), T(0), T(0)}, {T(0), v[1], T(0), T(0)}, {T(0), T(0), v[2], T(0)}, {T(0), T(0), T(0), T(1)} }}); } /// @private template constexpr inline matrix sub(const matrix& a, const matrix& b, std::index_sequence) noexcept { return {(a[I] - b[I]) ...}; } template constexpr matrix sub(const matrix& a, const matrix& b) noexcept { return sub(a, b, std::make_index_sequence{}); } /// @private template constexpr inline matrix sub(const matrix& a, T b, std::index_sequence) noexcept { return {(a[I] - b) ...}; } template constexpr matrix sub(const matrix& a, T b) noexcept { return sub(a, b, std::make_index_sequence{}); } /// @private template constexpr inline matrix sub(T a, const matrix& b, std::index_sequence) noexcept { return {(a - b[I]) ...}; } template constexpr matrix sub(T a, const matrix& b) noexcept { return sub(a, b, std::make_index_sequence{}); } template constexpr matrix translate(const matrix& m, const vector& v) { return mul(m, matrix {{ {T(1), T(0), T(0), T(0)}, {T(0), T(1), T(0), T(0)}, {T(0), T(0), T(1), T(0)}, {v[0], v[1], v[2], T(1)} }}); } /// @private template constexpr inline typename matrix::column_vector_type transpose_column(const matrix& m, std::size_t i, std::index_sequence) noexcept { return {m[I][i] ...}; } /// @private template constexpr inline matrix transpose(const matrix& m, std::index_sequence) noexcept { return {transpose_column(m, I, std::make_index_sequence{}) ...}; } template constexpr matrix transpose(const matrix& m) noexcept { return transpose(m, std::make_index_sequence{}); } namespace operators { /// @copydoc add(const matrix&, const matrix&) template constexpr inline matrix operator+(const matrix& a, const matrix& b) noexcept { return add(a, b); } /// @copydoc add(const matrix&, T) /// @{ template constexpr inline matrix operator+(const matrix& a, T b) noexcept { return add(a, b); } template constexpr inline matrix operator+(T a, const matrix& b) noexcept { return add(b, a); } /// @} /// @copydoc div(const matrix&, const matrix&) template constexpr inline matrix operator/(const matrix& a, const matrix& b) noexcept { return div(a, b); } /// @copydoc div(const matrix&, T) template constexpr inline matrix operator/(const matrix& a, T b) noexcept { return div(a, b); } /// @copydoc div(T, const matrix&) template constexpr inline matrix operator/(T a, const matrix& b) noexcept { return div(a, b); } /// @copydoc mul(const matrix&, const matrix&) template constexpr inline matrix operator*(const matrix& a, const matrix& b) noexcept { return mul(a, b); } /// @copydoc mul(const matrix&, T) /// @{ template constexpr inline matrix operator*(const matrix& a, T b) noexcept { return mul(a, b); } template constexpr inline matrix operator*(T a, const matrix& b) noexcept { return mul(b, a); } /// @} /// @copydoc mul(const matrix&, const typename matrix::row_vector_type&) template constexpr inline typename matrix::column_vector_type operator*(const matrix& a, const typename matrix::row_vector_type& b) noexcept { return mul(a, b); } /// @copydoc mul(const typename matrix::column_vector_type&, const matrix&) template constexpr inline typename matrix::row_vector_type operator*(const typename matrix::column_vector_type& a, const matrix& b) noexcept { return mul(a, b); } /// @copydoc sub(const matrix&, const matrix&) template constexpr inline matrix operator-(const matrix& a, const matrix& b) noexcept { return sub(a, b); } /// @copydoc sub(const matrix&, T) template constexpr inline matrix operator-(const matrix& a, T b) noexcept { return sub(a, b); } /// @copydoc sub(T, const matrix&) template constexpr inline matrix operator-(T a, const matrix& b) noexcept { return sub(a, b); } /** * Adds two values and stores the result in the first value. * * @param a First value. * @param b Second value. * @return Reference to the first value. */ /// @{ template constexpr inline matrix& operator+=(matrix& a, const matrix& b) noexcept { return (a = a + b); } template constexpr inline matrix& operator+=(matrix& a, T b) noexcept { return (a = a + b); } /// @} /** * Subtracts the first value by the second value and stores the result in the first value. * * @param a First value. * @param b Second value. * @return Reference to the first value. */ /// @{ template constexpr inline matrix& operator-=(matrix& a, const matrix& b) noexcept { return (a = a - b); } template constexpr inline matrix& operator-=(matrix& a, T b) noexcept { return (a = a - b); } /// @} /** * Multiplies two values and stores the result in the first value. * * @param a First value. * @param b Second value. * @return Reference to the first value. */ /// @{ template constexpr inline matrix& operator*=(matrix& a, matrix& b) noexcept { return (a = a * b); } template constexpr inline matrix& operator*=(matrix& a, T b) noexcept { return (a = a * b); } /// @} /** * Divides the first value by the second value and stores the result in the first value. * * @param a First value. * @param b Second value. * @return Reference to the first value. */ /// @{ template constexpr inline matrix& operator/=(matrix& a, const matrix& b) noexcept { return (a = a / b); } template constexpr inline matrix& operator/=(matrix& a, T b) noexcept { return (a = a / b); } /// @} /** * Writes the elements of a matrix to an output stream, with each element delimeted by a space. * * @param os Output stream. * @param m Matrix. * @return Output stream. */ template std::ostream& operator<<(std::ostream& os, const matrix& m) { for (std::size_t i = 0; i < m.size(); ++i) { if (i) os << ' '; os << m.element(i); } return os; } /** * Reads the elements of a matrix from an input stream, with each element delimeted by a space. * * @param is Input stream. * @param m Matrix. * @return Input stream. */ template std::istream& operator>>(std::istream& is, matrix& m) { for (std::size_t i = 0; i < m.size(); ++i) is >> m.element(i); return is; } } // namespace operators } // namespace math using namespace math::operators; #endif // ANTKEEPER_MATH_MATRIX_HPP