/// @file Built-In Matrix-Vector functions #ifndef IDMATVEC_HPP_ #define IDMATVEC_HPP_ #include #include "../IDConfig.hpp" #define BT_ID_HAVE_MAT3X namespace btInverseDynamics { class vec3; class vecx; class mat33; class matxx; class mat3x; /// This is a very basic implementation to enable stand-alone use of the library. /// The implementation is not really optimized and misses many features that you would /// want from a "fully featured" linear math library. class vec3 { public: idScalar& operator()(int i) { return m_data[i]; } const idScalar& operator()(int i) const { return m_data[i]; } const int size() const { return 3; } const vec3& operator=(const vec3& rhs); const vec3& operator+=(const vec3& b); const vec3& operator-=(const vec3& b); vec3 cross(const vec3& b) const; idScalar dot(const vec3& b) const; friend vec3 operator*(const mat33& a, const vec3& b); friend vec3 operator*(const vec3& a, const idScalar& s); friend vec3 operator*(const idScalar& s, const vec3& a); friend vec3 operator+(const vec3& a, const vec3& b); friend vec3 operator-(const vec3& a, const vec3& b); friend vec3 operator/(const vec3& a, const idScalar& s); private: idScalar m_data[3]; }; class mat33 { public: idScalar& operator()(int i, int j) { return m_data[3 * i + j]; } const idScalar& operator()(int i, int j) const { return m_data[3 * i + j]; } const mat33& operator=(const mat33& rhs); mat33 transpose() const; const mat33& operator+=(const mat33& b); const mat33& operator-=(const mat33& b); friend mat33 operator*(const mat33& a, const mat33& b); friend vec3 operator*(const mat33& a, const vec3& b); friend mat33 operator*(const mat33& a, const idScalar& s); friend mat33 operator*(const idScalar& s, const mat33& a); friend mat33 operator+(const mat33& a, const mat33& b); friend mat33 operator-(const mat33& a, const mat33& b); friend mat33 operator/(const mat33& a, const idScalar& s); private: // layout is [0,1,2;3,4,5;6,7,8] idScalar m_data[9]; }; class vecx { public: vecx(int size) : m_size(size) { m_data = static_cast(idMalloc(sizeof(idScalar) * size)); } ~vecx() { idFree(m_data); } const vecx& operator=(const vecx& rhs); idScalar& operator()(int i) { return m_data[i]; } const idScalar& operator()(int i) const { return m_data[i]; } const int& size() const { return m_size; } friend vecx operator*(const vecx& a, const idScalar& s); friend vecx operator*(const idScalar& s, const vecx& a); friend vecx operator+(const vecx& a, const vecx& b); friend vecx operator-(const vecx& a, const vecx& b); friend vecx operator/(const vecx& a, const idScalar& s); private: int m_size; idScalar* m_data; }; class matxx { public: matxx() { m_data = 0x0; m_cols = 0; m_rows = 0; } matxx(int rows, int cols) : m_rows(rows), m_cols(cols) { m_data = static_cast(idMalloc(sizeof(idScalar) * rows * cols)); } ~matxx() { idFree(m_data); } idScalar& operator()(int row, int col) { return m_data[row * m_cols + col]; } const idScalar& operator()(int row, int col) const { return m_data[row * m_cols + col]; } const int& rows() const { return m_rows; } const int& cols() const { return m_cols; } private: int m_rows; int m_cols; idScalar* m_data; }; class mat3x { public: mat3x() { m_data = 0x0; m_cols = 0; } mat3x(const mat3x& rhs) { m_cols = rhs.m_cols; allocate(); *this = rhs; } mat3x(int rows, int cols) : m_cols(cols) { allocate(); }; void operator=(const mat3x& rhs) { if (m_cols != rhs.m_cols) { bt_id_error_message("size missmatch, cols= %d but rhs.cols= %d\n", cols(), rhs.cols()); abort(); } for (int i = 0; i < 3 * m_cols; i++) { m_data[i] = rhs.m_data[i]; } } ~mat3x() { free(); } idScalar& operator()(int row, int col) { return m_data[row * m_cols + col]; } const idScalar& operator()(int row, int col) const { return m_data[row * m_cols + col]; } int rows() const { return m_rows; } const int& cols() const { return m_cols; } void resize(int rows, int cols) { m_cols = cols; free(); allocate(); } void setZero() { memset(m_data, 0x0, sizeof(idScalar) * m_rows * m_cols); } // avoid operators that would allocate -- use functions sub/add/mul in IDMath.hpp instead private: void allocate() { m_data = static_cast(idMalloc(sizeof(idScalar) * m_rows * m_cols)); } void free() { idFree(m_data); } enum { m_rows = 3 }; int m_cols; idScalar* m_data; }; inline void resize(mat3x& m, idArrayIdx size) { m.resize(3, size); m.setZero(); } ////////////////////////////////////////////////// // Implementations inline const vec3& vec3::operator=(const vec3& rhs) { if (&rhs != this) { memcpy(m_data, rhs.m_data, 3 * sizeof(idScalar)); } return *this; } inline vec3 vec3::cross(const vec3& b) const { vec3 result; result.m_data[0] = m_data[1] * b.m_data[2] - m_data[2] * b.m_data[1]; result.m_data[1] = m_data[2] * b.m_data[0] - m_data[0] * b.m_data[2]; result.m_data[2] = m_data[0] * b.m_data[1] - m_data[1] * b.m_data[0]; return result; } inline idScalar vec3::dot(const vec3& b) const { return m_data[0] * b.m_data[0] + m_data[1] * b.m_data[1] + m_data[2] * b.m_data[2]; } inline const mat33& mat33::operator=(const mat33& rhs) { if (&rhs != this) { memcpy(m_data, rhs.m_data, 9 * sizeof(idScalar)); } return *this; } inline mat33 mat33::transpose() const { mat33 result; result.m_data[0] = m_data[0]; result.m_data[1] = m_data[3]; result.m_data[2] = m_data[6]; result.m_data[3] = m_data[1]; result.m_data[4] = m_data[4]; result.m_data[5] = m_data[7]; result.m_data[6] = m_data[2]; result.m_data[7] = m_data[5]; result.m_data[8] = m_data[8]; return result; } inline mat33 operator*(const mat33& a, const mat33& b) { mat33 result; result.m_data[0] = a.m_data[0] * b.m_data[0] + a.m_data[1] * b.m_data[3] + a.m_data[2] * b.m_data[6]; result.m_data[1] = a.m_data[0] * b.m_data[1] + a.m_data[1] * b.m_data[4] + a.m_data[2] * b.m_data[7]; result.m_data[2] = a.m_data[0] * b.m_data[2] + a.m_data[1] * b.m_data[5] + a.m_data[2] * b.m_data[8]; result.m_data[3] = a.m_data[3] * b.m_data[0] + a.m_data[4] * b.m_data[3] + a.m_data[5] * b.m_data[6]; result.m_data[4] = a.m_data[3] * b.m_data[1] + a.m_data[4] * b.m_data[4] + a.m_data[5] * b.m_data[7]; result.m_data[5] = a.m_data[3] * b.m_data[2] + a.m_data[4] * b.m_data[5] + a.m_data[5] * b.m_data[8]; result.m_data[6] = a.m_data[6] * b.m_data[0] + a.m_data[7] * b.m_data[3] + a.m_data[8] * b.m_data[6]; result.m_data[7] = a.m_data[6] * b.m_data[1] + a.m_data[7] * b.m_data[4] + a.m_data[8] * b.m_data[7]; result.m_data[8] = a.m_data[6] * b.m_data[2] + a.m_data[7] * b.m_data[5] + a.m_data[8] * b.m_data[8]; return result; } inline const mat33& mat33::operator+=(const mat33& b) { for (int i = 0; i < 9; i++) { m_data[i] += b.m_data[i]; } return *this; } inline const mat33& mat33::operator-=(const mat33& b) { for (int i = 0; i < 9; i++) { m_data[i] -= b.m_data[i]; } return *this; } inline vec3 operator*(const mat33& a, const vec3& b) { vec3 result; result.m_data[0] = a.m_data[0] * b.m_data[0] + a.m_data[1] * b.m_data[1] + a.m_data[2] * b.m_data[2]; result.m_data[1] = a.m_data[3] * b.m_data[0] + a.m_data[4] * b.m_data[1] + a.m_data[5] * b.m_data[2]; result.m_data[2] = a.m_data[6] * b.m_data[0] + a.m_data[7] * b.m_data[1] + a.m_data[8] * b.m_data[2]; return result; } inline const vec3& vec3::operator+=(const vec3& b) { for (int i = 0; i < 3; i++) { m_data[i] += b.m_data[i]; } return *this; } inline const vec3& vec3::operator-=(const vec3& b) { for (int i = 0; i < 3; i++) { m_data[i] -= b.m_data[i]; } return *this; } inline mat33 operator*(const mat33& a, const idScalar& s) { mat33 result; for (int i = 0; i < 9; i++) { result.m_data[i] = a.m_data[i] * s; } return result; } inline mat33 operator*(const idScalar& s, const mat33& a) { return a * s; } inline vec3 operator*(const vec3& a, const idScalar& s) { vec3 result; for (int i = 0; i < 3; i++) { result.m_data[i] = a.m_data[i] * s; } return result; } inline vec3 operator*(const idScalar& s, const vec3& a) { return a * s; } inline mat33 operator+(const mat33& a, const mat33& b) { mat33 result; for (int i = 0; i < 9; i++) { result.m_data[i] = a.m_data[i] + b.m_data[i]; } return result; } inline vec3 operator+(const vec3& a, const vec3& b) { vec3 result; for (int i = 0; i < 3; i++) { result.m_data[i] = a.m_data[i] + b.m_data[i]; } return result; } inline mat33 operator-(const mat33& a, const mat33& b) { mat33 result; for (int i = 0; i < 9; i++) { result.m_data[i] = a.m_data[i] - b.m_data[i]; } return result; } inline vec3 operator-(const vec3& a, const vec3& b) { vec3 result; for (int i = 0; i < 3; i++) { result.m_data[i] = a.m_data[i] - b.m_data[i]; } return result; } inline mat33 operator/(const mat33& a, const idScalar& s) { mat33 result; for (int i = 0; i < 9; i++) { result.m_data[i] = a.m_data[i] / s; } return result; } inline vec3 operator/(const vec3& a, const idScalar& s) { vec3 result; for (int i = 0; i < 3; i++) { result.m_data[i] = a.m_data[i] / s; } return result; } inline const vecx& vecx::operator=(const vecx& rhs) { if (size() != rhs.size()) { bt_id_error_message("size missmatch, size()= %d but rhs.size()= %d\n", size(), rhs.size()); abort(); } if (&rhs != this) { memcpy(m_data, rhs.m_data, rhs.size() * sizeof(idScalar)); } return *this; } inline vecx operator*(const vecx& a, const idScalar& s) { vecx result(a.size()); for (int i = 0; i < result.size(); i++) { result.m_data[i] = a.m_data[i] * s; } return result; } inline vecx operator*(const idScalar& s, const vecx& a) { return a * s; } inline vecx operator+(const vecx& a, const vecx& b) { vecx result(a.size()); // TODO: error handling for a.size() != b.size()?? if (a.size() != b.size()) { bt_id_error_message("size missmatch. a.size()= %d, b.size()= %d\n", a.size(), b.size()); abort(); } for (int i = 0; i < a.size(); i++) { result.m_data[i] = a.m_data[i] + b.m_data[i]; } return result; } inline vecx operator-(const vecx& a, const vecx& b) { vecx result(a.size()); // TODO: error handling for a.size() != b.size()?? if (a.size() != b.size()) { bt_id_error_message("size missmatch. a.size()= %d, b.size()= %d\n", a.size(), b.size()); abort(); } for (int i = 0; i < a.size(); i++) { result.m_data[i] = a.m_data[i] - b.m_data[i]; } return result; } inline vecx operator/(const vecx& a, const idScalar& s) { vecx result(a.size()); for (int i = 0; i < result.size(); i++) { result.m_data[i] = a.m_data[i] / s; } return result; } inline vec3 operator*(const mat3x& a, const vecx& b) { vec3 result; if (a.cols() != b.size()) { bt_id_error_message("size missmatch. a.cols()= %d, b.size()= %d\n", a.cols(), b.size()); abort(); } result(0) = 0.0; result(1) = 0.0; result(2) = 0.0; for (int i = 0; i < b.size(); i++) { for (int k = 0; k < 3; k++) { result(k) += a(k, i) * b(i); } } return result; } inline void setMatxxElem(const idArrayIdx row, const idArrayIdx col, const idScalar val, matxx* m) { (*m)(row, col) = val; } inline void setMat3xElem(const idArrayIdx row, const idArrayIdx col, const idScalar val, mat3x* m) { (*m)(row, col) = val; } } // namespace btInverseDynamics #endif