/* * SOLID - Software Library for Interference Detection * * Copyright (C) 2001-2003 Dtecta. All rights reserved. * * This library may be distributed under the terms of the Q Public License * (QPL) as defined by Trolltech AS of Norway and appearing in the file * LICENSE.QPL included in the packaging of this file. * * This library may be distributed and/or modified under the terms of the * GNU General Public License (GPL) version 2 as published by the Free Software * Foundation and appearing in the file LICENSE.GPL included in the * packaging of this file. * * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * Commercial use or any other use of this library not covered by either * the QPL or the GPL requires an additional license from Dtecta. * Please contact info@dtecta.com for enquiries about the terms of commercial * use of this library. */ #ifndef MATRIX3X3_H #define MATRIX3X3_H #include #include "Vector3.h" #include "Quaternion.h" namespace MT { // Row-major 3x3 matrix template class Matrix3x3 { public: Matrix3x3() {} template explicit Matrix3x3(const Scalar2 *m) { setValue(m); } explicit Matrix3x3(const Quaternion& q) { setRotation(q); } template Matrix3x3(const Scalar2& yaw, const Scalar2& pitch, const Scalar2& roll) { setEuler(yaw, pitch, roll); } template Matrix3x3(const Scalar2& xx, const Scalar2& xy, const Scalar2& xz, const Scalar2& yx, const Scalar2& yy, const Scalar2& yz, const Scalar2& zx, const Scalar2& zy, const Scalar2& zz) { setValue(xx, xy, xz, yx, yy, yz, zx, zy, zz); } Vector3& operator[](int i) { assert(0 <= i && i < 3); return m_el[i]; } const Vector3& operator[](int i) const { assert(0 <= i && i < 3); return m_el[i]; } Matrix3x3& operator*=(const Matrix3x3& m); template void setValue(const Scalar2 *m) { m_el[0][0] = Scalar(m[0]); m_el[1][0] = Scalar(m[1]); m_el[2][0] = Scalar(m[2]); m_el[0][1] = Scalar(m[4]); m_el[1][1] = Scalar(m[5]); m_el[2][1] = Scalar(m[6]); m_el[0][2] = Scalar(m[8]); m_el[1][2] = Scalar(m[9]); m_el[2][2] = Scalar(m[10]); } template void setValue(const Scalar2& xx, const Scalar2& xy, const Scalar2& xz, const Scalar2& yx, const Scalar2& yy, const Scalar2& yz, const Scalar2& zx, const Scalar2& zy, const Scalar2& zz) { m_el[0][0] = Scalar(xx); m_el[0][1] = Scalar(xy); m_el[0][2] = Scalar(xz); m_el[1][0] = Scalar(yx); m_el[1][1] = Scalar(yy); m_el[1][2] = Scalar(yz); m_el[2][0] = Scalar(zx); m_el[2][1] = Scalar(zy); m_el[2][2] = Scalar(zz); } void setRotation(const Quaternion& q) { Scalar d = q.length2(); assert(d != Scalar(0.0)); Scalar s = Scalar(2.0) / d; Scalar xs = q[0] * s, ys = q[1] * s, zs = q[2] * s; Scalar wx = q[3] * xs, wy = q[3] * ys, wz = q[3] * zs; Scalar xx = q[0] * xs, xy = q[0] * ys, xz = q[0] * zs; Scalar yy = q[1] * ys, yz = q[1] * zs, zz = q[2] * zs; setValue(Scalar(1.0) - (yy + zz), xy - wz, xz + wy, xy + wz, Scalar(1.0) - (xx + zz), yz - wx, xz - wy, yz + wx, Scalar(1.0) - (xx + yy)); } template void setEuler(const Scalar2& yaw, const Scalar2& pitch, const Scalar2& roll) { Scalar cy(Scalar_traits::cos(yaw)); Scalar sy(Scalar_traits::sin(yaw)); Scalar cp(Scalar_traits::cos(pitch)); Scalar sp(Scalar_traits::sin(pitch)); Scalar cr(Scalar_traits::cos(roll)); Scalar sr(Scalar_traits::sin(roll)); Scalar cc = cy * cr; Scalar cs = cy * sr; Scalar sc = sy * cr; Scalar ss = sy * sr; setValue(cy * cp, -sc + sp * cs, ss - sp * cc, sy * cp, cc + sp * ss, -cs + sp * sc, -sp, cp * sr, cp * cr); } void setIdentity() { setValue(Scalar(1.0), Scalar(0.0), Scalar(0.0), Scalar(0.0), Scalar(1.0), Scalar(0.0), Scalar(0.0), Scalar(0.0), Scalar(1.0)); } template void getValue(Scalar2 *m) const { m[0] = Scalar2(m_el[0][0]); m[1] = Scalar2(m_el[1][0]); m[2] = Scalar2(m_el[2][0]); m[3] = Scalar2(0.0); m[4] = Scalar2(m_el[0][1]); m[5] = Scalar2(m_el[1][1]); m[6] = Scalar2(m_el[2][1]); m[7] = Scalar2(0.0); m[8] = Scalar2(m_el[0][2]); m[9] = Scalar2(m_el[1][2]); m[10] = Scalar2(m_el[2][2]); m[11] = Scalar2(0.0); } void getRotation(Quaternion& q) const { Scalar trace = m_el[0][0] + m_el[1][1] + m_el[2][2]; if (trace > Scalar(0.0)) { Scalar s = Scalar_traits::sqrt(trace + Scalar(1.0)); q[3] = s * Scalar(0.5); s = Scalar(0.5) / s; q[0] = (m_el[2][1] - m_el[1][2]) * s; q[1] = (m_el[0][2] - m_el[2][0]) * s; q[2] = (m_el[1][0] - m_el[0][1]) * s; } else { int i = m_el[0][0] < m_el[1][1] ? (m_el[1][1] < m_el[2][2] ? 2 : 1) : (m_el[0][0] < m_el[2][2] ? 2 : 0); int j = (i + 1) % 3; int k = (i + 2) % 3; Scalar s = Scalar_traits::sqrt(m_el[i][i] - m_el[j][j] - m_el[k][k] + Scalar(1.0)); q[i] = s * Scalar(0.5); s = Scalar(0.5) / s; q[3] = (m_el[k][j] - m_el[j][k]) * s; q[j] = (m_el[j][i] + m_el[i][j]) * s; q[k] = (m_el[k][i] + m_el[i][k]) * s; } } template void getEuler(Scalar2& yaw, Scalar2& pitch, Scalar2& roll) const { pitch = Scalar2(Scalar_traits::asin(-m_el[2][0])); if (pitch < Scalar_traits::TwoTimesPi()) { if (pitch > Scalar_traits::TwoTimesPi()) { yaw = Scalar2(Scalar_traits::atan2(m_el[1][0], m_el[0][0])); roll = Scalar2(Scalar_traits::atan2(m_el[2][1], m_el[2][2])); } else { yaw = Scalar2(-Scalar_traits::atan2(-m_el[0][1], m_el[0][2])); roll = Scalar2(0.0); } } else { yaw = Scalar2(Scalar_traits::atan2(-m_el[0][1], m_el[0][2])); roll = Scalar2(0.0); } } Vector3 getScaling() const { return Vector3(m_el[0][0] * m_el[0][0] + m_el[1][0] * m_el[1][0] + m_el[2][0] * m_el[2][0], m_el[0][1] * m_el[0][1] + m_el[1][1] * m_el[1][1] + m_el[2][1] * m_el[2][1], m_el[0][2] * m_el[0][2] + m_el[1][2] * m_el[1][2] + m_el[2][2] * m_el[2][2]); } Matrix3x3 scaled(const Vector3& s) const { return Matrix3x3(m_el[0][0] * s[0], m_el[0][1] * s[1], m_el[0][2] * s[2], m_el[1][0] * s[0], m_el[1][1] * s[1], m_el[1][2] * s[2], m_el[2][0] * s[0], m_el[2][1] * s[1], m_el[2][2] * s[2]); } Scalar determinant() const; Matrix3x3 adjoint() const; Matrix3x3 absolute() const; Matrix3x3 transpose() const; Matrix3x3 inverse() const; Matrix3x3 transposeTimes(const Matrix3x3& m) const; Matrix3x3 timesTranspose(const Matrix3x3& m) const; Scalar tdot(int c, const Vector3& v) const { return m_el[0][c] * v[0] + m_el[1][c] * v[1] + m_el[2][c] * v[2]; } protected: Scalar cofac(int r1, int c1, int r2, int c2) const { return m_el[r1][c1] * m_el[r2][c2] - m_el[r1][c2] * m_el[r2][c1]; } Vector3 m_el[3]; }; template inline std::ostream& operator<<(std::ostream& os, const Matrix3x3& m) { return os << m[0] << std::endl << m[1] << std::endl << m[2] << std::endl; } template inline Matrix3x3& Matrix3x3::operator*=(const Matrix3x3& m) { setValue(m.tdot(0, m_el[0]), m.tdot(1, m_el[0]), m.tdot(2, m_el[0]), m.tdot(0, m_el[1]), m.tdot(1, m_el[1]), m.tdot(2, m_el[1]), m.tdot(0, m_el[2]), m.tdot(1, m_el[2]), m.tdot(2, m_el[2])); return *this; } template inline Scalar Matrix3x3::determinant() const { return triple((*this)[0], (*this)[1], (*this)[2]); } template inline Matrix3x3 Matrix3x3::absolute() const { return Matrix3x3( Scalar_traits::abs(m_el[0][0]), Scalar_traits::abs(m_el[0][1]), Scalar_traits::abs(m_el[0][2]), Scalar_traits::abs(m_el[1][0]), Scalar_traits::abs(m_el[1][1]), Scalar_traits::abs(m_el[1][2]), Scalar_traits::abs(m_el[2][0]), Scalar_traits::abs(m_el[2][1]), Scalar_traits::abs(m_el[2][2])); } template inline Matrix3x3 Matrix3x3::transpose() const { return Matrix3x3(m_el[0][0], m_el[1][0], m_el[2][0], m_el[0][1], m_el[1][1], m_el[2][1], m_el[0][2], m_el[1][2], m_el[2][2]); } template inline Matrix3x3 Matrix3x3::adjoint() const { return Matrix3x3(cofac(1, 1, 2, 2), cofac(0, 2, 2, 1), cofac(0, 1, 1, 2), cofac(1, 2, 2, 0), cofac(0, 0, 2, 2), cofac(0, 2, 1, 0), cofac(1, 0, 2, 1), cofac(0, 1, 2, 0), cofac(0, 0, 1, 1)); } template inline Matrix3x3 Matrix3x3::inverse() const { Vector3 co(cofac(1, 1, 2, 2), cofac(1, 2, 2, 0), cofac(1, 0, 2, 1)); Scalar det = (*this)[0].dot(co); assert(det != Scalar(0.0)); Scalar s = Scalar(1.0) / det; return Matrix3x3(co[0] * s, cofac(0, 2, 2, 1) * s, cofac(0, 1, 1, 2) * s, co[1] * s, cofac(0, 0, 2, 2) * s, cofac(0, 2, 1, 0) * s, co[2] * s, cofac(0, 1, 2, 0) * s, cofac(0, 0, 1, 1) * s); } template inline Matrix3x3 Matrix3x3::transposeTimes(const Matrix3x3& m) const { return Matrix3x3( m_el[0][0] * m[0][0] + m_el[1][0] * m[1][0] + m_el[2][0] * m[2][0], m_el[0][0] * m[0][1] + m_el[1][0] * m[1][1] + m_el[2][0] * m[2][1], m_el[0][0] * m[0][2] + m_el[1][0] * m[1][2] + m_el[2][0] * m[2][2], m_el[0][1] * m[0][0] + m_el[1][1] * m[1][0] + m_el[2][1] * m[2][0], m_el[0][1] * m[0][1] + m_el[1][1] * m[1][1] + m_el[2][1] * m[2][1], m_el[0][1] * m[0][2] + m_el[1][1] * m[1][2] + m_el[2][1] * m[2][2], m_el[0][2] * m[0][0] + m_el[1][2] * m[1][0] + m_el[2][2] * m[2][0], m_el[0][2] * m[0][1] + m_el[1][2] * m[1][1] + m_el[2][2] * m[2][1], m_el[0][2] * m[0][2] + m_el[1][2] * m[1][2] + m_el[2][2] * m[2][2]); } template inline Matrix3x3 Matrix3x3::timesTranspose(const Matrix3x3& m) const { return Matrix3x3( m_el[0].dot(m[0]), m_el[0].dot(m[1]), m_el[0].dot(m[2]), m_el[1].dot(m[0]), m_el[1].dot(m[1]), m_el[1].dot(m[2]), m_el[2].dot(m[0]), m_el[2].dot(m[1]), m_el[2].dot(m[2])); } template inline Vector3 operator*(const Matrix3x3& m, const Vector3& v) { return Vector3(m[0].dot(v), m[1].dot(v), m[2].dot(v)); } template inline Vector3 operator*(const Vector3& v, const Matrix3x3& m) { return Vector3(m.tdot(0, v), m.tdot(1, v), m.tdot(2, v)); } template inline Matrix3x3 operator*(const Matrix3x3& m1, const Matrix3x3& m2) { return Matrix3x3( m2.tdot(0, m1[0]), m2.tdot(1, m1[0]), m2.tdot(2, m1[0]), m2.tdot(0, m1[1]), m2.tdot(1, m1[1]), m2.tdot(2, m1[1]), m2.tdot(0, m1[2]), m2.tdot(1, m1[2]), m2.tdot(2, m1[2])); } } #endif