Skip to content

Commit

Permalink
#5740: Refactoring. Introduce Matrix3, the little sister of Matrix4.
Browse files Browse the repository at this point in the history
  • Loading branch information
codereader committed Sep 6, 2021
1 parent a29bd81 commit 1368551
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 38 deletions.
43 changes: 43 additions & 0 deletions libs/math/Matrix3.h
@@ -0,0 +1,43 @@
#pragma once

#include "Vector3.h"
#include "eigen.h"

/**
* \brief A 3x3 matrix stored in double-precision floating-point.
*
* The 3 columns may regarded as 3 vectors named x, y, z:
*
* | xx yx zx |
* | xy yy zy |
* | xz yz zz |
*
*/
class alignas(16) Matrix3
{
// Underlying Eigen transform object (which can in turn be reduced to a 3x3
// Matrix)
using Transform = Eigen::Projective2d;
Transform _transform;

private:
/// Construct a matrix with uninitialised values.
Matrix3() { }

/// Construct from Eigen transform
explicit Matrix3(const Eigen::Projective2d& t) :
_transform(t)
{}

/// Get the underlying Eigen transform
Transform& eigen() { return _transform; }

/// Get the underlying const Eigen transform
const Transform& eigen() const { return _transform; }

/// Obtain the identity matrix.
static Matrix3 getIdentity()
{
return Matrix3(Eigen::Projective2d::Identity());
}
};
18 changes: 4 additions & 14 deletions libs/math/Matrix4.h
Expand Up @@ -3,20 +3,10 @@
/// \file
/// \brief Matrix data types and related operations.

#include "math/Vector3.h"
#include "math/Vector4.h"
#include "math/pi.h"

#undef Success // get rid of fuckwit X.h macro

// Silence C++17 deprecation warnings from Eigen\src\Core\util\Meta.h(373), will be unsilenced at the bottom of this file
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4996)
#pragma warning(disable : 4127)
#endif

#include <Eigen/Geometry>
#include "Vector3.h"
#include "Vector4.h"
#include "pi.h"
#include "eigen.h"

class Quaternion;

Expand Down
14 changes: 14 additions & 0 deletions libs/math/eigen.h
@@ -0,0 +1,14 @@
#pragma once

// Import the Eigen header files needed by our math classes

#undef Success // get rid of fuckwit X.h macro

// Silence C++17 deprecation warnings from Eigen\src\Core\util\Meta.h(373), will be unsilenced at the bottom of this file
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4996)
#pragma warning(disable : 4127)
#endif

#include <Eigen/Geometry>
55 changes: 55 additions & 0 deletions test/Brush.cpp
Expand Up @@ -184,6 +184,61 @@ TEST_F(BrushTest, FacePlaneTranslate)
});
}

// Calculate the texture projection matrix from a given set of XYZ and UV coords
TEST_F(BrushTest, TextureProjectionFromPoints)
{
Eigen::Vector3d points[4] =
{
{ -64, 64, 0 },
{ +64, 64, 0 },
{ +64, -64, 0 },
{ -64, -64, 0 }
};

Vector2 uvs[4] =
{
{ 0, 0 },
{ 0.5, 0 },
{ 0.5, 0.6 },
{ 0, 0.6 }
};

Eigen::Matrix3d mat;
mat(0, 0) = points[0].x();
mat(1, 0) = points[0].y();
mat(2, 0) = 1;

mat(0, 1) = points[1].x();
mat(1, 1) = points[1].y();
mat(2, 1) = 1;

mat(0, 2) = points[2].x();
mat(1, 2) = points[2].y();
mat(2, 2) = 1;

Eigen::Matrix3d uvMatrix;
uvMatrix(0, 0) = uvs[0].x();
uvMatrix(1, 0) = uvs[0].y();
uvMatrix(2, 0) = 1;

uvMatrix(0, 1) = uvs[1].x();
uvMatrix(1, 1) = uvs[1].y();
uvMatrix(2, 1) = 1;

uvMatrix(0, 2) = uvs[2].x();
uvMatrix(1, 2) = uvs[2].y();
uvMatrix(2, 2) = 1;

//auto det = mat.determinant();

Eigen::Matrix3d textureMatrix = uvMatrix * mat.inverse();

Eigen::Vector3d uv0 = textureMatrix * Eigen::Vector3d(points[0].x(), points[0].y(), 1);
Eigen::Vector3d uv1 = textureMatrix * Eigen::Vector3d(points[1].x(), points[1].y(), 1);
Eigen::Vector3d uv2 = textureMatrix * Eigen::Vector3d(points[2].x(), points[2].y(), 1);
Eigen::Vector3d uv3 = textureMatrix * Eigen::Vector3d(points[3].x(), points[3].y(), 1);
}

inline bool faceHasVertex(const IFace* face, const Vector3& expectedXYZ, const Vector2& expectedUV)
{
return algorithm::faceHasVertex(face, [&](const WindingVertex& vertex)
Expand Down
48 changes: 24 additions & 24 deletions test/math/Matrix4.cpp
Expand Up @@ -24,7 +24,7 @@ namespace
}
}

TEST(MatrixTest, CreateIdentityMatrix)
TEST(Matrix4Test, CreateIdentityMatrix)
{
const Matrix4 identity = Matrix4::getIdentity();
EXPECT_EQ(identity, Matrix4::byRows(1, 0, 0, 0,
Expand All @@ -33,7 +33,7 @@ TEST(MatrixTest, CreateIdentityMatrix)
0, 0, 0, 1));
}

TEST(MatrixTest, AssignMatrixComponents)
TEST(Matrix4Test, AssignMatrixComponents)
{
Matrix4 identity;

Expand All @@ -60,7 +60,7 @@ TEST(MatrixTest, AssignMatrixComponents)
EXPECT_EQ(identity, Matrix4::getIdentity());
}

TEST(MatrixTest, ConstructMatrixByRows)
TEST(Matrix4Test, ConstructMatrixByRows)
{
auto m = Matrix4::byRows(1, 2.5, 3, 0.34,
51, -6, 7, 9,
Expand Down Expand Up @@ -89,7 +89,7 @@ TEST(MatrixTest, ConstructMatrixByRows)
EXPECT_EQ(m.tw(), 32);
}

TEST(MatrixTest, ConstructTranslationMatrix)
TEST(Matrix4Test, ConstructTranslationMatrix)
{
const Vector3 TRANS(1.5, -2939, 357);
Matrix4 tm = Matrix4::getTranslation(TRANS);
Expand All @@ -101,7 +101,7 @@ TEST(MatrixTest, ConstructTranslationMatrix)
EXPECT_EQ(tm.translation(), TRANS);
}

TEST(MatrixTest, ConstructScaleMatrix)
TEST(Matrix4Test, ConstructScaleMatrix)
{
const Vector3 SCALE(0.75, 1.25, 960);
Matrix4 sm = Matrix4::getScale(SCALE);
Expand All @@ -113,7 +113,7 @@ TEST(MatrixTest, ConstructScaleMatrix)
EXPECT_EQ(sm.getScale(), SCALE);
}

TEST(MatrixTest, AccessMatrixColumnVectors)
TEST(Matrix4Test, AccessMatrixColumnVectors)
{
Matrix4 m = Matrix4::byRows(1, 4, 8, -5,
2, 9, 7, 13,
Expand All @@ -138,7 +138,7 @@ TEST(MatrixTest, AccessMatrixColumnVectors)
1.3, 1.4, 1.5, 1.6));
}

TEST(MatrixTest, MatrixRawArrayData)
TEST(Matrix4Test, MatrixRawArrayData)
{
Matrix4 m = Matrix4::byRows(1, 0.2, 35, 4,
5, -6, 17, 300,
Expand Down Expand Up @@ -166,7 +166,7 @@ TEST(MatrixTest, MatrixRawArrayData)
EXPECT_EQ(data[15], -4.5);
}

TEST(MatrixTest, MatrixEquality)
TEST(Matrix4Test, MatrixEquality)
{
Matrix4 m1 = Matrix4::byRows(1, 2, 3.5, 4,
5, -6, 17, 800,
Expand All @@ -179,7 +179,7 @@ TEST(MatrixTest, MatrixEquality)
EXPECT_TRUE(m2 != Matrix4::getIdentity());
}

TEST(MatrixTest, MatrixTranspose)
TEST(Matrix4Test, MatrixTranspose)
{
Matrix4 m = Matrix4::byRows(1, 2, 3, 4,
5, 6, 7, 8,
Expand All @@ -199,7 +199,7 @@ TEST(MatrixTest, MatrixTranspose)
EXPECT_EQ(m, mT);
}

TEST(MatrixTest, ConvertDegreesAndRadians)
TEST(Matrix4Test, ConvertDegreesAndRadians)
{
math::Degrees thirtyD(30);
EXPECT_DOUBLE_EQ(thirtyD.asDegrees(), 30);
Expand All @@ -210,7 +210,7 @@ TEST(MatrixTest, ConvertDegreesAndRadians)
EXPECT_DOUBLE_EQ(twoPiBy3R.asRadians(), 2 * math::PI / 3.0);
}

TEST(MatrixTest, MatrixRotationAboutZDegrees)
TEST(Matrix4Test, MatrixRotationAboutZDegrees)
{
math::Degrees angle(60.0);
double cosAngle = cos(angle.asRadians());
Expand All @@ -224,7 +224,7 @@ TEST(MatrixTest, MatrixRotationAboutZDegrees)
0, 0, 0, 1));
}

TEST(MatrixTest, MatrixRotationAboutZRadians)
TEST(Matrix4Test, MatrixRotationAboutZRadians)
{
double angle = math::PI / 3.0; // 60 degrees in radians
double cosAngle = cos(angle);
Expand All @@ -238,7 +238,7 @@ TEST(MatrixTest, MatrixRotationAboutZRadians)
0, 0, 0, 1));
}

TEST(MatrixTest, MatrixRotationForAxisAngle)
TEST(Matrix4Test, MatrixRotationForAxisAngle)
{
// Rotation with a zero angle should do nothing
Matrix4 noRot = Matrix4::getRotation(Vector3(0, 0, 1), 0);
Expand All @@ -257,7 +257,7 @@ TEST(MatrixTest, MatrixRotationForAxisAngle)
expectNear(rot45 * Vector3(1, 0, 0), Vector3(0, 1, 0));
}

TEST(MatrixTest, MatrixRotationForEulerXYZDegrees)
TEST(Matrix4Test, MatrixRotationForEulerXYZDegrees)
{
// Test euler angle constructors
Vector3 euler(30, -55, 75);
Expand Down Expand Up @@ -301,7 +301,7 @@ TEST(MatrixTest, MatrixRotationForEulerXYZDegrees)
EXPECT_DOUBLE_EQ(testEuler.z(), euler.z()) << "getEulerAnglesXYZDegrees fault at z()";
}

TEST(MatrixTest, MatrixMultiplication)
TEST(Matrix4Test, MatrixMultiplication)
{
auto a = Matrix4::byColumns(3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59);
auto b = Matrix4::byColumns(61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137);
Expand All @@ -323,7 +323,7 @@ TEST(MatrixTest, MatrixMultiplication)
EXPECT_EQ(b.getMultipliedBy(a), a.getPremultipliedBy(b)) << "Matrix pre-multiplication mismatch";
}

TEST(MatrixTest, MatrixTransformation)
TEST(Matrix4Test, MatrixTransformation)
{
auto a = Matrix4::byColumns(3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59);

Expand Down Expand Up @@ -358,7 +358,7 @@ TEST(MatrixTest, MatrixTransformation)
EXPECT_EQ(a.tCol().z(), 53) << "Matrix4::t failed";
}

TEST(MatrixTest, MatrixTransformVectorEqualsMultiplication)
TEST(Matrix4Test, MatrixTransformVectorEqualsMultiplication)
{
const Vector3 TRANSLATION(2, 5, -7);
auto t = Matrix4::getTranslation(TRANSLATION)
Expand Down Expand Up @@ -387,7 +387,7 @@ TEST(MatrixTest, MatrixTransformVectorEqualsMultiplication)
EXPECT_EQ((t * Vector4(vec3, 0)).getVector3(), t.transformDirection(vec3));
}

TEST(MatrixTest, MatrixScaleAffineInverse)
TEST(Matrix4Test, MatrixScaleAffineInverse)
{
// Construct a scale matrix
Vector3 SCALE(2, 4, 8);
Expand All @@ -405,7 +405,7 @@ TEST(MatrixTest, MatrixScaleAffineInverse)
Vector3(1.0 / SCALE.x(), 1.0 / SCALE.y(), 1.0 / SCALE.z()));
}

TEST(MatrixTest, MatrixTranslationAffineInverse)
TEST(Matrix4Test, MatrixTranslationAffineInverse)
{
// Construct a translation matrix
Vector3 TRANS(4, 32, -8);
Expand All @@ -425,7 +425,7 @@ TEST(MatrixTest, MatrixTranslationAffineInverse)
0, 0, 0, 1));
}

TEST(MatrixTest, MatrixRotationAffineInverse)
TEST(Matrix4Test, MatrixRotationAffineInverse)
{
// Construct a translation matrix
const math::Degrees ANGLE(60);
Expand All @@ -440,7 +440,7 @@ TEST(MatrixTest, MatrixRotationAffineInverse)
expectNear(inverse, backRotMat);
}

TEST(MatrixTest, MatrixAffineInverseMatchesFullInverse)
TEST(Matrix4Test, MatrixAffineInverseMatchesFullInverse)
{
// Create an affine transformation
Matrix4 affTrans = Matrix4::getRotationAboutZ(math::Degrees(78))
Expand Down Expand Up @@ -468,7 +468,7 @@ TEST(MatrixTest, MatrixAffineInverseMatchesFullInverse)
EXPECT_GT(diffInv.ty(), 8);
}

TEST(MatrixTest, MatrixFullInverse)
TEST(Matrix4Test, MatrixFullInverse)
{
auto a = Matrix4::byColumns(3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59);

Expand All @@ -495,7 +495,7 @@ TEST(MatrixTest, MatrixFullInverse)
EXPECT_DOUBLE_EQ(inv.tw(), 0.3571428571428571) << "Matrix inversion failed on tw";
}

TEST(MatrixTest, MatrixTranslateBy)
TEST(Matrix4Test, MatrixTranslateBy)
{
const Vector3 TRANS(27, -16, 0.84);

Expand Down Expand Up @@ -525,7 +525,7 @@ TEST(MatrixTest, MatrixTranslateBy)
expectNear(m.translation(), SCALE * ONE);
}

TEST(MatrixTest, GetInverseScale)
TEST(Matrix4Test, GetInverseScale)
{
// Create an arbitrary transformation
Matrix4 m = Matrix4::getRotationAboutZ(math::Degrees(15))
Expand Down
2 changes: 2 additions & 0 deletions tools/msvc/mathlib.vcxproj
Expand Up @@ -146,11 +146,13 @@
<ItemGroup>
<ClInclude Include="..\..\libs\math\AABB.h" />
<ClInclude Include="..\..\libs\math\curve.h" />
<ClInclude Include="..\..\libs\math\eigen.h" />
<ClInclude Include="..\..\libs\math\FloatTools.h" />
<ClInclude Include="..\..\libs\math\Frustum.h" />
<ClInclude Include="..\..\libs\math\Hash.h" />
<ClInclude Include="..\..\libs\math\Line.h" />
<ClInclude Include="..\..\libs\math\lrint.h" />
<ClInclude Include="..\..\libs\math\Matrix3.h" />
<ClInclude Include="..\..\libs\math\Matrix4.h" />
<ClInclude Include="..\..\libs\math\pi.h" />
<ClInclude Include="..\..\libs\math\Plane3.h" />
Expand Down
2 changes: 2 additions & 0 deletions tools/msvc/mathlib.vcxproj.filters
Expand Up @@ -27,6 +27,8 @@
<ClInclude Include="..\..\libs\math\Vector4.h" />
<ClInclude Include="..\..\libs\math\Viewer.h" />
<ClInclude Include="..\..\libs\math\ViewProjection.h" />
<ClInclude Include="..\..\libs\math\Matrix3.h" />
<ClInclude Include="..\..\libs\math\eigen.h" />
</ItemGroup>
<ItemGroup>
<Filter Include="natvis">
Expand Down

0 comments on commit 1368551

Please sign in to comment.