#pragma once #include #include #include #include namespace LinearAlgebra { /// A 3-by-3 matrix for linear transformations of 3D geometry. /* This can represent any kind of linear transformations of 3D geometry, which include * rotation, scale, shear, mirroring, and orthographic projection. * A 3x3 matrix cannot represent translation, which requires a 3x4, or perspective projection (4x4). * The elements of this matrix are * m_00, m_01, m_02 * m_10, m_11, m_12 * m_20, m_21, m_22 * * The element m_yx is the value on the row y and column x. * You can access m_yx using the double-bracket notation m[y][x], or using the member function At. * * @note The member functions in this class use the convention that transforms are applied to * vectors in the form M * v. This means that "Matrix3x3 M, M1, M2; M = M1 * M2;" gives a transformation M * that applies M2 first, followed by M1 second */ class Matrix3x3 { public: enum { Rows = 3 }; enum { Cols = 3 }; static const Matrix3x3 Zero; static const Matrix3x3 Identity; static const Matrix3x3 NaN; Matrix3x3() {} Matrix3x3(float val); Matrix3x3(float m00, float m01, float m02, float m10, float m11, float m12, float m20, float m21, float m22); Matrix3x3(const Vector3& r1, const Vector3& r2, const Vector3& r3); explicit Matrix3x3(const Quaternion& orientation); static Matrix3x3 RotateX(float radians); static Matrix3x3 RotateY(float radians); static Matrix3x3 RotateZ(float radians); Vector3 GetRow(int index) const; Vector3 GetColumn(int index) const; float &At(int row, int col); float At(int x, int y) const; void SetRotatePart(const Vector3& a, float angle); /// Creates a new M3x3 that rotates about the given axis by the given angle static Matrix3x3 RotateAxisAngle(const Vector3& axis, float angleRadians); static Matrix3x3 RotateFromTo(const Vector3& source, const Vector3& direction) { } void SetRow(int i, const Vector3 &vector3); void SetColumn(int i, const Vector3& vector); void SetAt(int x, int y, float value); void Orthonormalize(int c0, int c1, int c2) { Vector3 v0 = GetColumn(c0); Vector3 v1 = GetColumn(c1); Vector3 v2 = GetColumn(c2); Vector3::Orthonormalize(v0, v1, v2); SetColumn(c0, v0); SetColumn(c1, v1); SetColumn(c2, v2); } static Matrix3x3 LookAt(const Vector3& forward, const Vector3& target, const Vector3& localUp, const Vector3& worldUp); static Matrix3x3 FromQuat(const Quaternion& orientation) { return Matrix3x3(orientation); } Quaternion ToQuat() const; /// Creates a new Matrix3x3 as a combination of rotation and scale. // This function creates a new matrix M in the form M = R * S // where R is a rotation matrix and S is a scale matrix. // Transforming a vector v using this matrix computes the vector // v' == M * v == R*S*v == (R * (S * v)) which means the scale operation // is applied to the vector first, followed by rotation, and finally translation static Matrix3x3 FromRS(const Quaternion& rotate, const Vector3& scale) { return Matrix3x3(rotate) * Matrix3x3::Scale(scale); } static Matrix3x3 FromRS(const Matrix3x3 &rotate, const Vector3& scale) { return rotate * Matrix3x3::Scale(scale); } /// Creates a new transformation matrix that scales by the given factors. // This matrix scales with respect to origin. static Matrix3x3 Scale(float sx, float sy, float sz); static Matrix3x3 Scale(const Vector3& scale); /// Returns the main diagonal. Vector3 Diagonal() const; /// Returns the local +X/+Y/+Z axis in world space. /// This is the same as transforming the vector{1,0,0} by this matrix. Vector3 WorldX() const; /// Returns the local +Y axis in world space. /// This is the same as transforming the vector{0,1,0} by this matrix. Vector3 WorldY() const; /// Returns the local +Z axis in world space. /// This is the same as transforming the vector{0,0,1} by this matrix. Vector3 WorldZ() const; /// Computes the determinant of this matrix. // If the determinant is nonzero, this matrix is invertible. // If the determinant is negative, this matrix performs reflection about some axis. // From http://msdn.microsoft.com/en-us/library/bb204853(VS.85).aspx : // "If the determinant is positive, the basis is said to be "positively" oriented (or right-handed). // If the determinant is negative, the basis is said to be "negatively" oriented (or left-handed)." // @note This function computes 9 LOADs, 9 MULs and 5 ADDs. */ float Determinant() const; // Returns an inverted copy of this matrix. This Matrix3x3 Inverse() const; // Returns a transposed copy of this matrix. Matrix3x3 Transpose() const; // Transforms the given vectors by this matrix M, i.e. returns M * (x,y,z) Vector2 Transform(const Vector2& rhs) const; Vector3 Transform(const Vector3& rhs) const; Vector3 operator[](int row) const { return Vector3{elems[row][0], elems[row][1], elems[row][2]}; } Vector3 operator * (const Vector3& rhs) const; Matrix3x3 operator * (const Matrix3x3& rhs) const; protected: float elems[3][3]; }; }