#pragma region CPL License /* Nuclex Native Framework Copyright (C) 2002-2015 Nuclex Development Labs This library is free software; you can redistribute it and/or modify it under the terms of the IBM Common Public License as published by the IBM Corporation; either version 1.0 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 IBM Common Public License for more details. You should have received a copy of the IBM Common Public License along with this library */ #pragma endregion // CPL License #ifndef NUCLEX_GEOMETRY_MATRIX33_H #define NUCLEX_GEOMETRY_MATRIX33_H #include "Math.h" #include "Nuclex/Geometry/Config.h" #include "Nuclex/Geometry/Math.h" #include "Nuclex/Geometry/Point3.h" #include "Nuclex/Geometry/Vector3.h" #include "Nuclex/Geometry/Areas/Rectangle2.h" #include namespace Nuclex { namespace Geometry { // ------------------------------------------------------------------------------------------- // /// Matrix of 3x3 elements (2D transformation or 3D rotation) /// /// /// This kind of matrix can be used to express a complete 2D transformation (rotation /// translation and shear/skew): /// /// /// /// _ _ /// | | /// | cos(phi), -sin(phi), x | /// | sin(phi), cos(phi), y | Note: in-memory layout is transposed /// | 0, 0, 1 | /// |_ _| /// /// /// /// It can also be used to store a complete 3D orientation (without translation): /// /// /// /// _ _ /// | | /// | Right-X, Up-X, In-X | /// | Right-Y, Up-Y, In-Y | Note: in-memory layout is transposed /// | Right-Z, Up-Z, In-Z | /// |_ _| /// /// /// template struct Matrix33 { /// Number of rows in this matrix public: static const std::size_t RowCount = 3; /// Number of columns in this matrix public: static const std::size_t ColumnCount = 3; #pragma region class MatrixRowAccessor /// Accesses a single row in a matrix public: class MatrixRowAccessor { /// Initializes a new matrix row accessor /// Matrix that the row accessor will access /// Index of the row the row accessor will access public: MatrixRowAccessor(Matrix33 &matrix, std::size_t rowIndex) : matrix(matrix), rowIndex(rowIndex) { if(rowIndex >= 3) { throw std::out_of_range("Invalid row index"); } } /// Accesses an entire row of the matrix as a 4D vector public: operator const Vector3() const { switch(this->rowIndex) { case 0: { return Vector3(this->matrix->M11, this->matrix->M12, this->matrix->M13); } case 1: { return Vector3(this->matrix->M21, this->matrix->M22, this->matrix->M23); } case 2: { return Vector3(this->matrix->M31, this->matrix->M32, this->matrix->M33); } } } /// Accesses the specified column in the row assigned to the accessor /// Column in which the accessor will access a row /// The matrix element at the specified column public: TScalar &operator[](std::size_t columnIndex) { if(columnIndex >= 2) { throw std::out_of_range("Invalid column index"); } switch((rowIndex << 4) | columnIndex) { case 0x0000: { return matrix->M11; } case 0x0001: { return matrix->M12; } case 0x0002: { return matrix->M13; } case 0x0100: { return matrix->M21; } case 0x0101: { return matrix->M22; } case 0x0102: { return matrix->M23; } case 0x0200: { return matrix->M31; } case 0x0201: { return matrix->M32; } case 0x0202: { return matrix->M33; } } } /// Accesses the specified column in the row assigned to the accessor /// Column in which the accessor will access a row /// The matrix element at the specified column public: const TScalar &operator[](std::size_t columnIndex) const { if(columnIndex >= 4) { throw std::out_of_range("Invalid column index"); } switch((rowIndex << 4) | columnIndex) { case 0x0000: { return matrix->M11; } case 0x0001: { return matrix->M12; } case 0x0002: { return matrix->M13; } case 0x0100: { return matrix->M21; } case 0x0101: { return matrix->M22; } case 0x0102: { return matrix->M23; } case 0x0200: { return matrix->M31; } case 0x0201: { return matrix->M32; } case 0x0202: { return matrix->M33; } } } /// Matrix the accessor will access private: Matrix33 &matrix; /// Index of the row in which the accessor will access an element private: std::size_t rowIndex; }; #pragma endregion // class MatrixRowAccessor #pragma region class ConstMatrixRowAccessor /// Accesses a single row in an immutable matrix public: class ConstMatrixRowAccessor { /// Initializes a new matrix row accessor /// Matrix that the row accessor will access /// Index of the row the row accessor will access public: ConstMatrixRowAccessor(const Matrix33 &matrix, std::size_t rowIndex) : matrix(matrix), rowIndex(rowIndex) { if(rowIndex >= 3) { throw std::out_of_range("Invalid row index"); } } /// Accesses an entire row of the matrix as a 3D vector public: operator const Vector3() const { switch(this->rowIndex) { case 0: { return Vector3(this->matrix->M11, this->matrix->M12, this->matrix->M13); } case 1: { return Vector3(this->matrix->M21, this->matrix->M22, this->matrix->M23); } case 2: { return Vector3(this->matrix->M31, this->matrix->M32, this->matrix->M33); } } } /// Accesses the specified column in the row assigned to the accessor /// Column in which the accessor will access a row /// The matrix element at the specified column public: const TScalar &operator[](std::size_t columnIndex) const { if(columnIndex >= 3) { throw std::out_of_range("Invalid column index"); } switch((rowIndex << 4) | columnIndex) { case 0x0000: { return matrix->M11; } case 0x0001: { return matrix->M12; } case 0x0002: { return matrix->M13; } case 0x0100: { return matrix->M21; } case 0x0101: { return matrix->M22; } case 0x0102: { return matrix->M23; } case 0x0200: { return matrix->M31; } case 0x0201: { return matrix->M32; } case 0x0202: { return matrix->M33; } } } /// Matrix the accessor will access private: const Matrix33 &matrix; /// Index of the row in which the accessor will access an element private: std::size_t rowIndex; }; #pragma endregion // class ConstMatrixRowAccessor /// An empty matrix public: static const Matrix33 Empty; /// The identity matrix public: static const Matrix33 Identity; /// Constructs an uninitialized 3x3 matrix public: Matrix33() {} /// Initializes a new 3x3 matrix /// Existing matrix that will be copied public: Matrix33(TScalar m[3][3]) : M11(m[0][0]), M12(m[0][1]), M13(m[0][2]), M21(m[1][0]), M22(m[1][1]), M23(m[1][2]), M31(m[2][0]), M32(m[2][1]), M33(m[2][2]) {} /// Initializes a new 3x3 matrix /// Value for the element in row 1, column 1 /// Value for the element in row 1, column 2 /// Value for the element in row 1, column 3 /// Value for the element in row 2, column 1 /// Value for the element in row 2, column 2 /// Value for the element in row 2, column 3 /// Value for the element in row 3, column 1 /// Value for the element in row 3, column 2 /// Value for the element in row 3, column 3 public: Matrix33( TScalar m11, TScalar m12, TScalar m13, TScalar m21, TScalar m22, TScalar m23, TScalar m31, TScalar m32, TScalar m33 ) : M11(m11), M12(m12), M13(m13), M21(m21), M22(m22), M23(m23), M31(m31), M32(m32), M33(m33) {} /// Multiplies the matrix with another matrix /// Other matrix this matrix will be multiplied with /// The result of the matrix multiplication public: Matrix33 operator *(const Matrix33 &other) { return Matrix33( this->M11 * other.M11 + this->M12 * other.M21 + this->M13 * other.M31, this->M11 * other.M12 + this->M12 * other.M22 + this->M13 * other.M32, this->M11 * other.M13 + this->M12 * other.M23 + this->M13 * other.M33, this->M21 * other.M11 + this->M22 * other.M21 + this->M23 * other.M31, this->M21 * other.M12 + this->M22 * other.M22 + this->M23 * other.M32, this->M21 * other.M13 + this->M22 * other.M23 + this->M23 * other.M33, this->M31 * other.M11 + this->M32 * other.M21 + this->M33 * other.M31, this->M31 * other.M12 + this->M32 * other.M22 + this->M33 * other.M32, this->M31 * other.M13 + this->M32 * other.M23 + this->M33 * other.M33 ); } /// Matrix row 1 column 1, storing the right vector's X coordinate public: TScalar M11; /// Matrix row 1 column 2, storing the right vector's Y coordinate public: TScalar M12; /// Matrix row 1 column 3, storing the right vector's Z coordinate public: TScalar M13; /// Matrix row 2 column 1, storing the up vector's X coordinate public: TScalar M21; /// Matrix row 2 column 2, storing the up vector's Y coordinate public: TScalar M22; /// Matrix row 2 column 3, storing the up vector's Z coordinate public: TScalar M23; /// Matrix row 3 column 1, storing the forward vector's X coordinate public: TScalar M31; /// Matrix row 3 column 2, storing the forward vector's Y coordinate public: TScalar M32; /// Matrix row 3 column 3, storing the forward vector's Z coordinate public: TScalar M33; }; // ------------------------------------------------------------------------------------------- // template const Matrix33 Matrix33::Empty( 0, 0, 0, 0, 0, 0, 0, 0, 0 ); // ------------------------------------------------------------------------------------------- // template const Matrix33 Matrix33::Identity( 1, 0, 0, 0, 1, 0, 0, 0, 1 ); // ------------------------------------------------------------------------------------------- // }} // namespace Nuclex::Geometry #endif // NUCLEX_GEOMETRY_MATRIX33_H