/* * This program source code file is part of KICAD, a free EDA CAD application. * * Copyright (C) 2012 Torsten Hueter, torstenhtr gmx.de * Copyright (C) 2012 Kicad Developers, see change_log.txt for contributors. * * Matrix class (3x3) * * This program 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 2 * of the License, or (at your option) any later version. *- * This program 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 this program; if not, you may find one here: * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * or you may search the http://www.gnu.org website for the version 2 license, * or you may write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef MATRIX3X3_H_ #define MATRIX3X3_H_ #include /** * Class MATRIX3x3 describes a general 3x3 matrix. * * Any linear transformation in 2D can be represented * by a homogeneous 3x3 transformation matrix. Given a vector x, the linear transformation * with the transformation matrix M is given as * * x' = M * x * * To represent an affine transformation, homogeneous coordinates have to be used. That means * the 2D-vector (x, y) has to be extended to a 3D-vector by a third component (x, y, 1). * * Transformations can be easily combined by matrix multiplication. * * A * (B * x ) = (A * B) * x * ( A, B: transformation matrices, x: vector ) * * This class was implemented using templates, so flexible type combinations are possible. * */ // Forward declaration for template friends template class MATRIX3x3; template std::ostream& operator<<( std::ostream& aStream, const MATRIX3x3& aMatrix ); template class MATRIX3x3 { public: T m_data[3][3]; /** * @brief Constructor * * Initialize all matrix members to zero. */ MATRIX3x3(); /** * @brief Constructor * * Initialize with given matrix members * * @param a00 is the component [0,0]. * @param a01 is the component [0,1]. * @param a02 is the component [0,2]. * @param a10 is the component [1,0]. * @param a11 is the component [1,1]. * @param a12 is the component [1,2]. * @param a20 is the component [2,0]. * @param a21 is the component [2,1]. * @param a22 is the component [2,2]. */ MATRIX3x3( T a00, T a01, T a02, T a10, T a11, T a12, T a20, T a21, T a22 ); /** * @brief Set the matrix to the identity matrix. * * The diagonal components of the matrix are set to 1. */ void SetIdentity(); /** * @brief Set the translation components of the matrix. * * @param aTranslation is the translation, specified as 2D-vector. */ void SetTranslation( VECTOR2 aTranslation ); /** * @brief Get the translation components of the matrix. * * @return is the translation (2D-vector). */ VECTOR2 GetTranslation() const; /** * @brief Set the rotation components of the matrix. * * The angle needs to have a positive value for an anti-clockwise rotation. * * @param aAngle is the rotation angle in [rad]. */ void SetRotation( T aAngle ); /** * @brief Set the scale components of the matrix. * * @param aScale contains the scale factors, specified as 2D-vector. */ void SetScale( VECTOR2 aScale ); /** * @brief Get the scale components of the matrix. * * @return the scale factors, specified as 2D-vector. */ VECTOR2 GetScale() const; /** * @brief Compute the determinant of the matrix. * * @return the determinant value. */ T Determinant() const; /** * @brief Determine the inverse of the matrix. * * The inverse of a transformation matrix can be used to revert a transformation. * * x = Minv * ( M * x ) * ( M: transformation matrix, Minv: inverse transformation matrix, x: vector) * * @return the inverse matrix. */ MATRIX3x3 Inverse() const; /** * @brief Get the transpose of the matrix. * * @return the transpose matrix. */ MATRIX3x3 Transpose() const; /** * @brief Output to a stream. */ friend std::ostream& operator<<( std::ostream& aStream, const MATRIX3x3& aMatrix ); }; // Operators //! @brief Matrix multiplication template MATRIX3x3 const operator*( MATRIX3x3 const& aA, MATRIX3x3 const& aB ); //! @brief Multiplication with a 2D vector, the 3rd z-component is assumed to be 1 template VECTOR2 const operator*( MATRIX3x3 const& aA, VECTOR2 const& aB ); //! @brief Multiplication with a scalar template MATRIX3x3 const operator*( MATRIX3x3 const& aA, T aScalar ); template MATRIX3x3 const operator*( T aScalar, MATRIX3x3 const& aMatrix ); // ---------------------- // --- Implementation --- // ---------------------- template MATRIX3x3::MATRIX3x3() { for( int j = 0; j < 3; j++ ) { for( int i = 0; i < 3; i++ ) { m_data[i][j] = 0.0; } } } template MATRIX3x3::MATRIX3x3( T a00, T a01, T a02, T a10, T a11, T a12, T a20, T a21, T a22 ) { m_data[0][0] = a00; m_data[0][1] = a01; m_data[0][2] = a02; m_data[1][0] = a10; m_data[1][1] = a11; m_data[1][2] = a12; m_data[2][0] = a20; m_data[2][1] = a21; m_data[2][2] = a22; } template void MATRIX3x3::SetIdentity( void ) { for( int j = 0; j < 3; j++ ) { for( int i = 0; i < 3; i++ ) { if( i == j ) m_data[i][j] = 1.0; else m_data[i][j] = 0.0; } } } template void MATRIX3x3::SetTranslation( VECTOR2 aTranslation ) { m_data[0][2] = aTranslation.x; m_data[1][2] = aTranslation.y; } template VECTOR2 MATRIX3x3::GetTranslation() const { VECTOR2 result; result.x = m_data[0][2]; result.y = m_data[1][2]; return result; } template void MATRIX3x3::SetRotation( T aAngle ) { T cosValue = cos( aAngle ); T sinValue = sin( aAngle ); m_data[0][0] = cosValue; m_data[0][1] = -sinValue; m_data[1][0] = sinValue; m_data[1][1] = cosValue; } template void MATRIX3x3::SetScale( VECTOR2 aScale ) { m_data[0][0] = aScale.x; m_data[1][1] = aScale.y; } template VECTOR2 MATRIX3x3::GetScale() const { VECTOR2 result( m_data[0][0], m_data[1][1] ); return result; } template MATRIX3x3 const operator*( MATRIX3x3 const& aA, MATRIX3x3 const& aB ) { MATRIX3x3 result; for( int i = 0; i < 3; i++ ) { for( int j = 0; j < 3; j++ ) { result.m_data[i][j] = aA.m_data[i][0] * aB.m_data[0][j] + aA.m_data[i][1] * aB.m_data[1][j] + aA.m_data[i][2] * aB.m_data[2][j]; } } return result; } template VECTOR2 const operator*( MATRIX3x3 const& aMatrix, VECTOR2 const& aVector ) { VECTOR2 result( 0, 0 ); result.x = aMatrix.m_data[0][0] * aVector.x + aMatrix.m_data[0][1] * aVector.y + aMatrix.m_data[0][2]; result.y = aMatrix.m_data[1][0] * aVector.x + aMatrix.m_data[1][1] * aVector.y + aMatrix.m_data[1][2]; return result; } template T MATRIX3x3::Determinant() const { return m_data[0][0] * ( m_data[1][1] * m_data[2][2] - m_data[1][2] * m_data[2][1] ) - m_data[0][1] * ( m_data[1][0] * m_data[2][2] - m_data[1][2] * m_data[2][0] ) + m_data[0][2] * ( m_data[1][0] * m_data[2][1] - m_data[1][1] * m_data[2][0] ); } template MATRIX3x3 const operator*( MATRIX3x3 const& aMatrix, S aScalar ) { MATRIX3x3 result; for( int i = 0; i < 3; i++ ) { for( int j = 0; j < 3; j++ ) { result.m_data[i][j] = aMatrix.m_data[i][j] * aScalar; } } return result; } template MATRIX3x3 const operator*( S aScalar, MATRIX3x3 const& aMatrix ) { return aMatrix * aScalar; } template MATRIX3x3 MATRIX3x3::Inverse() const { MATRIX3x3 result; result.m_data[0][0] = m_data[1][1] * m_data[2][2] - m_data[2][1] * m_data[1][2]; result.m_data[0][1] = m_data[0][2] * m_data[2][1] - m_data[2][2] * m_data[0][1]; result.m_data[0][2] = m_data[0][1] * m_data[1][2] - m_data[1][1] * m_data[0][2]; result.m_data[1][0] = m_data[1][2] * m_data[2][0] - m_data[2][2] * m_data[1][0]; result.m_data[1][1] = m_data[0][0] * m_data[2][2] - m_data[2][0] * m_data[0][2]; result.m_data[1][2] = m_data[0][2] * m_data[1][0] - m_data[1][2] * m_data[0][0]; result.m_data[2][0] = m_data[1][0] * m_data[2][1] - m_data[2][0] * m_data[1][1]; result.m_data[2][1] = m_data[0][1] * m_data[2][0] - m_data[2][1] * m_data[0][0]; result.m_data[2][2] = m_data[0][0] * m_data[1][1] - m_data[1][0] * m_data[0][1]; return result * ( 1.0 / Determinant() ); } template MATRIX3x3 MATRIX3x3::Transpose() const { MATRIX3x3 result; for( int i = 0; i < 3; i++ ) { for( int j = 0; j < 3; j++ ) { result.m_data[j][i] = m_data[i][j]; } } return result; } template std::ostream& operator<<( std::ostream& aStream, const MATRIX3x3& aMatrix ) { for( int i = 0; i < 3; i++ ) { aStream << "| "; for( int j = 0; j < 3; j++ ) { aStream << aMatrix.m_data[i][j]; aStream << " "; } aStream << "|"; aStream << "\n"; } return aStream; } /* Default specializations */ typedef MATRIX3x3 MATRIX3x3D; #endif /* MATRIX3X3_H_ */