From 4d4dc91ff46e57c72b89a30b9ba5d86a26efee21 Mon Sep 17 00:00:00 2001 From: Eryn Wells Date: Sun, 10 Aug 2014 16:57:34 -0700 Subject: [PATCH] Add Matrix4 Inverse and Transpose Transpose is easy, with a bool flag to determine whether to access elements in row-major or column-major format. Inverse is more difficult, so this change only does translation inverses. --- src/basics/matrix.cc | 69 +++++++++++++++++++++++++++++++++++++++++--- src/basics/matrix.hh | 16 ++++++++++ test/test_basics.cc | 18 ++++++++++++ 3 files changed, 99 insertions(+), 4 deletions(-) diff --git a/src/basics/matrix.cc b/src/basics/matrix.cc index 6c24450..5779794 100644 --- a/src/basics/matrix.cc +++ b/src/basics/matrix.cc @@ -65,7 +65,8 @@ Matrix4::Translation(Double x, * charles::basics::Matrix4::Matrix4 -- */ Matrix4::Matrix4() - : mData() + : mData(), + mTransposed(false) { } @@ -73,6 +74,7 @@ Matrix4::Matrix4() * charles::basics::Matrix4::Matrix4 -- */ Matrix4::Matrix4(const Double data[16]) + : mTransposed(false) { memcpy(mData, data, sizeof(Double) * 16); } @@ -83,7 +85,13 @@ Matrix4::Matrix4(const Double data[16]) */ Matrix4::Matrix4(const Matrix4 &rhs) : Matrix4(rhs.mData) -{ } +{ + /* + * Needs to be in the body instead of the initializer list because + * (apparently) delegating constructors must be the only thing in the list. + */ + mTransposed = rhs.mTransposed; +} /* @@ -93,6 +101,7 @@ Matrix4& Matrix4::operator=(const Matrix4 &rhs) { memcpy(mData, rhs.mData, sizeof(Double) * 16); + mTransposed = rhs.mTransposed; return *this; } @@ -138,7 +147,12 @@ Matrix4::operator()(UInt i, ss << "matrix index out of bounds: i = " << i << ", j = " << j; throw std::out_of_range(ss.str()); } - return mData[i*4 + j]; + + if (!mTransposed) { + return mData[i*4 + j]; + } else { + return mData[i + j*4]; + } } @@ -155,7 +169,11 @@ Matrix4::operator()(UInt i, ss << "matrix index out of bounds: i = " << i << ", j = " << j; throw std::out_of_range(ss.str()); } - return mData[i*4 + j]; + if (!mTransposed) { + return mData[i*4 + j]; + } else { + return mData[i + j*4]; + } } @@ -255,6 +273,28 @@ Matrix4::operator*(const Vector4 &rhs) } +/* + * charles::basics::Matrix4::Transpose -- + */ +Matrix4& +Matrix4::Transpose() +{ + mTransposed = !mTransposed; + return *this; +} + + +Matrix4& +Matrix4::Inverse() +{ + /* XXX: Only translation matrices are supported right now. */ + operator()(0,3) = -operator()(0,3); + operator()(1,3) = -operator()(1,3); + operator()(2,3) = -operator()(2,3); + return *this; +} + + /* * charles::basics::operator* -- */ @@ -266,6 +306,27 @@ operator*(Double lhs, return rhs * lhs; } + +/* + * charles::basics::Transposed -- + */ +Matrix4 +Transposed(Matrix4 m) +{ + return m.Transpose(); +} + + +/* + * charles::basics::Inverse -- + */ +Matrix4 +Inverse(Matrix4 m) +{ + return m.Inverse(); +} + + } /* namespace mespace */ } /* namespace charles */ diff --git a/src/basics/matrix.hh b/src/basics/matrix.hh index 2128e45..ba8309c 100644 --- a/src/basics/matrix.hh +++ b/src/basics/matrix.hh @@ -73,15 +73,31 @@ struct Matrix4 Vector4 operator*(const Vector4 &rhs) const; /** @} */ + Matrix4& Transpose(); + Matrix4& Inverse(); + protected: /** The matrix data */ Double mData[16]; + + /** + * `true` if the matrix has been transposed (i.e. should be indexed in + * column-major format). + */ + bool mTransposed; }; /** Scalar multiplication, scalar factor on the left. */ Matrix4 operator*(Double lhs, const Matrix4 &rhs); + +/** Transpose the given matrix. */ +Matrix4 Transposed(Matrix4 rhs); + +/** Invert the given matrix. */ +Matrix4 Inverse(Matrix4 rhs); + } /* namespace basics */ } /* namespace charles */ diff --git a/test/test_basics.cc b/test/test_basics.cc index dad6dae..a5b99bb 100644 --- a/test/test_basics.cc +++ b/test/test_basics.cc @@ -293,3 +293,21 @@ TEST_F(Matrix4Test, IdentityVectorMultiplication) EXPECT_EQ(p1.Y(), v1.Y()); EXPECT_EQ(p1.Z(), v1.Z()); } + + +TEST_F(Matrix4Test, Transpose) +{ + Matrix4 t1 = Transposed(m1); + for (UInt i = 0; i < 4; i++) { + for (UInt j = 0; j < 4; j++) { + EXPECT_EQ(m1(i,j), t1(j,i)); + } + } + + t1.Transpose(); + for (UInt i = 0; i < 4; i++) { + for (UInt j = 0; j < 4; j++) { + EXPECT_EQ(m1(i,j), t1(i,j)); + } + } +}