Add unit tests for the mathematics classes

This commit is contained in:
Daniel Chappuis 2013-03-13 20:52:59 +01:00
parent 02a3cd2db8
commit a3c6fa07e8
5 changed files with 397 additions and 35 deletions

View File

@ -28,18 +28,20 @@
#include "tests/mathematics/TestVector3.h" #include "tests/mathematics/TestVector3.h"
#include "tests/mathematics/TestTransform.h" #include "tests/mathematics/TestTransform.h"
#include "tests/mathematics/TestQuaternion.h" #include "tests/mathematics/TestQuaternion.h"
#include "tests/mathematics/TestMatrix3x3.h"
using namespace reactphysics3d; using namespace reactphysics3d;
int main() { int main() {
TestSuite testSuite("ReactPhysics3D tests"); TestSuite testSuite("ReactPhysics3D Tests");
// ---------- Mathematics tests ---------- // // ---------- Mathematics tests ---------- //
testSuite.addTest(new TestVector3); testSuite.addTest(new TestVector3);
testSuite.addTest(new TestTransform); testSuite.addTest(new TestTransform);
testSuite.addTest(new TestQuaternion); testSuite.addTest(new TestQuaternion);
testSuite.addTest(new TestMatrix3x3);
// ----------------------------- --------- // // ----------------------------- --------- //

View File

@ -51,21 +51,229 @@ class TestMatrix3x3 : public Test {
/// Identity transform /// Identity transform
Matrix3x3 mIdentity; Matrix3x3 mIdentity;
/// First example matrix
Matrix3x3 mMatrix1;
public : public :
// ---------- Methods ---------- // // ---------- Methods ---------- //
/// Constructor /// Constructor
TestMatrix3x3() : mIdentity(Matrix3x3::identity()){ TestMatrix3x3() : mIdentity(Matrix3x3::identity()),
mMatrix1(2, 24, 4, 5, -6, 234, -15, 11, 66) {
} }
/// Run the tests /// Run the tests
void run() { void run() {
testConstructors();
testGetSet();
testIdentity();
testOthersMethods();
testOperators();
} }
/// Test the constructors
void testConstructors() {
Matrix3x3 test1(5.0);
Matrix3x3 test2(2, 3, 4, 5, 6, 7, 8, 9, 10);
Matrix3x3 test3(mMatrix1);
test(test1[0][0] == 5);
test(test1[0][1] == 5);
test(test1[0][2] == 5);
test(test1[1][0] == 5);
test(test1[1][1] == 5);
test(test1[1][2] == 5);
test(test1[2][0] == 5);
test(test1[2][1] == 5);
test(test1[2][2] == 5);
test(test2[0][0] == 2);
test(test2[0][1] == 3);
test(test2[0][2] == 4);
test(test2[1][0] == 5);
test(test2[1][1] == 6);
test(test2[1][2] == 7);
test(test2[2][0] == 8);
test(test2[2][1] == 9);
test(test2[2][2] == 10);
test(test3 == mMatrix1);
}
/// Test the getter and setter methods
void testGetSet() {
// Test method to set all the values
Matrix3x3 test2;
test2.setAllValues(2, 24, 4, 5, -6, 234, -15, 11, 66);
test(test2 == mMatrix1);
// Test method to set to zero
test2.setToZero();
test(test2 == Matrix3x3(0, 0, 0, 0, 0, 0, 0, 0, 0));
// Test method that returns a column
Vector3 column1 = mMatrix1.getColumn(0);
Vector3 column2 = mMatrix1.getColumn(1);
Vector3 column3 = mMatrix1.getColumn(2);
test(column1 == Vector3(2, 5, -15));
test(column2 == Vector3(24, -6, 11));
test(column3 == Vector3(4, 234, 66));
// Test method that returns a row
Vector3 row1 = mMatrix1.getRow(0);
Vector3 row2 = mMatrix1.getRow(1);
Vector3 row3 = mMatrix1.getRow(2);
test(row1 == Vector3(2, 24, 4));
test(row2 == Vector3(5, -6, 234));
test(row3 == Vector3(-15, 11, 66));
}
/// Test the identity methods
void testIdentity() {
Matrix3x3 identity = Matrix3x3::identity();
Matrix3x3 test1;
test1.setToIdentity();
test(identity[0][0] == 1);
test(identity[0][1] == 0);
test(identity[0][2] == 0);
test(identity[1][0] == 0);
test(identity[1][1] == 1);
test(identity[1][2] == 0);
test(identity[2][0] == 0);
test(identity[2][1] == 0);
test(identity[2][2] == 1);
test(test1 == Matrix3x3::identity());
}
/// Test others methods
void testOthersMethods() {
// Test transpose
Matrix3x3 transpose = mMatrix1.getTranspose();
test(transpose == Matrix3x3(2, 5, -15, 24, -6, 11, 4, 234, 66));
// Test trace
test(mMatrix1.getTrace() == 62);
test(Matrix3x3::identity().getTrace() == 3);
// Test determinant
Matrix3x3 matrix(-24, 64, 253, -35, 52, 72, 21, -35, -363);
test(mMatrix1.getDeterminant() == -98240);
test(matrix.getDeterminant() == -290159);
test(mIdentity.getDeterminant() == 1);
// Test inverse
Matrix3x3 inverseMatrix = matrix.getInverse();
test(approxEqual(inverseMatrix[0][0], decimal(0.056369), decimal(10e-6)));
test(approxEqual(inverseMatrix[0][1], decimal(-0.049549), decimal(10e-6)));
test(approxEqual(inverseMatrix[0][2], decimal(0.029460), decimal(10e-6)));
test(approxEqual(inverseMatrix[1][0], decimal(0.038575), decimal(10e-6)));
test(approxEqual(inverseMatrix[1][1], decimal(-0.011714), decimal(10e-6)));
test(approxEqual(inverseMatrix[1][2], decimal(0.024562), decimal(10e-6)));
test(approxEqual(inverseMatrix[2][0], decimal(-0.000458), decimal(10e-6)));
test(approxEqual(inverseMatrix[2][1], decimal(-0.001737), decimal(10e-6)));
test(approxEqual(inverseMatrix[2][2], decimal(-0.003419), decimal(10e-6)));
Matrix3x3 inverseMatrix1 = mMatrix1.getInverse();
test(approxEqual(inverseMatrix1[0][0], decimal(0.030232), decimal(10e-6)));
test(approxEqual(inverseMatrix1[0][1], decimal(0.015676), decimal(10e-6)));
test(approxEqual(inverseMatrix1[0][2], decimal(-0.057410), decimal(10e-6)));
test(approxEqual(inverseMatrix1[1][0], decimal(0.039088), decimal(10e-6)));
test(approxEqual(inverseMatrix1[1][1], decimal(-0.001954), decimal(10e-6)));
test(approxEqual(inverseMatrix1[1][2], decimal(0.004560), decimal(10e-6)));
test(approxEqual(inverseMatrix1[2][0], decimal(0.000356), decimal(10e-6)));
test(approxEqual(inverseMatrix1[2][1], decimal(0.003888), decimal(10e-6)));
test(approxEqual(inverseMatrix1[2][2], decimal(0.001344), decimal(10e-6)));
// Test absolute matrix
Matrix3x3 matrix2(-2, -3, -4, -5, -6, -7, -8, -9, -10);
test(matrix.getAbsoluteMatrix() == Matrix3x3(24, 64, 253, 35, 52, 72, 21, 35, 363));
Matrix3x3 absoluteMatrix = matrix2.getAbsoluteMatrix();
test(absoluteMatrix == Matrix3x3(2, 3, 4, 5, 6, 7, 8, 9, 10));
}
/// Test the operators
void testOperators() {
// Test addition
Matrix3x3 matrix1(2, 3, 4, 5, 6, 7, 8, 9, 10);
Matrix3x3 matrix2(-2, 3, -5, 10, 4, 7, 2, 5, 8);
Matrix3x3 addition1 = matrix1 + matrix2;
Matrix3x3 addition2(matrix1);
addition2 += matrix2;
test(addition1 == Matrix3x3(0, 6, -1, 15, 10, 14, 10, 14, 18));
test(addition2 == Matrix3x3(0, 6, -1, 15, 10, 14, 10, 14, 18));
// Test substraction
Matrix3x3 substraction1 = matrix1 - matrix2;
Matrix3x3 substraction2(matrix1);
substraction2 -= matrix2;
test(substraction1 == Matrix3x3(4, 0, 9, -5, 2, 0, 6, 4, 2));
test(substraction2 == Matrix3x3(4, 0, 9, -5, 2, 0, 6, 4, 2));
// Test negative operator
Matrix3x3 negative = -matrix1;
test(negative == Matrix3x3(-2, -3, -4, -5, -6, -7, -8, -9, -10));
// Test multiplication with a number
Matrix3x3 multiplication1 = 3 * matrix1;
Matrix3x3 multiplication2 = matrix1 * 3;
Matrix3x3 multiplication3(matrix1);
multiplication3 *= 3;
test(multiplication1 == Matrix3x3(6, 9, 12, 15, 18, 21, 24, 27, 30));
test(multiplication2 == Matrix3x3(6, 9, 12, 15, 18, 21, 24, 27, 30));
test(multiplication3 == Matrix3x3(6, 9, 12, 15, 18, 21, 24, 27, 30));
// Test multiplication with a matrix
Matrix3x3 multiplication4 = matrix1 * matrix2;
Matrix3x3 multiplication5 = matrix2 * matrix1;
test(multiplication4 == Matrix3x3(34, 38, 43, 64, 74, 73, 94, 110, 103));
test(multiplication5 == Matrix3x3(-29, -33, -37, 96, 117, 138, 93, 108, 123));
// Test multiplication with a vector
Vector3 vector1(3, -32, 59);
Vector3 vector2(-31, -422, 34);
Vector3 test1 = matrix1 * vector1;
Vector3 test2 = matrix2 * vector2;
test(test1 == Vector3(146, 236, 326));
test(test2 == Vector3(-1374, -1760, -1900));
// Test equality operators
test(Matrix3x3(34, 38, 43, 64, 74, 73, 94, 110, 103) ==
Matrix3x3(34, 38, 43, 64, 74, 73, 94, 110, 103));
test(Matrix3x3(34, 64, 43, 7, -1, 73, 94, 110, 103) !=
Matrix3x3(34, 38, 43, 64, 74, 73, 94, 110, 103));
// Test operator to read a value
test(mMatrix1[0][0] == 2);
test(mMatrix1[0][1] == 24);
test(mMatrix1[0][2] == 4);
test(mMatrix1[1][0] == 5);
test(mMatrix1[1][1] == -6);
test(mMatrix1[1][2] == 234);
test(mMatrix1[2][0] == -15);
test(mMatrix1[2][1] == 11);
test(mMatrix1[2][2] == 66);
// Test operator to set a value
Matrix3x3 test3;
test3[0][0] = 2;
test3[0][1] = 24;
test3[0][2] = 4;
test3[1][0] = 5;
test3[1][1] = -6;
test3[1][2] = 234;
test3[2][0] = -15;
test3[2][1] = 11;
test3[2][2] = 66;
test(test3 == mMatrix1);
}
}; };

View File

@ -61,18 +61,25 @@ class TestQuaternion : public Test {
/// Constructor /// Constructor
TestQuaternion() : mIdentity(Quaternion::identity()) { TestQuaternion() : mIdentity(Quaternion::identity()) {
decimal sinA = sin(PI/8.0f); decimal sinA = sin(decimal(PI/8.0));
decimal cosA = cos(PI/8.0f); decimal cosA = cos(decimal(PI/8.0));
mQuaternion1 = Quaternion(sinA, sinA, sinA, cosA); Vector3 vector(2, 3, 4);
vector.normalize();
mQuaternion1 = Quaternion(vector.x * sinA, vector.y * sinA, vector.z * sinA, cosA);
mQuaternion1.normalize();
} }
/// Run the tests /// Run the tests
void run() { void run() {
testConstructors(); testConstructors();
testUnitLengthNormalize();
testOthersMethods();
testOperators();
} }
/// Test the constructors /// Test the constructors
void testConstructors() { void testConstructors() {
Quaternion quaternion1(mQuaternion1); Quaternion quaternion1(mQuaternion1);
test(mQuaternion1== quaternion1); test(mQuaternion1== quaternion1);
@ -80,21 +87,144 @@ class TestQuaternion : public Test {
test(quaternion2 == Quaternion(4, 5, 6, 7)); test(quaternion2 == Quaternion(4, 5, 6, 7));
Quaternion quaternion3(8, Vector3(3, 5, 2)); Quaternion quaternion3(8, Vector3(3, 5, 2));
test(quaternion3 == Quaternion(5, 6, 7, 4)); test(quaternion3 == Quaternion(3, 5, 2, 8));
Matrix3x3 matrix(2, 3, 4, 5, 6, 7, 8, 9, 10); Quaternion quaternion4(mQuaternion1.getMatrix());
Quaternion quaternion4(matrix); test(approxEqual(quaternion4.x, mQuaternion1.x));
Matrix3x3 result = quaternion4.getMatrix(); test(approxEqual(quaternion4.y, mQuaternion1.y));
test(approxEqual(matrix.getValue(0, 0), result.getValue(0, 0), 0.1)); test(approxEqual(quaternion4.z, mQuaternion1.z));
std::cout << "matrix : " << matrix.getValue(0, 0) << ", " << result.getValue(0, 0) << std::endl; test(approxEqual(quaternion4.w, mQuaternion1.w));
test(approxEqual(matrix.getValue(0, 1), result.getValue(0, 1), 0.1)); }
test(approxEqual(matrix.getValue(0, 2), result.getValue(0, 2), 0.1));
test(approxEqual(matrix.getValue(1, 0), result.getValue(1, 0), 0.1)); /// Test unit, length, normalize methods
test(approxEqual(matrix.getValue(1, 1), result.getValue(1, 1), 0.1)); void testUnitLengthNormalize() {
test(approxEqual(matrix.getValue(1, 2), result.getValue(1, 2), 0.1));
test(approxEqual(matrix.getValue(2, 0), result.getValue(2, 0), 0.1)); // Test method that returns the length
test(approxEqual(matrix.getValue(2, 1), result.getValue(2, 1), 0.1)); Quaternion quaternion(2, 3, -4, 5);
test(approxEqual(matrix.getValue(2, 2), result.getValue(2, 2), 0.1)); test(approxEqual(quaternion.length(), sqrt(decimal(54.0))));
// Test method that returns a unit quaternion
test(approxEqual(quaternion.getUnit().length(), 1.0));
// Test the normalization method
Quaternion quaternion2(4, 5, 6, 7);
quaternion2.normalize();
test(approxEqual(quaternion2.length(), 1.0));
}
/// Test others methods
void testOthersMethods() {
// Test the method to set the values
Quaternion quaternion;
quaternion.setAllValues(1, 2, 3, 4);
test(quaternion == Quaternion(1, 2, 3, 4));
// Test the method to set the quaternion to zero
quaternion.setToZero();
test(quaternion == Quaternion(0, 0, 0, 0));
// Test the method to get the vector (x, y, z)
Vector3 v = mQuaternion1.getVectorV();
test(v.x == mQuaternion1.x);
test(v.y == mQuaternion1.y);
test(v.z == mQuaternion1.z);
// Test the conjugate method
Quaternion conjugate = mQuaternion1.getConjugate();
test(conjugate.x == -mQuaternion1.x);
test(conjugate.y == -mQuaternion1.y);
test(conjugate.z == -mQuaternion1.z);
test(conjugate.w == mQuaternion1.w);
// Test the inverse method
Quaternion inverse = mQuaternion1.getInverse();
Quaternion product = mQuaternion1 * inverse;
test(approxEqual(product.x, mIdentity.x, decimal(10e-6)));
test(approxEqual(product.y, mIdentity.y, decimal(10e-6)));
test(approxEqual(product.z, mIdentity.z, decimal(10e-6)));
test(approxEqual(product.w, mIdentity.w, decimal(10e-6)));
// Test the dot product
Quaternion quaternion1(2, 3, 4, 5);
Quaternion quaternion2(6, 7, 8, 9);
decimal dotProduct = quaternion1.dot(quaternion2);
test(dotProduct == 110);
// Test the method that returns the rotation angle and axis
Vector3 axis;
decimal angle;
Vector3 originalAxis = Vector3(2, 3, 4).getUnit();
mQuaternion1.getRotationAngleAxis(angle, axis);
test(approxEqual(axis.x, originalAxis.x));
test(approxEqual(angle, decimal(PI/4.0), decimal(10e-6)));
// Test the method that returns the corresponding matrix
Matrix3x3 matrix = mQuaternion1.getMatrix();
Vector3 vector(56, -2, 82);
Vector3 vector1 = matrix * vector;
Vector3 vector2 = mQuaternion1 * vector;
test(approxEqual(vector1.x, vector2.x));
test(approxEqual(vector1.y, vector2.y));
test(approxEqual(vector1.z, vector2.z));
// Test slerp method
Quaternion quatStart = quaternion1.getUnit();
Quaternion quatEnd = quaternion2.getUnit();
Quaternion test1 = Quaternion::slerp(quatStart, quatEnd, 0.0);
Quaternion test2 = Quaternion::slerp(quatStart, quatEnd, 1.0);
test(test1 == quatStart);
test(test2 == quatEnd);
decimal sinA = sin(decimal(PI/4.0));
decimal cosA = cos(decimal(PI/4.0));
Quaternion quat(sinA, 0, 0, cosA);
Quaternion test3 = Quaternion::slerp(mIdentity, quat, decimal(0.5));
test(approxEqual(test3.x, sin(decimal(PI/8.0))));
test(approxEqual(test3.y, 0.0));
test(approxEqual(test3.z, 0.0));
test(approxEqual(test3.w, cos(decimal(PI/8.0)), decimal(10e-6)));
}
/// Test overloaded operators
void testOperators() {
// Test addition
Quaternion quat1(4, 5, 2, 10);
Quaternion quat2(-2, 7, 8, 3);
Quaternion test1 = quat1 + quat2;
test(test1 == Quaternion(2, 12, 10, 13));
// Test substraction
Quaternion test2 = quat1 - quat2;
test(test2 == Quaternion(6, -2, -6, 7));
// Test multiplication with a number
Quaternion test3 = quat1 * 3.0;
test(test3 == Quaternion(12, 15, 6, 30));
// Test multiplication between two quaternions
Quaternion test4 = quat1 * quat2;
Quaternion test5 = mQuaternion1 * mIdentity;
test(test4 == Quaternion(18, 49, 124, -13));
test(test5 == mQuaternion1);
// Test multiplication between a quaternion and a point
Vector3 point(5, -24, 563);
Vector3 vector1 = mIdentity * point;
Vector3 vector2 = mQuaternion1 * point;
Vector3 testVector2 = mQuaternion1.getMatrix() * point;
test(vector1 == point);
test(approxEqual(vector2.x, testVector2.x, decimal(10e-6)));
test(approxEqual(vector2.y, testVector2.y, decimal(10e-6)));
test(approxEqual(vector2.z, testVector2.z, decimal(10e-6)));
// Test assignment operator
Quaternion quaternion;
quaternion = mQuaternion1;
test(quaternion == mQuaternion1);
// Test equality operator
test(mQuaternion1 == mQuaternion1);
} }
}; };

View File

@ -82,6 +82,7 @@ class TestTransform : public Test {
testInverse(); testInverse();
testGetSetOpenGLMatrix(); testGetSetOpenGLMatrix();
testInterpolateTransform(); testInterpolateTransform();
testIdentity();
testOperators(); testOperators();
} }
@ -127,27 +128,27 @@ class TestTransform : public Test {
Transform transform; Transform transform;
Vector3 position = mTransform1.getPosition(); Vector3 position = mTransform1.getPosition();
Matrix3x3 orientation = mTransform1.getOrientation().getMatrix(); Matrix3x3 orientation = mTransform1.getOrientation().getMatrix();
decimal openglMatrix[16] = {orientation.getValue(0,0), orientation.getValue(1,0), decimal openglMatrix[16] = {orientation[0][0], orientation[1][0],
orientation.getValue(2,0), 0, orientation[2][0], 0,
orientation.getValue(0,1), orientation.getValue(1,1), orientation[0][1], orientation[1][1],
orientation.getValue(2,1), 0, orientation[2][1], 0,
orientation.getValue(0,2), orientation.getValue(1,2), orientation[0][2], orientation[1][2],
orientation.getValue(2,2), 0, orientation[2][2], 0,
position.x, position.y, position.z, 1}; position.x, position.y, position.z, 1};
transform.setFromOpenGL(openglMatrix); transform.setFromOpenGL(openglMatrix);
decimal openglMatrix2[16]; decimal openglMatrix2[16];
transform.getOpenGLMatrix(openglMatrix2); transform.getOpenGLMatrix(openglMatrix2);
test(approxEqual(openglMatrix2[0], orientation.getValue(0,0))); test(approxEqual(openglMatrix2[0], orientation[0][0]));
test(approxEqual(openglMatrix2[1], orientation.getValue(1,0))); test(approxEqual(openglMatrix2[1], orientation[1][0]));
test(approxEqual(openglMatrix2[2], orientation.getValue(2,0))); test(approxEqual(openglMatrix2[2], orientation[2][0]));
test(approxEqual(openglMatrix2[3], 0)); test(approxEqual(openglMatrix2[3], 0));
test(approxEqual(openglMatrix2[4], orientation.getValue(0,1))); test(approxEqual(openglMatrix2[4], orientation[0][1]));
test(approxEqual(openglMatrix2[5], orientation.getValue(1,1))); test(approxEqual(openglMatrix2[5], orientation[1][1]));
test(approxEqual(openglMatrix2[6], orientation.getValue(2,1))); test(approxEqual(openglMatrix2[6], orientation[2][1]));
test(approxEqual(openglMatrix2[7], 0)); test(approxEqual(openglMatrix2[7], 0));
test(approxEqual(openglMatrix2[8], orientation.getValue(0,2))); test(approxEqual(openglMatrix2[8], orientation[0][2]));
test(approxEqual(openglMatrix2[9], orientation.getValue(1,2))); test(approxEqual(openglMatrix2[9], orientation[1][2]));
test(approxEqual(openglMatrix2[10], orientation.getValue(2,2))); test(approxEqual(openglMatrix2[10], orientation[2][2]));
test(approxEqual(openglMatrix2[11], 0)); test(approxEqual(openglMatrix2[11], 0));
test(approxEqual(openglMatrix2[12], position.x)); test(approxEqual(openglMatrix2[12], position.x));
test(approxEqual(openglMatrix2[13], position.y)); test(approxEqual(openglMatrix2[13], position.y));
@ -180,6 +181,18 @@ class TestTransform : public Test {
test(approxEqual(orientation.w, cosB)); test(approxEqual(orientation.w, cosB));
} }
/// Test the identity methods
void testIdentity() {
Transform transform = Transform::identity();
test(transform.getPosition() == Vector3(0, 0, 0));
test(transform.getOrientation() == Quaternion::identity());
Transform transform2(Vector3(5, 6, 2), Quaternion(3, 5, 1, 6));
transform2.setToIdentity();
test(transform2.getPosition() == Vector3(0, 0, 0));
test(transform2.getOrientation() == Quaternion::identity());
}
/// Test the overloaded operators /// Test the overloaded operators
void testOperators() { void testOperators() {

View File

@ -92,6 +92,10 @@ class TestVector3 : public Test {
test(approxEqual(newVector2.x, decimal(6.1))); test(approxEqual(newVector2.x, decimal(6.1)));
test(approxEqual(newVector2.y, decimal(7.2))); test(approxEqual(newVector2.y, decimal(7.2)));
test(approxEqual(newVector2.z, decimal(8.6))); test(approxEqual(newVector2.z, decimal(8.6)));
// Test method to set to zero
newVector2.setToZero();
test(newVector2 == Vector3(0, 0, 0));
} }
/// Test the length, unit vector and normalize methods /// Test the length, unit vector and normalize methods
@ -219,6 +223,11 @@ class TestVector3 : public Test {
vector4 /= 3; vector4 /= 3;
test(vector3 == Vector3(60, 330, 620)); test(vector3 == Vector3(60, 330, 620));
test(vector4 == Vector3(5, 20, 11)); test(vector4 == Vector3(5, 20, 11));
// Negative operator
Vector3 vector5(-34, 5, 422);
Vector3 negative = -vector5;
test(negative == Vector3(34, -5, -422));
} }
}; };