//################################################################################################## // // Custom Visualization Core library // Copyright (C) 2011-2013 Ceetron AS // // This library may be used under the terms of either the GNU General Public License or // the GNU Lesser General Public License as follows: // // GNU General Public License Usage // This library 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. // // This library 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 at <> // for more details. // // GNU Lesser General Public License Usage // This library is free software; you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation; either version 2.1 of the License, or // (at your option) any later version. // // This library 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 Lesser General Public License at <> // for more details. // //################################################################################################## namespace cvf { //================================================================================================== /// /// \class cvf::Matrix4 /// \ingroup Core /// /// Matrices are stored internally as a one dimensional array for performance reasons. /// /// The internal indices into the 1D array are as follows: /// ///
///   | m00  m01  m02  m03 |     | 0  4   8  12 | 
///   | m10  m11  m12  m13 |     | 1  5   9  13 | 
///   | m20  m21  m22  m23 |     | 2  6  10  14 | 
///   | m30  m31  m32  m33 |     | 3  7  11  15 | 
/// 
/// /// This is consistent with the way matrices are represented in %OpenGL. /// To exemplify, translation values are stored in elements 12,13,14; see figure below /// ///
///   | 1  0  0 Tx |
///   | 0  1  0 Ty |
///   | 0  0  1 Tz |
///   | 0  0  0  1 |
/// 
/// /// From the %OpenGL red book (page 68) v' = M*v /// ///
///   | X'|   | 1  0  0 Tx |   | X |
///   | Y'|   | 0  1  0 Ty |   | Y |
///   | Z'| = | 0  0  1 Tz | * | Z |
///   | 1 |   | 0  0  0  1 |   | 1 |
/// 
/// /// Beware when porting code that uses C style double array indexing. In this case, the first /// index given will corrspond to the columnd, eg M[3][0] = Tx, M[3][1] = Ty, M[3][2] = Tz /// /// To ease accessing the internal 1D array in implementations, the private eij constants can be used. /// These are consistent with the normal row column ordering, so that e02 accesses the element /// in the first row and the third column. /// //================================================================================================== template Matrix4 const Matrix4::IDENTITY; template Matrix4 const Matrix4::ZERO(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); //---------------------------------------------------------------------------------------------------- /// Default constructor. Initializes matrix to identity //---------------------------------------------------------------------------------------------------- template Matrix4::Matrix4() { setIdentity(); } //---------------------------------------------------------------------------------------------------- /// Copy constructor //---------------------------------------------------------------------------------------------------- template inline Matrix4::Matrix4(const Matrix4& other) { System::memcpy(m_v, sizeof(m_v), other.m_v, sizeof(other.m_v)); } //---------------------------------------------------------------------------------------------------- /// Constructor with explicit initialization of all matrix elements. /// /// The value of the parameter \a mrc will be placed in row r and column c of the matrix, eg m23 /// goes into row 2, column 3. //---------------------------------------------------------------------------------------------------- template Matrix4::Matrix4(S m00, S m01, S m02, S m03, S m10, S m11, S m12, S m13, S m20, S m21, S m22, S m23, S m30, S m31, S m32, S m33) { m_v[e00] = m00; m_v[e10] = m10; m_v[e20] = m20; m_v[e30] = m30; m_v[e01] = m01; m_v[e11] = m11; m_v[e21] = m21; m_v[e31] = m31; m_v[e02] = m02; m_v[e12] = m12; m_v[e22] = m22; m_v[e32] = m32; m_v[e03] = m03; m_v[e13] = m13; m_v[e23] = m23; m_v[e33] = m33; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- template Matrix4::Matrix4(const Matrix3& other) { setFromMatrix3(other); } //---------------------------------------------------------------------------------------------------- /// //---------------------------------------------------------------------------------------------------- template template Matrix4::Matrix4(const Matrix4& other) { m_v[e00] = static_cast(other.rowCol(0, 0)); m_v[e10] = static_cast(other.rowCol(1, 0)); m_v[e20] = static_cast(other.rowCol(2, 0)); m_v[e30] = static_cast(other.rowCol(3, 0)); m_v[e01] = static_cast(other.rowCol(0, 1)); m_v[e11] = static_cast(other.rowCol(1, 1)); m_v[e21] = static_cast(other.rowCol(2, 1)); m_v[e31] = static_cast(other.rowCol(3, 1)); m_v[e02] = static_cast(other.rowCol(0, 2)); m_v[e12] = static_cast(other.rowCol(1, 2)); m_v[e22] = static_cast(other.rowCol(2, 2)); m_v[e32] = static_cast(other.rowCol(3, 2)); m_v[e03] = static_cast(other.rowCol(0, 3)); m_v[e13] = static_cast(other.rowCol(1, 3)); m_v[e23] = static_cast(other.rowCol(2, 3)); m_v[e33] = static_cast(other.rowCol(3, 3)); } //---------------------------------------------------------------------------------------------------- /// Assignment operator //---------------------------------------------------------------------------------------------------- template inline Matrix4& Matrix4::operator=(const Matrix4& obj) { System::memcpy(m_v, sizeof(m_v), obj.m_v, sizeof(obj.m_v)); return *this; } //---------------------------------------------------------------------------------------------------- /// Check if matrices are equal using exact comparisons. //---------------------------------------------------------------------------------------------------- template bool Matrix4::equals(const Matrix4& mat) const { for (int i = 0; i < 16; i++) { if (m_v[i] != mat.m_v[i]) return false; } return true; } //---------------------------------------------------------------------------------------------------- /// Comparison operator. Checks for equality using exact comparisons. //---------------------------------------------------------------------------------------------------- template bool Matrix4::operator==(const Matrix4& rhs) const { return this->equals(rhs); } //---------------------------------------------------------------------------------------------------- /// Comparison operator. Checks for not equal using exact comparisons. //---------------------------------------------------------------------------------------------------- template bool Matrix4::operator!=(const Matrix4& rhs) const { int i; for (i = 0; i < 16; i++) { if (m_v[i] != rhs.m_v[i]) return true; } return false; } //-------------------------------------------------------------------------------------------------- /// Multiplies this matrix M with the matrix \a mat, M = M*mat //-------------------------------------------------------------------------------------------------- template void Matrix4::multiply(const Matrix4& mat) { *this = (*this)*mat; } //---------------------------------------------------------------------------------------------------- /// //---------------------------------------------------------------------------------------------------- template const Matrix4 Matrix4::operator*(const Matrix4& rhs) const { Matrix4 m; m.m_v[e00] = m_v[e00] * rhs.m_v[e00] + m_v[e01] * rhs.m_v[e10] + m_v[e02] * rhs.m_v[e20] + m_v[e03] * rhs.m_v[e30]; m.m_v[e01] = m_v[e00] * rhs.m_v[e01] + m_v[e01] * rhs.m_v[e11] + m_v[e02] * rhs.m_v[e21] + m_v[e03] * rhs.m_v[e31]; m.m_v[e02] = m_v[e00] * rhs.m_v[e02] + m_v[e01] * rhs.m_v[e12] + m_v[e02] * rhs.m_v[e22] + m_v[e03] * rhs.m_v[e32]; m.m_v[e03] = m_v[e00] * rhs.m_v[e03] + m_v[e01] * rhs.m_v[e13] + m_v[e02] * rhs.m_v[e23] + m_v[e03] * rhs.m_v[e33]; m.m_v[e10] = m_v[e10] * rhs.m_v[e00] + m_v[e11] * rhs.m_v[e10] + m_v[e12] * rhs.m_v[e20] + m_v[e13] * rhs.m_v[e30]; m.m_v[e11] = m_v[e10] * rhs.m_v[e01] + m_v[e11] * rhs.m_v[e11] + m_v[e12] * rhs.m_v[e21] + m_v[e13] * rhs.m_v[e31]; m.m_v[e12] = m_v[e10] * rhs.m_v[e02] + m_v[e11] * rhs.m_v[e12] + m_v[e12] * rhs.m_v[e22] + m_v[e13] * rhs.m_v[e32]; m.m_v[e13] = m_v[e10] * rhs.m_v[e03] + m_v[e11] * rhs.m_v[e13] + m_v[e12] * rhs.m_v[e23] + m_v[e13] * rhs.m_v[e33]; m.m_v[e20] = m_v[e20] * rhs.m_v[e00] + m_v[e21] * rhs.m_v[e10] + m_v[e22] * rhs.m_v[e20] + m_v[e23] * rhs.m_v[e30]; m.m_v[e21] = m_v[e20] * rhs.m_v[e01] + m_v[e21] * rhs.m_v[e11] + m_v[e22] * rhs.m_v[e21] + m_v[e23] * rhs.m_v[e31]; m.m_v[e22] = m_v[e20] * rhs.m_v[e02] + m_v[e21] * rhs.m_v[e12] + m_v[e22] * rhs.m_v[e22] + m_v[e23] * rhs.m_v[e32]; m.m_v[e23] = m_v[e20] * rhs.m_v[e03] + m_v[e21] * rhs.m_v[e13] + m_v[e22] * rhs.m_v[e23] + m_v[e23] * rhs.m_v[e33]; m.m_v[e30] = m_v[e30] * rhs.m_v[e00] + m_v[e31] * rhs.m_v[e10] + m_v[e32] * rhs.m_v[e20] + m_v[e33] * rhs.m_v[e30]; m.m_v[e31] = m_v[e30] * rhs.m_v[e01] + m_v[e31] * rhs.m_v[e11] + m_v[e32] * rhs.m_v[e21] + m_v[e33] * rhs.m_v[e31]; m.m_v[e32] = m_v[e30] * rhs.m_v[e02] + m_v[e31] * rhs.m_v[e12] + m_v[e32] * rhs.m_v[e22] + m_v[e33] * rhs.m_v[e32]; m.m_v[e33] = m_v[e30] * rhs.m_v[e03] + m_v[e31] * rhs.m_v[e13] + m_v[e32] * rhs.m_v[e23] + m_v[e33] * rhs.m_v[e33]; return m; } //---------------------------------------------------------------------------------------------------- /// //---------------------------------------------------------------------------------------------------- template const Vector4 Matrix4::operator*(const Vector4& rhs) const { return Vector4(m_v[e00]*rhs.x() + m_v[e01]*rhs.y() + m_v[e02]*rhs.z() + m_v[e03]*rhs.w(), m_v[e10]*rhs.x() + m_v[e11]*rhs.y() + m_v[e12]*rhs.z() + m_v[e13]*rhs.w(), m_v[e20]*rhs.x() + m_v[e21]*rhs.y() + m_v[e22]*rhs.z() + m_v[e23]*rhs.w(), m_v[e30]*rhs.x() + m_v[e31]*rhs.y() + m_v[e32]*rhs.z() + m_v[e33]*rhs.w()); } //---------------------------------------------------------------------------------------------------- /// Sets this matrix to identity //---------------------------------------------------------------------------------------------------- template void Matrix4::setIdentity() { m_v[0] = 1; m_v[1] = 0; m_v[2] = 0; m_v[3] = 0; m_v[4] = 0; m_v[5] = 1; m_v[6] = 0; m_v[7] = 0; m_v[8] = 0; m_v[9] = 0; m_v[10] = 1; m_v[11] = 0; m_v[12] = 0; m_v[13] = 0; m_v[14] = 0; m_v[15] = 1; } //---------------------------------------------------------------------------------------------------- /// Check if this matrix is identity using exact comparisons //---------------------------------------------------------------------------------------------------- template bool Matrix4::isIdentity() const { if (m_v[0] != 1) return false; if (m_v[1] != 0) return false; if (m_v[2] != 0) return false; if (m_v[3] != 0) return false; if (m_v[4] != 0) return false; if (m_v[5] != 1) return false; if (m_v[6] != 0) return false; if (m_v[7] != 0) return false; if (m_v[8] != 0) return false; if (m_v[9] != 0) return false; if (m_v[10] != 1) return false; if (m_v[11] != 0) return false; if (m_v[12] != 0) return false; if (m_v[13] != 0) return false; if (m_v[14] != 0) return false; if (m_v[15] != 1) return false; return true; } //---------------------------------------------------------------------------------------------------- /// Set all matrix elements to 0 //---------------------------------------------------------------------------------------------------- template void Matrix4::setZero() { m_v[0] = 0; m_v[1] = 0; m_v[2] = 0; m_v[3] = 0; m_v[4] = 0; m_v[5] = 0; m_v[6] = 0; m_v[7] = 0; m_v[8] = 0; m_v[9] = 0; m_v[10] = 0; m_v[11] = 0; m_v[12] = 0; m_v[13] = 0; m_v[14] = 0; m_v[15] = 0; } //---------------------------------------------------------------------------------------------------- /// Returns true if all elements of the matrix are 0. Uses exact comparison. //---------------------------------------------------------------------------------------------------- template bool Matrix4::isZero() const { if (m_v[0] != 0) return false; if (m_v[1] != 0) return false; if (m_v[2] != 0) return false; if (m_v[3] != 0) return false; if (m_v[4] != 0) return false; if (m_v[5] != 0) return false; if (m_v[6] != 0) return false; if (m_v[7] != 0) return false; if (m_v[8] != 0) return false; if (m_v[9] != 0) return false; if (m_v[10] != 0) return false; if (m_v[11] != 0) return false; if (m_v[12] != 0) return false; if (m_v[13] != 0) return false; if (m_v[14] != 0) return false; if (m_v[15] != 0) return false; return true; } //---------------------------------------------------------------------------------------------------- /// Set the matrix element at the specified row and column //---------------------------------------------------------------------------------------------------- template inline void Matrix4::setRowCol(int row, int col, S value) { CVF_TIGHT_ASSERT(row >= 0 && row < 4); CVF_TIGHT_ASSERT(col >= 0 && col < 4); m_v[4*col + row] = value; } //---------------------------------------------------------------------------------------------------- /// Get the matrix element at the specified row and column //---------------------------------------------------------------------------------------------------- template inline S Matrix4::rowCol(int row, int col) const { CVF_TIGHT_ASSERT(row >= 0 && row < 4); CVF_TIGHT_ASSERT(col >= 0 && col < 4); return m_v[4*col + row]; } //-------------------------------------------------------------------------------------------------- /// Get modifiable reference to the the matrix element at the specified row and column //-------------------------------------------------------------------------------------------------- template inline S& Matrix4::operator()(int row, int col) { CVF_TIGHT_ASSERT(row >= 0 && row < 4); CVF_TIGHT_ASSERT(col >= 0 && col < 4); return m_v[4*col + row]; } //-------------------------------------------------------------------------------------------------- /// Get the matrix element at the specified row and column //-------------------------------------------------------------------------------------------------- template inline S Matrix4::operator()(int row, int col) const { CVF_TIGHT_ASSERT(row >= 0 && row < 4); CVF_TIGHT_ASSERT(col >= 0 && col < 4); return m_v[4*col + row]; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- template void Matrix4::setRow(int row, const Vector4& vector) { CVF_TIGHT_ASSERT(row >= 0 && row < 4); m_v[row] = vector.x(); m_v[row + 4] = vector.y(); m_v[row + 8] = vector.z(); m_v[row + 12] = vector.w(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- template Vector4 Matrix4::row(int row) const { CVF_TIGHT_ASSERT(row >= 0 && row < 4); return Vector4(m_v[row], m_v[row + 4], m_v[row + 8], m_v[row + 12]); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- template void Matrix4::setCol(int column, const Vector4& vector) { CVF_TIGHT_ASSERT(column >= 0 && column < 4); m_v[4*column] = vector.x(); m_v[4*column + 1] = vector.y(); m_v[4*column + 2] = vector.z(); m_v[4*column + 3] = vector.w(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- template Vector4 Matrix4::col(int column) const { CVF_TIGHT_ASSERT(column >= 0 && column < 4); return Vector4(m_v[4*column], m_v[4*column + 1], m_v[4*column + 2], m_v[4*column + 3]); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- template template void Matrix4::set(const Matrix4& mat) { const T* matPtr = mat.ptr(); for (int i = 0; i < 16; i++) { m_v[i] = static_cast(matPtr[i]); } } //---------------------------------------------------------------------------------------------------- /// Extracts the translation part of the transformation matrix //---------------------------------------------------------------------------------------------------- template Vector3 Matrix4::translation() const { return Vector3(m_v[e03], m_v[e13], m_v[e23]); } //---------------------------------------------------------------------------------------------------- /// Sets the translation transformation part of the matrix //---------------------------------------------------------------------------------------------------- template void Matrix4::setTranslation(const Vector3& trans) { m_v[e03] = trans.x(); m_v[e13] = trans.y(); m_v[e23] = trans.z(); } //---------------------------------------------------------------------------------------------------- /// Adds translation by pre-multiplying the matrix with a matrix containing the specified translation /// /// Adds translation to this (transformation) matrix by pre-multiplying the current matrix M with /// a matrix T containing only the specified translation. /// Calling this function has the effect of doing the multiplication M' = T x M /// /// \param trans Specifies the X, Y and Z components of the translation. //---------------------------------------------------------------------------------------------------- template void Matrix4::translatePreMultiply(const Vector3& trans) { m_v[e00] += trans.x()*m_v[e30]; m_v[e01] += trans.x()*m_v[e31]; m_v[e02] += trans.x()*m_v[e32]; m_v[e03] += trans.x()*m_v[e33]; m_v[e10] += trans.y()*m_v[e30]; m_v[e11] += trans.y()*m_v[e31]; m_v[e12] += trans.y()*m_v[e32]; m_v[e13] += trans.y()*m_v[e33]; m_v[e20] += trans.z()*m_v[e30]; m_v[e21] += trans.z()*m_v[e31]; m_v[e22] += trans.z()*m_v[e32]; m_v[e23] += trans.z()*m_v[e33]; } //---------------------------------------------------------------------------------------------------- /// Adds translation by post-multiplying the matrix with a matrix containing the specified translation /// /// Adds translation to this (transformation) matrix by post-multiplying the current matrix M with /// a matrix T containing only the specified translation. /// Calling this function has the effect of doing the multiplication M' = M x T /// /// \param trans Specifies the X, Y and Z coordinates of the translation. //---------------------------------------------------------------------------------------------------- template void Matrix4::translatePostMultiply(const Vector3& trans) { m_v[e03] += trans.x()*m_v[e00] + trans.y()*m_v[e01] + trans.z()*m_v[e02]; m_v[e13] += trans.x()*m_v[e10] + trans.y()*m_v[e11] + trans.z()*m_v[e12]; m_v[e23] += trans.x()*m_v[e20] + trans.y()*m_v[e21] + trans.z()*m_v[e22]; m_v[e33] += trans.x()*m_v[e30] + trans.y()*m_v[e31] + trans.z()*m_v[e32]; } //---------------------------------------------------------------------------------------------------- /// //---------------------------------------------------------------------------------------------------- template bool Matrix4::invert() { // Use double internally here const double m00 = static_cast(m_v[e00]); const double m10 = static_cast(m_v[e10]); const double m20 = static_cast(m_v[e20]); const double m30 = static_cast(m_v[e30]); const double m01 = static_cast(m_v[e01]); const double m11 = static_cast(m_v[e11]); const double m21 = static_cast(m_v[e21]); const double m31 = static_cast(m_v[e31]); const double m02 = static_cast(m_v[e02]); const double m12 = static_cast(m_v[e12]); const double m22 = static_cast(m_v[e22]); const double m32 = static_cast(m_v[e32]); const double m03 = static_cast(m_v[e03]); const double m13 = static_cast(m_v[e13]); const double m23 = static_cast(m_v[e23]); const double m33 = static_cast(m_v[e33]); const double s0 = m00 * m11 - m01 * m10; const double s1 = m00 * m12 - m02 * m10; const double s2 = m00 * m13 - m03 * m10; const double s3 = m01 * m12 - m02 * m11; const double s4 = m01 * m13 - m03 * m11; const double s5 = m02 * m13 - m03 * m12; const double c5 = m22 * m33 - m23 * m32; const double c4 = m21 * m33 - m23 * m31; const double c3 = m21 * m32 - m22 * m31; const double c2 = m20 * m33 - m23 * m30; const double c1 = m20 * m32 - m22 * m30; const double c0 = m20 * m31 - m21 * m30; const double det = s0*c5 - s1*c4 + s2*c3 + s3*c2 - s4*c1 + s5*c0; if (Math::abs(det) > std::numeric_limits::epsilon()) { const double invDet = 1/det; m_v[e00] = static_cast( ( m11 * c5 - m12 * c4 + m13 * c3 ) * invDet ); m_v[e10] = static_cast( ( - m10 * c5 + m12 * c2 - m13 * c1 ) * invDet ); m_v[e20] = static_cast( ( m10 * c4 - m11 * c2 + m13 * c0 ) * invDet ); m_v[e30] = static_cast( ( - m10 * c3 + m11 * c1 - m12 * c0 ) * invDet ); m_v[e01] = static_cast( ( - m01 * c5 + m02 * c4 - m03 * c3 ) * invDet ); m_v[e11] = static_cast( ( m00 * c5 - m02 * c2 + m03 * c1 ) * invDet ); m_v[e21] = static_cast( ( - m00 * c4 + m01 * c2 - m03 * c0 ) * invDet ); m_v[e31] = static_cast( ( m00 * c3 - m01 * c1 + m02 * c0 ) * invDet ); m_v[e02] = static_cast( ( m31 * s5 - m32 * s4 + m33 * s3 ) * invDet ); m_v[e12] = static_cast( ( - m30 * s5 + m32 * s2 - m33 * s1 ) * invDet ); m_v[e22] = static_cast( ( m30 * s4 - m31 * s2 + m33 * s0 ) * invDet ); m_v[e32] = static_cast( ( - m30 * s3 + m31 * s1 - m32 * s0 ) * invDet ); m_v[e03] = static_cast( ( - m21 * s5 + m22 * s4 - m23 * s3 ) * invDet ); m_v[e13] = static_cast( ( m20 * s5 - m22 * s2 + m23 * s1 ) * invDet ); m_v[e23] = static_cast( ( - m20 * s4 + m21 * s2 - m23 * s0 ) * invDet ); m_v[e33] = static_cast( ( m20 * s3 - m21 * s1 + m22 * s0 ) * invDet ); return true; } else { return false; } } //---------------------------------------------------------------------------------------------------- /// //---------------------------------------------------------------------------------------------------- template const Matrix4 Matrix4::getInverted(bool* pInvertible) const { Matrix4 m(*this); if (m.invert()) { if (pInvertible) *pInvertible = true; } else { if (pInvertible) *pInvertible = false; m.setZero(); } return m; } //---------------------------------------------------------------------------------------------------- /// //---------------------------------------------------------------------------------------------------- template S Matrix4::determinant() const { // Consider using double precision for the intermediate calculations here // Haven't seen any direct need for it yet, but good old GLview API did that const S a0 = m_v[e00]*m_v[e11] - m_v[e01]*m_v[e10]; const S a1 = m_v[e00]*m_v[e12] - m_v[e02]*m_v[e10]; const S a2 = m_v[e00]*m_v[e13] - m_v[e03]*m_v[e10]; const S a3 = m_v[e01]*m_v[e12] - m_v[e02]*m_v[e11]; const S a4 = m_v[e01]*m_v[e13] - m_v[e03]*m_v[e11]; const S a5 = m_v[e02]*m_v[e13] - m_v[e03]*m_v[e12]; const S b0 = m_v[e20]*m_v[e31] - m_v[e21]*m_v[e30]; const S b1 = m_v[e20]*m_v[e32] - m_v[e22]*m_v[e30]; const S b2 = m_v[e20]*m_v[e33] - m_v[e23]*m_v[e30]; const S b3 = m_v[e21]*m_v[e32] - m_v[e22]*m_v[e31]; const S b4 = m_v[e21]*m_v[e33] - m_v[e23]*m_v[e31]; const S b5 = m_v[e22]*m_v[e33] - m_v[e23]*m_v[e32]; return (a0*b5 - a1*b4 + a2*b3 + a3*b2 - a4*b1 + a5*b0); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- template void Matrix4::transpose() { S tmp; int i, j; for (i = 0; i < 4; i++) { for (j = i + 1; j < 4; j++) { tmp = m_v[j + 4*i]; m_v[j + 4*i] = m_v[4*j + i]; m_v[4*j + i] = tmp; } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- template const Matrix4 Matrix4::getTransposed() const { Matrix4 m(*this); m.transpose(); return m; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- template void Matrix4::setFromMatrix3(const Matrix3& mat3) { m_v[e00] = mat3.rowCol(0, 0); m_v[e01] = mat3.rowCol(0, 1); m_v[e02] = mat3.rowCol(0, 2); m_v[e03] = 0; m_v[e10] = mat3.rowCol(1, 0); m_v[e11] = mat3.rowCol(1, 1); m_v[e12] = mat3.rowCol(1, 2); m_v[e13] = 0; m_v[e20] = mat3.rowCol(2, 0); m_v[e21] = mat3.rowCol(2, 1); m_v[e22] = mat3.rowCol(2, 2); m_v[e23] = 0; m_v[e30] = 0; m_v[e31] = 0; m_v[e32] = 0; m_v[e33] = 1; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- template Matrix3 Matrix4::toMatrix3() const { return Matrix3(m_v[e00], m_v[e01], m_v[e02], m_v[e10], m_v[e11], m_v[e12], m_v[e20], m_v[e21], m_v[e22]); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- template void Matrix4::toMatrix3(Matrix3* mat3) const { CVF_ASSERT(mat3); mat3->setRowCol(0, 0, m_v[e00]); mat3->setRowCol(0, 1, m_v[e01]); mat3->setRowCol(0, 2, m_v[e02]); mat3->setRowCol(1, 0, m_v[e10]); mat3->setRowCol(1, 1, m_v[e11]); mat3->setRowCol(1, 2, m_v[e12]); mat3->setRowCol(2, 0, m_v[e20]); mat3->setRowCol(2, 1, m_v[e21]); mat3->setRowCol(2, 2, m_v[e22]); } //---------------------------------------------------------------------------------------------------- /// //---------------------------------------------------------------------------------------------------- template const S* Matrix4::ptr() const { return m_v; } //---------------------------------------------------------------------------------------------------- /// Static member function that creates a transformation matrix containing only translation //---------------------------------------------------------------------------------------------------- template Matrix4 Matrix4::fromTranslation(const Vector3& trans) { return Matrix4(1, 0, 0, trans.x(), 0, 1, 0, trans.y(), 0, 0, 1, trans.z(), 0, 0, 0, 1); } //---------------------------------------------------------------------------------------------------- /// Static member function that creates a transformation matrix containing only scaling //---------------------------------------------------------------------------------------------------- template Matrix4 Matrix4::fromScaling(const Vector3& scale) { return Matrix4(scale.x(), 0, 0, 0, 0, scale.y(), 0, 0, 0, 0, scale.z(), 0, 0, 0, 0, 1); } //---------------------------------------------------------------------------------------------------- /// //---------------------------------------------------------------------------------------------------- template Matrix4 Matrix4::fromRotation(Vector3 axis, S angle) { axis.normalize(); S rcos = Math::cos(angle); S rsin = Math::sin(angle); Matrix4 m; m.m_v[e00] = rcos + axis.x()*axis.x()*(1 - rcos); m.m_v[e10] = axis.z() * rsin + axis.y()*axis.x()*(1 - rcos); m.m_v[e20] = -axis.y() * rsin + axis.z()*axis.x()*(1 - rcos); m.m_v[e01] = -axis.z() * rsin + axis.x()*axis.y()*(1 - rcos); m.m_v[e11] = rcos + axis.y()*axis.y()*(1 - rcos); m.m_v[e21] = axis.x() * rsin + axis.z()*axis.y()*(1 - rcos); m.m_v[e02] = axis.y() * rsin + axis.x()*axis.z()*(1 - rcos); m.m_v[e12] = -axis.x() * rsin + axis.y()*axis.z()*(1 - rcos); m.m_v[e22] = rcos + axis.z()*axis.z()*(1 - rcos); return m; } //---------------------------------------------------------------------------------------------------- /// Create a rotation matrix that will align the global X, Y and Z axes with the specified axes. /// /// Note that at least one axis must be specified and all specified axes must be normalized. /// If two or three axes are specified, they must be orthogonal to each other. /// /// \param xAxis Orientation of x axis /// \param yAxis Orientation of y axis /// \param zAxis Orientation of z axis //---------------------------------------------------------------------------------------------------- template Matrix4 Matrix4::fromCoordSystemAxes(const Vector3* xAxis, const Vector3* yAxis, const Vector3* zAxis) { Vector3 x(0, 0, 0); Vector3 y(0, 0, 0); Vector3 z(0, 0, 0); if (xAxis && yAxis && zAxis) { x = *xAxis; y = *yAxis; z = *zAxis; } else if (xAxis && yAxis) { x = *xAxis; y = *yAxis; z = x ^ y; } else if (xAxis && zAxis) { x = *xAxis; z = *zAxis; y = z ^ x; } else if (yAxis && zAxis) { y = *yAxis; z = *zAxis; x = y ^ z; } else if (xAxis) { xAxis->createOrthonormalBasis(0, &x, &y, &z); } else if (yAxis) { yAxis->createOrthonormalBasis(1, &x, &y, &z); } else if (zAxis) { zAxis->createOrthonormalBasis(2, &x, &y, &z); } else { CVF_FAIL_MSG("Must specify at least one axis"); } Matrix4 m; m.setIdentity(); m.setCol(0, Vector4(x, 0)); m.setCol(1, Vector4(y, 0)); m.setCol(2, Vector4(z, 0)); return m; } //-------------------------------------------------------------------------------------------------- /// Post multiplication: matrix * column vector /// /// v' = M*v //-------------------------------------------------------------------------------------------------- template cvf::Vector4 operator*(const cvf::Matrix4& m, const cvf::Vector4& v) { cvf::Vector4 vec( v.x()*m.rowCol(0,0) + v.y()*m.rowCol(0,1) + v.z()*m.rowCol(0,2) + v.w()*m.rowCol(0,3), v.x()*m.rowCol(1,0) + v.y()*m.rowCol(1,1) + v.z()*m.rowCol(1,2) + v.w()*m.rowCol(1,3), v.x()*m.rowCol(2,0) + v.y()*m.rowCol(2,1) + v.z()*m.rowCol(2,2) + v.w()*m.rowCol(2,3), v.x()*m.rowCol(3,0) + v.y()*m.rowCol(3,1) + v.z()*m.rowCol(3,2) + v.w()*m.rowCol(3,3) ); return vec; } }