1
0
forked from mirrors/0ad

Make CMatrix3D::operator*= behave as expected.

This commit is contained in:
Stan
2024-09-13 13:27:42 +02:00
parent 09e42692bb
commit bd5f8392be
3 changed files with 167 additions and 11 deletions
+11 -2
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 2019 Wildfire Games.
/* Copyright (C) 2024 Wildfire Games.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -24,8 +24,9 @@
#define INCLUDED_SELF_TEST
// for convenience, to avoid having to include all of these manually
#include "lib/status.h"
#include "lib/lib.h"
#include "lib/os_path.h"
#include "lib/status.h"
#include "lib/posix/posix.h"
#define CXXTEST_HAVE_EH
@@ -147,6 +148,14 @@ std::vector<T> ts_make_vector(T* start, size_t size_bytes)
#define TS_ASSERT_VECTOR_EQUALS_ARRAY(vec1, array) TS_ASSERT_EQUALS(vec1, ts_make_vector((array), sizeof(array)))
#define TS_ASSERT_VECTOR_CONTAINS(vec1, element) TS_ASSERT(std::find((vec1).begin(), (vec1).end(), element) != (vec1).end());
#define TS_ASSERT_MATRIX_EQUALS_DELTA(m1, m2, size, epsilon) \
for (int j = 0; j < size; ++j) \
TS_ASSERT_DELTA(m1._data[j], m2._data[j], epsilon);
#define TS_ASSERT_MATRIX_DIFFERS_DELTA(m1, m2, size, epsilon) \
for (int j = 0; j < size; ++j) \
TS_ASSERT(!feq(m1._data[j], m2._data[j], epsilon));
class ScriptInterface;
// Script-based testing setup (defined in test_setup.cpp). Defines TS_* functions.
void ScriptTestSetup(const ScriptInterface&);
+9 -1
View File
@@ -77,6 +77,14 @@ public:
{
}
CMatrix3D(const float data[]) :
_11(data[0]), _21(data[1]), _31(data[2]), _41(data[3]),
_12(data[4]), _22(data[5]), _32(data[6]), _42(data[7]),
_13(data[8]), _23(data[9]), _33(data[10]), _43(data[11]),
_14(data[12]), _24(data[13]), _34(data[14]), _44(data[15])
{
}
// accessors to individual elements of matrix
// NOTE: in this function definition, 'col' and 'row' represent the column and row into the
// internal element matrix which is the transposed of the mathematical notation, so the first
@@ -128,7 +136,7 @@ public:
// matrix multiplication/assignment
CMatrix3D& operator*=(const CMatrix3D &matrix)
{
Concatenate(matrix);
*this = *this * matrix;
return *this;
}
+147 -8
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 2021 Wildfire Games.
/* Copyright (C) 2024 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -27,6 +27,7 @@
class TestMatrix : public CxxTest::TestSuite
{
std::mt19937 m_Engine;
const float m_Epsilon{0.0001f};
public:
void setUp()
@@ -46,19 +47,157 @@ public:
}
CMatrix3D n;
m.GetInverse(n);
m *= n;
m.Concatenate(n);
// verify identity has 1s on diagonal and 0 otherwise
for (int x = 0; x < 4; ++x)
{
for (int y = 0; y < 4; ++y)
{
const float expected = (x==y)? 1.0f : 0.0f;
TS_ASSERT_DELTA(m(x,y), expected, 0.0002f);
TS_ASSERT_DELTA(m(x,y), expected, m_Epsilon);
}
}
}
}
void test_compoundMultiplication()
{
const float invertibleData[16] = {
2.f, -3.f, 0.f, 1.f,
-2.f, 3.f, 0.f, 0.f,
1.f, -2.f, 1.f, 0.f,
1.f, -1.f, 0.f, 0.f
};
// Invertible matrix.
CMatrix3D a(invertibleData);
CMatrix3D n;
a.GetInverse(n);
a *= n;
CMatrix3D a2(invertibleData);
n *= a2;
TS_ASSERT_MATRIX_EQUALS_DELTA(a, n, 16, m_Epsilon);
// Non invertible matrix.
const float nonInvertibleData[16] = {
2.f, -3.f, 0.f, 1.f,
-2.f, 3.f, 0.f, 0.f,
1.f, -2.f, 1.f, 0.f,
0.f, 0.f, 0.f, 0.f
};
CMatrix3D b(nonInvertibleData);
b.GetInverse(n);
b *= n;
CMatrix3D b2(nonInvertibleData);
n *= b2;
TS_ASSERT_MATRIX_DIFFERS_DELTA(b, n, 16, m_Epsilon);
}
void test_multiplication()
{
const float data1[16] = {
2.f, -3.f, 0.f, 1.f,
-2.f, 3.f, 0.f, 0.f,
1.f, -2.f, 1.f, 0.f,
1.f, -1.f, 0.f, 0.f
};
const float data2[16] = {
22.f, -3.f, 0.f, 1.f,
-2.f, 3.f, 8.f, 12.f,
1.f, -2.f, 1.f, 0.f,
1.f, -1.f, 16.f, 0.f
};
CMatrix3D mat1(data1);
CMatrix3D mat2(data2);
CMatrix3D mat3 = mat2 * mat1;
const float result[16] = {
51.f, -16.f, -8.f, -34.f,
-50.f, 15.f, 24.f, 34.f,
27.f, -11.f, -15.f, -23.f,
24.f, -6.f, -8.f, -11.f
};
CMatrix3D resultMat3(result);
TS_ASSERT_MATRIX_EQUALS_DELTA(mat3, resultMat3, 16, m_Epsilon);
const float result2[16] = {
51.f, -76.f, 0.f, 22.f,
10.f, -13.f, 8.f, -2.f,
7.f, -11.f, 1.f, 1.f,
20.f, -38.f, 16.f, 1.f
};
CMatrix3D resultMat4(result2);
CMatrix3D mat4 = mat1 * mat2;
TS_ASSERT_MATRIX_EQUALS_DELTA(mat4, resultMat4, 16, m_Epsilon);
mat1.Concatenate(mat2);
TS_ASSERT_MATRIX_EQUALS_DELTA(mat1, resultMat3, 16, m_Epsilon);
mat1 = CMatrix3D(data1);
mat2.Concatenate(mat1);
TS_ASSERT_MATRIX_EQUALS_DELTA(mat2, resultMat4, 16, m_Epsilon);
}
void test_nonCommutative()
{
const float data1[16] = {
1.f, 1.f, 1.f, 1.f,
0.f, 0.f, 0.f, 0.f,
0.f, 0.f, 0.f, 0.f,
0.f, 0.f, 0.f, 0.f
};
const float data2[16] = {
1.f, 0.f, 0.f, 0.f,
1.f, 0.f, 0.f, 0.f,
1.f, 0.f, 0.f, 0.f,
1.f, 0.f, 0.f, 0.f
};
CMatrix3D mat1(data1);
CMatrix3D mat2(data2);
mat1 *= mat2;
const float result[16] = {
1.f, 1.f, 1.f, 1.f,
1.f, 1.f, 1.f, 1.f,
1.f, 1.f, 1.f, 1.f,
1.f, 1.f, 1.f, 1.f
};
CMatrix3D resultMat3(result);
TS_ASSERT_MATRIX_EQUALS_DELTA(mat1, resultMat3, 16, m_Epsilon);
const float result2[16] = {
4.f, 0.f, 0.f, 0.f,
0.f, 0.f, 0.f, 0.f,
0.f, 0.f, 0.f, 0.f,
0.f, 0.f, 0.f, 0.f
};
CMatrix3D mat3(data1);
CMatrix3D resultMat4(result2);
mat2 *= mat3;
TS_ASSERT_MATRIX_EQUALS_DELTA(mat2, resultMat4, 16, m_Epsilon);
}
void test_quats()
{
std::uniform_real_distribution<float> distribution01(0.0f, std::nextafter(1.0f, 2.0f));
@@ -108,7 +247,7 @@ public:
for (int x = 0; x < 4; ++x)
for (int y = 0; y < 4; ++y)
TS_ASSERT_DELTA(a(x,y), b(x,y), 0.0002f);
TS_ASSERT_DELTA(a(x,y), b(x,y), m_Epsilon);
a = m;
b = m;
@@ -118,7 +257,7 @@ public:
for (int x = 0; x < 4; ++x)
for (int y = 0; y < 4; ++y)
TS_ASSERT_DELTA(a(x,y), b(x,y), 0.0002f);
TS_ASSERT_DELTA(a(x,y), b(x,y), m_Epsilon);
a = m;
b = m;
@@ -128,7 +267,7 @@ public:
for (int x = 0; x < 4; ++x)
for (int y = 0; y < 4; ++y)
TS_ASSERT_DELTA(a(x,y), b(x,y), 0.0002f);
TS_ASSERT_DELTA(a(x,y), b(x,y), m_Epsilon);
}
void test_getRotation()
@@ -147,7 +286,7 @@ public:
{
float a = 2 * M_PI * distribution01(m_Engine) - M_PI;
m.SetYRotation(a);
TS_ASSERT_DELTA(m.GetYRotation(), a, 0.001f);
TS_ASSERT_DELTA(m.GetYRotation(), a, m_Epsilon);
}
}
@@ -170,6 +309,6 @@ public:
for (int x = 0; x < 4; ++x)
for (int y = 0; y < 4; ++y)
TS_ASSERT_DELTA(a(x,y), b(x,y), 0.0002f);
TS_ASSERT_DELTA(a(x,y), b(x,y), m_Epsilon);
}
};