Raw File
Matrix2.h
#pragma once

typedef Eigen::Vector2d Vector2;

// Rotation matrices are of the form
//   R = cos(t) -sin(t)
//       sin(t)  cos(t)
// where t > 0 indicates a counterclockwise rotation in the xy-plane.

template <typename Real>
class Matrix2
{
public:
    // If makeZero is 'true', create the zero matrix; otherwise, create the
    // identity matrix.
    Matrix2 (bool makeZero = true);

    // Copy constructor.
    Matrix2 (const Matrix2& mat);

    // Input mrc is in row r, column c.
    Matrix2 (Real m00, Real m01, Real m10, Real m11);

    // Create a matrix from an array of numbers.  The input array is
    // interpreted based on the bool input as
    //   true:  entry[0..3] = {m00,m01,m10,m11}  [row major]
    //   false: entry[0..3] = {m00,m10,m01,m11}  [column major]
    Matrix2 (const Real entry[4], bool rowMajor);

    // Create matrices based on vector input.  The bool is interpreted as
    //   true: vectors are columns of the matrix
    //   false: vectors are rows of the matrix
    Matrix2 (const Vector2& u, const Vector2& v, bool columns);
    Matrix2 (const Vector2* vectors, bool columns);

    // Create a diagonal matrix, m01 = m10 = 0.
    Matrix2 (Real m00, Real m11);

    // Create a rotation matrix (positive angle -> counterclockwise).
    Matrix2 (Real angle);

    // Create a tensor product U*V^T.
    Matrix2 (const Vector2& u, const Vector2& v);

    // Assignment.
    Matrix2& operator= (const Matrix2& mat);

    // Create various matrices.
    void MakeZero ();
    void MakeIdentity ();
    void MakeDiagonal (Real m00, Real m11);
    void MakeRotation (Real angle);
    void MakeTensorProduct (const Vector2& u, const Vector2& v);

    // Arithmetic operations.
    Matrix2 operator+ (const Matrix2& mat) const;
    Matrix2 operator- (const Matrix2& mat) const;
    Matrix2 operator* (Real scalar) const;
    Matrix2 operator/ (Real scalar) const;
    Matrix2 operator- () const;

    // Arithmetic updates.
    Matrix2& operator+= (const Matrix2& mat);
    Matrix2& operator-= (const Matrix2& mat);
    Matrix2& operator*= (Real scalar);
    Matrix2& operator/= (Real scalar);

    // M*vec
    Vector2 operator* (const Vector2& vec) const;

    // u^T*M*v
    Real QForm (const Vector2& u, const Vector2& v) const;

    // M^T
    Matrix2 Transpose () const;

    // M*mat
    Matrix2 operator* (const Matrix2& mat) const;

    // M^T*mat
    Matrix2 TransposeTimes (const Matrix2& mat) const;

    // M*mat^T
    Matrix2 TimesTranspose (const Matrix2& mat) const;

    // M^T*mat^T
    Matrix2 TransposeTimesTranspose (const Matrix2& mat) const;

    // Other operations.
    Matrix2 Inverse (const Real epsilon = (Real)0) const;
    Matrix2 Adjoint () const;
    Real Determinant () const;

    // The matrix must be a rotation for these functions to be valid.  The
    // last function uses Gram-Schmidt orthonormalization applied to the
    // columns of the rotation matrix.  The angle must be in radians, not
    // degrees.
    void ExtractAngle (Real& angle) const;
    void Orthonormalize ();

    // The matrix must be symmetric.  Factor M = R * D * R^T where
    // R = [u0|u1] is a rotation matrix with columns u0 and u1 and
    // D = diag(d0,d1) is a diagonal matrix whose diagonal entries are d0
    // and d1.  The eigenvector u[i] corresponds to eigenvector d[i].  The
    // eigenvalues are ordered as d0 <= d1.
    void EigenDecomposition (Matrix2& rot, Matrix2& diag) const;

    // Special matrices.
    static const Matrix2 ZERO;
    static const Matrix2 IDENTITY;

	inline const Real* operator[] (int row) const{ return &mEntry[2*row]; }
	inline Real* operator[] (int row){ return &mEntry[2*row]; }

protected:
	Real mEntry[4];
};

// c * M
template <typename Real>
inline Matrix2<Real> operator* (Real scalar, const Matrix2<Real>& mat);

// v^T * M
template <typename Real>
inline Vector2 operator* (const Vector2& vec, const Matrix2<Real>& mat);


//----------------------------------------------------------------------------
template <typename Real>
Matrix2<Real>::Matrix2 (bool makeZero)
{
    if (makeZero)
    {
        MakeZero();
    }
    else
    {
        MakeIdentity();
    }
}
//----------------------------------------------------------------------------
template <typename Real>
Matrix2<Real>::Matrix2 (const Matrix2& mat)
{
    mEntry[0] = mat.mEntry[0];
    mEntry[1] = mat.mEntry[1];
    mEntry[2] = mat.mEntry[2];
    mEntry[3] = mat.mEntry[3];
}
//----------------------------------------------------------------------------
template <typename Real>
Matrix2<Real>::Matrix2 (Real m00, Real m01, Real m10, Real m11)
{
    mEntry[0] = m00;
    mEntry[1] = m01;
    mEntry[2] = m10;
    mEntry[3] = m11;
}
//----------------------------------------------------------------------------
template <typename Real>
Matrix2<Real>::Matrix2 (const Real entry[4], bool rowMajor)
{
    if (rowMajor)
    {
        mEntry[0] = entry[0];
        mEntry[1] = entry[1];
        mEntry[2] = entry[2];
        mEntry[3] = entry[3];
    }
    else
    {
        mEntry[0] = entry[0];
        mEntry[1] = entry[2];
        mEntry[2] = entry[1];
        mEntry[3] = entry[3];
    }
}
//----------------------------------------------------------------------------
template <typename Real>
Matrix2<Real>::Matrix2 (const Vector2& u, const Vector2& v,
    bool columns)
{
    if (columns)
    {
        mEntry[0] = u[0];
        mEntry[1] = v[0];
        mEntry[2] = u[1];
        mEntry[3] = v[1];
    }
    else
    {
        mEntry[0] = u[0];
        mEntry[1] = u[1];
        mEntry[2] = v[0];
        mEntry[3] = v[1];
    }
}
//----------------------------------------------------------------------------
template <typename Real>
Matrix2<Real>::Matrix2 (const Vector2* v, bool columns)
{
    if (columns)
    {
        mEntry[0] = v[0][0];
        mEntry[1] = v[1][0];
        mEntry[2] = v[0][1];
        mEntry[3] = v[1][1];
    }
    else
    {
        mEntry[0] = v[0][0];
        mEntry[1] = v[0][1];
        mEntry[2] = v[1][0];
        mEntry[3] = v[1][1];
    }
}
//----------------------------------------------------------------------------
template <typename Real>
Matrix2<Real>::Matrix2 (Real m00, Real m11)
{
    MakeDiagonal(m00, m11);
}
//----------------------------------------------------------------------------
template <typename Real>
Matrix2<Real>::Matrix2 (Real angle)
{
    MakeRotation(angle);
}
//----------------------------------------------------------------------------
template <typename Real>
Matrix2<Real>::Matrix2 (const Vector2& u, const Vector2& v)
{
    MakeTensorProduct(u, v);
}
//----------------------------------------------------------------------------
template <typename Real>
Matrix2<Real>& Matrix2<Real>::operator= (const Matrix2& mat)
{
    mEntry[0] = mat.mEntry[0];
    mEntry[1] = mat.mEntry[1];
    mEntry[2] = mat.mEntry[2];
    mEntry[3] = mat.mEntry[3];
    return *this;
}
//----------------------------------------------------------------------------
template <typename Real>
void Matrix2<Real>::MakeZero ()
{
    mEntry[0] = (Real)0;
    mEntry[1] = (Real)0;
    mEntry[2] = (Real)0;
    mEntry[3] = (Real)0;
}
//----------------------------------------------------------------------------
template <typename Real>
void Matrix2<Real>::MakeIdentity ()
{
    mEntry[0] = (Real)1;
    mEntry[1] = (Real)0;
    mEntry[2] = (Real)0;
    mEntry[3] = (Real)1;
}
//----------------------------------------------------------------------------
template <typename Real>
void Matrix2<Real>::MakeDiagonal (Real m00, Real m11)
{
    mEntry[0] = m00;
    mEntry[1] = (Real)0;
    mEntry[2] = (Real)0;
    mEntry[3] = m11;
}
//----------------------------------------------------------------------------
template <typename Real>
void Matrix2<Real>::MakeRotation (Real angle)
{
    mEntry[0] = cos(angle);
    mEntry[2] = sin(angle);
    mEntry[1] = -mEntry[2];
    mEntry[3] =  mEntry[0];
}
//----------------------------------------------------------------------------
template <typename Real>
void Matrix2<Real>::MakeTensorProduct (const Vector2& u,
    const Vector2& v)
{
    mEntry[0] = u[0]*v[0];
    mEntry[1] = u[0]*v[1];
    mEntry[2] = u[1]*v[0];
    mEntry[3] = u[1]*v[1];
}
//----------------------------------------------------------------------------
template <typename Real>
Matrix2<Real> Matrix2<Real>::operator+ (const Matrix2& mat) const
{
    return Matrix2<Real>
    (
        mEntry[0] + mat.mEntry[0],
        mEntry[1] + mat.mEntry[1],
        mEntry[2] + mat.mEntry[2],
        mEntry[3] + mat.mEntry[3]
    );
}
//----------------------------------------------------------------------------
template <typename Real>
Matrix2<Real> Matrix2<Real>::operator- (const Matrix2& mat)
    const
{
    return Matrix2<Real>
    (
        mEntry[0] - mat.mEntry[0],
        mEntry[1] - mat.mEntry[1],
        mEntry[2] - mat.mEntry[2],
        mEntry[3] - mat.mEntry[3]
    );
}
//----------------------------------------------------------------------------
template <typename Real>
Matrix2<Real> Matrix2<Real>::operator* (Real scalar) const
{
    return Matrix2<Real>
    (
        scalar*mEntry[0],
        scalar*mEntry[1],
        scalar*mEntry[2],
        scalar*mEntry[3]
    );
}
//----------------------------------------------------------------------------
template <typename Real>
Matrix2<Real> Matrix2<Real>::operator/ (Real scalar) const
{
    if (scalar != (Real)0)
    {
        Real invScalar = ((Real)1)/scalar;
        return Matrix2<Real>
        (
            invScalar*mEntry[0],
            invScalar*mEntry[1],
            invScalar*mEntry[2],
            invScalar*mEntry[3]
        );
    }
    else
    {
        return Matrix2<Real>
        (
            DBL_MAX,
            DBL_MAX,
            DBL_MAX,
            DBL_MAX
        );
    }
}
//----------------------------------------------------------------------------
template <typename Real>
Matrix2<Real> Matrix2<Real>::operator- () const
{
    return Matrix2<Real>
    (
        -mEntry[0],
        -mEntry[1],
        -mEntry[2],
        -mEntry[3]
    );
}
//----------------------------------------------------------------------------
template <typename Real>
Matrix2<Real>& Matrix2<Real>::operator+= (const Matrix2& mat)
{
    mEntry[0] += mat.mEntry[0];
    mEntry[1] += mat.mEntry[1];
    mEntry[2] += mat.mEntry[2];
    mEntry[3] += mat.mEntry[3];
    return *this;
}
//----------------------------------------------------------------------------
template <typename Real>
Matrix2<Real>& Matrix2<Real>::operator-= (const Matrix2& mat)
{
    mEntry[0] -= mat.mEntry[0];
    mEntry[1] -= mat.mEntry[1];
    mEntry[2] -= mat.mEntry[2];
    mEntry[3] -= mat.mEntry[3];
    return *this;
}
//----------------------------------------------------------------------------
template <typename Real>
Matrix2<Real>& Matrix2<Real>::operator*= (Real scalar)
{
    mEntry[0] *= scalar;
    mEntry[1] *= scalar;
    mEntry[2] *= scalar;
    mEntry[3] *= scalar;
    return *this;
}
//----------------------------------------------------------------------------
template <typename Real>
Matrix2<Real>& Matrix2<Real>::operator/= (Real scalar)
{
    if (scalar != (Real)0)
    {
        Real invScalar = ((Real)1)/scalar;
        mEntry[0] *= invScalar;
        mEntry[1] *= invScalar;
        mEntry[2] *= invScalar;
        mEntry[3] *= invScalar;
    }
    else
    {
        mEntry[0] = DBL_MAX;
        mEntry[1] = DBL_MAX;
        mEntry[2] = DBL_MAX;
        mEntry[3] = DBL_MAX;
    }

    return *this;
}
//----------------------------------------------------------------------------
template <typename Real>
Vector2 Matrix2<Real>::operator* (const Vector2& vec) const
{
    return Vector2
    (
        mEntry[0]*vec[0] + mEntry[1]*vec[1],
        mEntry[2]*vec[0] + mEntry[3]*vec[1]
    );
}
//----------------------------------------------------------------------------
template <typename Real>
Real Matrix2<Real>::QForm (const Vector2& u, const Vector2& v)
    const
{
    return dot(u,(*this)*v);
}
//----------------------------------------------------------------------------
template <typename Real>
Matrix2<Real> Matrix2<Real>::Transpose () const
{
    return Matrix2<Real>
    (
        mEntry[0],
        mEntry[2],
        mEntry[1],
        mEntry[3]
    );
}
//----------------------------------------------------------------------------
template <typename Real>
Matrix2<Real> Matrix2<Real>::operator* (const Matrix2& mat) const
{
    // A*B
    return Matrix2<Real>
    (
        mEntry[0]*mat.mEntry[0] + mEntry[1]*mat.mEntry[2],
        mEntry[0]*mat.mEntry[1] + mEntry[1]*mat.mEntry[3],
        mEntry[2]*mat.mEntry[0] + mEntry[3]*mat.mEntry[2],
        mEntry[2]*mat.mEntry[1] + mEntry[3]*mat.mEntry[3]
    );
}
//----------------------------------------------------------------------------
template <typename Real>
Matrix2<Real> Matrix2<Real>::TransposeTimes (const Matrix2& mat) const
{
    // A^T*B
    return Matrix2<Real>
    (
        mEntry[0]*mat.mEntry[0] + mEntry[2]*mat.mEntry[2],
        mEntry[0]*mat.mEntry[1] + mEntry[2]*mat.mEntry[3],
        mEntry[1]*mat.mEntry[0] + mEntry[3]*mat.mEntry[2],
        mEntry[1]*mat.mEntry[1] + mEntry[3]*mat.mEntry[3]
    );
}
//----------------------------------------------------------------------------
template <typename Real>
Matrix2<Real> Matrix2<Real>::TimesTranspose (const Matrix2& mat) const
{
    // A*B^T
    return Matrix2<Real>
    (
        mEntry[0]*mat.mEntry[0] + mEntry[1]*mat.mEntry[1],
        mEntry[0]*mat.mEntry[2] + mEntry[1]*mat.mEntry[3],
        mEntry[2]*mat.mEntry[0] + mEntry[3]*mat.mEntry[1],
        mEntry[2]*mat.mEntry[2] + mEntry[3]*mat.mEntry[3]
    );
}
//----------------------------------------------------------------------------
template <typename Real>
Matrix2<Real> Matrix2<Real>::TransposeTimesTranspose (const Matrix2& mat)
    const
{
    // A^T*B^T
    return Matrix2<Real>
    (
        mEntry[0]*mat.mEntry[0] + mEntry[2]*mat.mEntry[1],
        mEntry[0]*mat.mEntry[2] + mEntry[2]*mat.mEntry[3],
        mEntry[1]*mat.mEntry[0] + mEntry[3]*mat.mEntry[1],
        mEntry[1]*mat.mEntry[2] + mEntry[3]*mat.mEntry[3]
    );
}
//----------------------------------------------------------------------------
template <typename Real>
Matrix2<Real> Matrix2<Real>::Inverse (const Real epsilon) const
{
    Matrix2<Real> inverse;

    Real det = mEntry[0]*mEntry[3] - mEntry[1]*mEntry[2];
    if (fabs(det) > epsilon)
    {
        Real invDet = ((Real)1)/det;
        inverse.mEntry[0] =  mEntry[3]*invDet;
        inverse.mEntry[1] = -mEntry[1]*invDet;
        inverse.mEntry[2] = -mEntry[2]*invDet;
        inverse.mEntry[3] =  mEntry[0]*invDet;
    }
    else
    {
        inverse.mEntry[0] = (Real)0;
        inverse.mEntry[1] = (Real)0;
        inverse.mEntry[2] = (Real)0;
        inverse.mEntry[3] = (Real)0;
    }

    return inverse;
}
//----------------------------------------------------------------------------
template <typename Real>
Matrix2<Real> Matrix2<Real>::Adjoint () const
{
    return Matrix2<Real>(mEntry[3], -mEntry[1], -mEntry[2], mEntry[0]);
}
//----------------------------------------------------------------------------
template <typename Real>
Real Matrix2<Real>::Determinant () const
{
    return mEntry[0]*mEntry[3] - mEntry[1]*mEntry[2];
}
//----------------------------------------------------------------------------
template <typename Real>
void Matrix2<Real>::ExtractAngle (Real& angle) const
{
    // assert:  'this' matrix represents a rotation
    angle = atan2(mEntry[2], mEntry[0]);
}
//----------------------------------------------------------------------------
template <typename Real>
void Matrix2<Real>::Orthonormalize ()
{
    // Algorithm uses Gram-Schmidt orthogonalization.  If 'this' matrix is
    // M = [m0|m1], then orthonormal output matrix is Q = [q0|q1],
    //
    //   q0 = m0/|m0|
    //   q1 = (m1-(q0*m1)q0)/|m1-(q0*m1)q0|
    //
    // where |V| indicates length of vector V and A*B indicates dot
    // product of vectors A and B.

    // Compute q0.
    Real invLength = 1.0/sqrt(mEntry[0]*mEntry[0] +
        mEntry[2]*mEntry[2]);

    mEntry[0] *= invLength;
    mEntry[2] *= invLength;

    // Compute q1.
    Real dot0 = mEntry[0]*mEntry[1] + mEntry[2]*mEntry[3];
    mEntry[1] -= dot0*mEntry[0];
    mEntry[3] -= dot0*mEntry[2];

    invLength = 1.0/sqrt(mEntry[1]*mEntry[1] +
        mEntry[3]*mEntry[3]);

    mEntry[1] *= invLength;
    mEntry[3] *= invLength;
}
//----------------------------------------------------------------------------
template <typename Real>
void Matrix2<Real>::EigenDecomposition (Matrix2& rot, Matrix2& diag) const
{
    Real sum = fabs(mEntry[0]) + fabs(mEntry[3]);
    if (fabs(mEntry[1]) + sum == sum)
    {
        // The matrix M is diagonal (within numerical round-off).
        rot.mEntry[0] = (Real)1;
        rot.mEntry[1] = (Real)0;
        rot.mEntry[2] = (Real)0;
        rot.mEntry[3] = (Real)1;
        diag.mEntry[0] = mEntry[0];
        diag.mEntry[1] = (Real)0;
        diag.mEntry[2] = (Real)0;
        diag.mEntry[3] = mEntry[3];
        return;
    }

    Real trace = mEntry[0] + mEntry[3];
    Real diff = mEntry[0] - mEntry[3];
    Real discr = sqrt(diff*diff + ((Real)4)*mEntry[1]*mEntry[1]);
    Real eigVal0 = ((Real)0.5)*(trace - discr);
    Real eigVal1 = ((Real)0.5)*(trace + discr);
    diag.MakeDiagonal(eigVal0, eigVal1);

    Real cs, sn;
    if (diff >= (Real)0)
    {
        cs = mEntry[1];
        sn = eigVal0 - mEntry[0];
    }
    else
    {
        cs = eigVal0 - mEntry[3];
        sn = mEntry[1];
    }
    Real invLength = 1.0/sqrt(cs*cs + sn*sn);
    cs *= invLength;
    sn *= invLength;

    rot.mEntry[0] = cs;
    rot.mEntry[1] = -sn;
    rot.mEntry[2] = sn;
    rot.mEntry[3] = cs;
}
//----------------------------------------------------------------------------
template <typename Real>
inline Matrix2<Real> operator* (Real scalar, const Matrix2<Real>& mat)
{
    return mat*scalar;
}
//----------------------------------------------------------------------------
template <typename Real>
inline Vector2 operator* (const Vector2& vec,
    const Matrix2<Real>& mat)
{
    return Vector2
    (
        vec[0]*mat[0][0] + vec[1]*mat[1][0],
        vec[0]*mat[0][1] + vec[1]*mat[1][1]
    );
}
//----------------------------------------------------------------------------


typedef Matrix2<float> Matrix2f;
typedef Matrix2<double> Matrix2d;


template<> const Matrix2<float> Matrix2<float>::ZERO(true);
template<> const Matrix2<float> Matrix2<float>::IDENTITY(false);

template<> const Matrix2<double> Matrix2<double>::ZERO(true);
template<> const Matrix2<double> Matrix2<double>::IDENTITY(false);
back to top