diff --git a/tests/QTestExtensions.hpp b/tests/QTestExtensions.hpp index 2ff213906d..e29ba9d426 100644 --- a/tests/QTestExtensions.hpp +++ b/tests/QTestExtensions.hpp @@ -73,6 +73,32 @@ inline QString QTest_generateCompareFailureMessage (const char * failMessage, co return msg; } +// Why does qt have to make things so complicated...? +inline QString makeMessageFromStream (std::function writeMessage) { + QString msg; + QTextStream stream(&msg); + writeMessage(stream); + return msg; +} + +inline void QTest_failWithCustomMessage (std::function writeMessage, int line, const char *file) +{ + QTest::qFail(qPrintable(makeMessageFromStream(writeMessage)), file, line); +} + +#define QFAIL_WITH_MESSAGE(...) \ +do { \ + QTest_failWithCustomMessage([&](QTextStream& stream) { stream << __VA_ARGS__; }, __LINE__, __FILE__); \ + return; \ +} while(0) + +inline void foo () { + int thing = 2; + QFAIL_WITH_MESSAGE("Message " << thing << ";"); +} + + + // Generates a QCOMPARE style failure message with custom arguments. // This is expected to be wrapped in a macro (see QFUZZY_COMPARE), and it must // actually return on failure (unless other functionality is desired). @@ -100,7 +126,9 @@ template inline auto QTest_fuzzyCompare(const T & actual, const T & expected, const char * actual_expr, const char * expected_expr, int line, const char * file, const V & epsilon) -> decltype(fuzzyCompare(actual, expected)) { if (fuzzyCompare(actual, expected) > epsilon) { - QTest::qFail(qPrintable(QTest_generateCompareFailureMessage("Compared values are not the same (fuzzy compare)", actual, expected, actual_expr, expected_expr, + QTest::qFail(qPrintable(QTest_generateCompareFailureMessage( + "Compared values are not the same (fuzzy compare)", + actual, expected, actual_expr, expected_expr, [&] (QTextStream & stream) -> QTextStream & { return stream << "Err tolerance: " << fuzzyCompare((actual), (expected)) << " > " << epsilon; })), file, line); @@ -115,4 +143,24 @@ do { \ return; \ } while(0) +#define QCOMPARE_WITH_FUNCTION(actual, expected, testFunc) \ +do { \ + if (!testFunc(actual, expected)) { \ + QTest_failWithMessage("Compared values are not the same", actual, expected, #actual, #expected, __LINE__, __FILE__); \ + return; \ + } \ +while (0) + +#define QCOMPARE_WITH_LAMBDA(actual, expected, testClosure) \ +do { \ + if (!testClosure()) \ + QTest_failWithMessage("Compared values are not the same", actual, expected, #actual, #expected, __LINE__, __FILE__); \ + return; \ + } \ +while (0) + #endif + + + + diff --git a/tests/physics/src/BulletUtilTests.cpp b/tests/physics/src/BulletUtilTests.cpp index e31618255d..ef01311710 100644 --- a/tests/physics/src/BulletUtilTests.cpp +++ b/tests/physics/src/BulletUtilTests.cpp @@ -42,7 +42,7 @@ void BulletUtilTests::fromBulletToGLM() { glm::quat gQ = bulletToGLM(bQ); QCOMPARE(gQ.x, bQ.getX()); QCOMPARE(gQ.y, bQ.getY()); - QCOMPARE(gQ.z, bQ.getZ() + 10); + QCOMPARE(gQ.z, bQ.getZ()); QCOMPARE(gQ.w, bQ.getW()); } @@ -66,11 +66,11 @@ void BulletUtilTests::fromGLMToBullet() { QCOMPARE(gQ.w, bQ.getW()); } -void BulletUtilTests::fooTest () { - - glm::vec3 a { 1, 0, 3 }; - glm::vec3 b { 2, 0, 5 }; - -// QCOMPARE(10, 22); - QFUZZY_COMPARE(a, b, 1.0f); -} +//void BulletUtilTests::fooTest () { +// +// glm::vec3 a { 1, 0, 3 }; +// glm::vec3 b { 2, 0, 5 }; +// +//// QCOMPARE(10, 22); +// QFUZZY_COMPARE(a, b, 1.0f); +//} diff --git a/tests/physics/src/BulletUtilTests.h b/tests/physics/src/BulletUtilTests.h index 804b91bb8a..42606fb950 100644 --- a/tests/physics/src/BulletUtilTests.h +++ b/tests/physics/src/BulletUtilTests.h @@ -22,7 +22,7 @@ class BulletUtilTests : public QObject { private slots: void fromBulletToGLM(); void fromGLMToBullet(); - void fooTest (); +// void fooTest (); }; // Define comparison + printing functions for the data types we need diff --git a/tests/physics/src/MeshMassPropertiesTests.cpp b/tests/physics/src/MeshMassPropertiesTests.cpp index d4d1a6768b..b0b5e63082 100644 --- a/tests/physics/src/MeshMassPropertiesTests.cpp +++ b/tests/physics/src/MeshMassPropertiesTests.cpp @@ -86,7 +86,7 @@ void MeshMassPropertiesTests::testParallelAxisTheorem() { // } // Try commenting this out to see what happens when the test fails - twoSmallBoxesInertia[0][2] += 10; +// twoSmallBoxesInertia[0][2] += 10; // This now does the same as the above (using the maxDiff fuzzyCompare impl for two btMatrices) QFUZZY_COMPARE(bitBoxInertia, twoSmallBoxesInertia, acceptableAbsoluteError); @@ -101,10 +101,7 @@ void MeshMassPropertiesTests::testParallelAxisTheorem() { void MeshMassPropertiesTests::testTetrahedron(){ // given the four vertices of a tetrahedron verify the analytic formula for inertia // agrees with expected results -#ifdef VERBOSE_UNIT_TESTS - std::cout << "\n" << __FUNCTION__ << std::endl; -#endif // VERBOSE_UNIT_TESTS - + // these numbers from the Tonon paper: btVector3 points[4]; points[0] = btVector3(8.33220f, -11.86875f, 0.93355f); @@ -142,37 +139,59 @@ void MeshMassPropertiesTests::testTetrahedron(){ } btMatrix3x3 inertia; computeTetrahedronInertia(volume, points, inertia); - - // verify - for (int i = 0; i < 3; ++i) { - for (int j = 0; j < 3; ++j) { - error = (inertia[i][j] - expectedInertia[i][j]) / expectedInertia[i][j]; - if (fabsf(error) > acceptableRelativeError) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR : inertia[" << i << "][" << j << "] off by " - << error << std::endl; + + // if error = (volume - expectedVolume) / expectedVolume + // then fabsf(error) > acceptableRelativeError == fabsf(volume - expectedVolume) > err + // where err = acceptableRelativeError * expectedVolume + + QFUZZY_COMPARE(volume, expectedVolume, acceptableRelativeError * volume); + + // pseudo-hack -- error value is calculated per-element, so QFUZZY_COMPARE will not work. + // QCOMPARE_WITH_FUNCTION and QCOMPARE_WITH_LAMBDA lets you get around this by writing + // a custom function to do the actual comparison; printing, etc is done automatically. + auto testFunc = [&inertia, &expectedInertia] () { + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + auto error = (inertia[i][j] - expectedInertia[i][j]) / expectedInertia[i][j]; + if (fabsf(error) > acceptableRelativeError) + return false; } } - } + return true; + }; + QCOMPARE_WITH_LAMBDA(inertia, expectedInertia, testFunc); + + QCOMPARE_WITH_RELATIVE_ERROR(inertia, expectedInertia, acceptableRelativeError); +// // verify +// for (int i = 0; i < 3; ++i) { +// for (int j = 0; j < 3; ++j) { +// error = (inertia[i][j] - expectedInertia[i][j]) / expectedInertia[i][j]; +// if (fabsf(error) > acceptableRelativeError) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR : inertia[" << i << "][" << j << "] off by " +// << error << std::endl; +// } +// } +// } -#ifdef VERBOSE_UNIT_TESTS - std::cout << "expected volume = " << expectedVolume << std::endl; - std::cout << "measured volume = " << volume << std::endl; - printMatrix("expected inertia", expectedInertia); - printMatrix("computed inertia", inertia); - - // when building VERBOSE you might be instrested in the results from the brute force method: - btMatrix3x3 bruteInertia; - computeTetrahedronInertiaByBruteForce(points, bruteInertia); - printMatrix("brute inertia", bruteInertia); -#endif // VERBOSE_UNIT_TESTS +//#ifdef VERBOSE_UNIT_TESTS +// std::cout << "expected volume = " << expectedVolume << std::endl; +// std::cout << "measured volume = " << volume << std::endl; +// printMatrix("expected inertia", expectedInertia); +// printMatrix("computed inertia", inertia); +// +// // when building VERBOSE you might be instrested in the results from the brute force method: +// btMatrix3x3 bruteInertia; +// computeTetrahedronInertiaByBruteForce(points, bruteInertia); +// printMatrix("brute inertia", bruteInertia); +//#endif // VERBOSE_UNIT_TESTS } void MeshMassPropertiesTests::testOpenTetrahedonMesh() { // given the simplest possible mesh (open, with one triangle) // verify MeshMassProperties computes the right nubers -#ifdef VERBOSE_UNIT_TESTS - std::cout << "\n" << __FUNCTION__ << std::endl; -#endif // VERBOSE_UNIT_TESTS +//#ifdef VERBOSE_UNIT_TESTS +// std::cout << "\n" << __FUNCTION__ << std::endl; +//#endif // VERBOSE_UNIT_TESTS // these numbers from the Tonon paper: VectorOfPoints points; @@ -208,27 +227,37 @@ void MeshMassPropertiesTests::testOpenTetrahedonMesh() { MeshMassProperties mesh(shiftedPoints, triangles); // verify - btScalar error = (mesh._volume - expectedVolume) / expectedVolume; - if (fabsf(error) > acceptableRelativeError) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR : volume of tetrahedron off by = " - << error << std::endl; - } + // (expected - actual) / expected > e ==> expected - actual > e * expected + QFUZZY_COMPARE(mesh._volume, expectedVolume, acceptableRelativeError * expectedVolume); + + + +// btScalar error = (mesh._volume - expectedVolume) / expectedVolume; +// if (fabsf(error) > acceptableRelativeError) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR : volume of tetrahedron off by = " +// << error << std::endl; +// } - error = (mesh._centerOfMass - expectedCenterOfMass).length(); - if (fabsf(error) > acceptableAbsoluteError) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR : centerOfMass of tetrahedron off by = " - << error << std::endl; - } + + QFUZZY_COMPARE(mesh._centerOfMass, expectedCenterOfMass, acceptableAbsoluteError); + +// error = (mesh._centerOfMass - expectedCenterOfMass).length(); +// if (fabsf(error) > acceptableAbsoluteError) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR : centerOfMass of tetrahedron off by = " +// << error << std::endl; +// } + + QCOMPARE_WITH_RELATIVE_ERROR(mesh._inertia, expectedInertia, acceptableRelativeError); - for (int i = 0; i < 3; ++i) { - for (int j = 0; j < 3; ++j) { - error = (mesh._inertia[i][j] - expectedInertia[i][j]) / expectedInertia[i][j]; - if (fabsf(error) > acceptableRelativeError) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR : inertia[" << i << "][" << j << "] off by " - << error << std::endl; - } - } - } +// for (int i = 0; i < 3; ++i) { +// for (int j = 0; j < 3; ++j) { +// error = (mesh._inertia[i][j] - expectedInertia[i][j]) / expectedInertia[i][j]; +// if (fabsf(error) > acceptableRelativeError) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR : inertia[" << i << "][" << j << "] off by " +// << error << std::endl; +// } +// } +// } #ifdef VERBOSE_UNIT_TESTS std::cout << "expected volume = " << expectedVolume << std::endl; @@ -277,36 +306,40 @@ void MeshMassPropertiesTests::testClosedTetrahedronMesh() { MeshMassProperties mesh(points, triangles); // verify - btScalar error; - error = (mesh._volume - expectedVolume) / expectedVolume; - if (fabsf(error) > acceptableRelativeError) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR : volume of tetrahedron off by = " - << error << std::endl; - } + QFUZZY_COMPARE(mesh._volume, expectedVolume, acceptableRelativeError); +// btScalar error; +// error = (mesh._volume - expectedVolume) / expectedVolume; +// if (fabsf(error) > acceptableRelativeError) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR : volume of tetrahedron off by = " +// << error << std::endl; +// } - error = (mesh._centerOfMass - expectedCenterOfMass).length(); - if (fabsf(error) > acceptableAbsoluteError) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR : centerOfMass of tetrahedron off by = " - << error << std::endl; - } + + QFUZZY_COMPARE(mesh._centerOfMass, expectedCenterOfMass, acceptableAbsoluteError); +// error = (mesh._centerOfMass - expectedCenterOfMass).length(); +// if (fabsf(error) > acceptableAbsoluteError) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR : centerOfMass of tetrahedron off by = " +// << error << std::endl; +// } - for (int i = 0; i < 3; ++i) { - for (int j = 0; j < 3; ++j) { - error = (mesh._inertia[i][j] - expectedInertia[i][j]) / expectedInertia[i][j]; - if (fabsf(error) > acceptableRelativeError) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR : inertia[" << i << "][" << j << "] off by " - << error << std::endl; - } - } - } + QCOMPARE_WITH_RELATIVE_ERROR(mesh._inertia, expectedInertia, acceptableRelativeError); +// for (int i = 0; i < 3; ++i) { +// for (int j = 0; j < 3; ++j) { +// error = (mesh._inertia[i][j] - expectedInertia[i][j]) / expectedInertia[i][j]; +// if (fabsf(error) > acceptableRelativeError) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR : inertia[" << i << "][" << j << "] off by " +// << error << std::endl; +// } +// } +// } -#ifdef VERBOSE_UNIT_TESTS - std::cout << "(a) tetrahedron as mesh" << std::endl; - std::cout << "expected volume = " << expectedVolume << std::endl; - std::cout << "measured volume = " << mesh._volume << std::endl; - printMatrix("expected inertia", expectedInertia); - printMatrix("computed inertia", mesh._inertia); -#endif // VERBOSE_UNIT_TESTS +//#ifdef VERBOSE_UNIT_TESTS +// std::cout << "(a) tetrahedron as mesh" << std::endl; +// std::cout << "expected volume = " << expectedVolume << std::endl; +// std::cout << "measured volume = " << mesh._volume << std::endl; +// printMatrix("expected inertia", expectedInertia); +// printMatrix("computed inertia", mesh._inertia); +//#endif // VERBOSE_UNIT_TESTS // test again, but this time shift the points so that the origin is definitely OUTSIDE the mesh btVector3 shift = points[0] + expectedCenterOfMass; @@ -319,42 +352,45 @@ void MeshMassPropertiesTests::testClosedTetrahedronMesh() { mesh.computeMassProperties(points, triangles); // verify - error = (mesh._volume - expectedVolume) / expectedVolume; - if (fabsf(error) > acceptableRelativeError) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR : volume of tetrahedron off by = " - << error << std::endl; - } +// QFUZZY_COMPARE(mesh._volume, expectedVolume, acceptableRelativeError * expectedVolume); +//// error = (mesh._volume - expectedVolume) / expectedVolume; +//// if (fabsf(error) > acceptableRelativeError) { +//// std::cout << __FILE__ << ":" << __LINE__ << " ERROR : volume of tetrahedron off by = " +//// << error << std::endl; +//// } +// +// QFUZZY_COMPARE(mesh._centerOfMass, expectedCenterOfMass, acceptableAbsoluteError); +//// error = (mesh._centerOfMass - expectedCenterOfMass).length(); +//// if (fabsf(error) > acceptableAbsoluteError) { +//// std::cout << __FILE__ << ":" << __LINE__ << " ERROR : centerOfMass of tetrahedron off by = " +//// << error << std::endl; +//// } +// +// QCOMPARE_WITH_RELATIVE_ERROR(mesh._inertia, expectedInertia, acceptableRelativeError); +//// for (int i = 0; i < 3; ++i) { +//// for (int j = 0; j < 3; ++j) { +//// error = (mesh._inertia[i][j] - expectedInertia[i][j]) / expectedInertia[i][j]; +//// if (fabsf(error) > acceptableRelativeError) { +//// std::cout << __FILE__ << ":" << __LINE__ << " ERROR : inertia[" << i << "][" << j << "] off by " +//// << error << std::endl; +//// } +//// } +//// } - error = (mesh._centerOfMass - expectedCenterOfMass).length(); - if (fabsf(error) > acceptableAbsoluteError) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR : centerOfMass of tetrahedron off by = " - << error << std::endl; - } - - for (int i = 0; i < 3; ++i) { - for (int j = 0; j < 3; ++j) { - error = (mesh._inertia[i][j] - expectedInertia[i][j]) / expectedInertia[i][j]; - if (fabsf(error) > acceptableRelativeError) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR : inertia[" << i << "][" << j << "] off by " - << error << std::endl; - } - } - } - -#ifdef VERBOSE_UNIT_TESTS - std::cout << "(b) shifted tetrahedron as mesh" << std::endl; - std::cout << "expected volume = " << expectedVolume << std::endl; - std::cout << "measured volume = " << mesh._volume << std::endl; - printMatrix("expected inertia", expectedInertia); - printMatrix("computed inertia", mesh._inertia); -#endif // VERBOSE_UNIT_TESTS +//#ifdef VERBOSE_UNIT_TESTS +// std::cout << "(b) shifted tetrahedron as mesh" << std::endl; +// std::cout << "expected volume = " << expectedVolume << std::endl; +// std::cout << "measured volume = " << mesh._volume << std::endl; +// printMatrix("expected inertia", expectedInertia); +// printMatrix("computed inertia", mesh._inertia); +//#endif // VERBOSE_UNIT_TESTS } void MeshMassPropertiesTests::testBoxAsMesh() { // verify that a mesh box produces the same mass properties as the analytic box. -#ifdef VERBOSE_UNIT_TESTS - std::cout << "\n" << __FUNCTION__ << std::endl; -#endif // VERBOSE_UNIT_TESTS +//#ifdef VERBOSE_UNIT_TESTS +// std::cout << "\n" << __FUNCTION__ << std::endl; +//#endif // VERBOSE_UNIT_TESTS // build a box: @@ -411,58 +447,56 @@ void MeshMassPropertiesTests::testBoxAsMesh() { MeshMassProperties mesh(points, triangles); // verify - btScalar error; - error = (mesh._volume - expectedVolume) / expectedVolume; - if (fabsf(error) > acceptableRelativeError) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR : volume of tetrahedron off by = " - << error << std::endl; - } + + QFUZZY_COMPARE(mesh._volume, expectedVolume, acceptableRelativeError * expectedVolume); +// btScalar error; +// error = (mesh._volume - expectedVolume) / expectedVolume; +// if (fabsf(error) > acceptableRelativeError) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR : volume of tetrahedron off by = " +// << error << std::endl; +// } - error = (mesh._centerOfMass - expectedCenterOfMass).length(); - if (fabsf(error) > acceptableAbsoluteError) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR : centerOfMass of tetrahedron off by = " - << error << std::endl; - } + QFUZZY_COMPARE(mesh._centerOfMass, expectedCenterOfMass, acceptableAbsoluteError); +// error = (mesh._centerOfMass - expectedCenterOfMass).length(); +// if (fabsf(error) > acceptableAbsoluteError) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR : centerOfMass of tetrahedron off by = " +// << error << std::endl; +// } - for (int i = 0; i < 3; ++i) { - for (int j = 0; j < 3; ++j) { - if (expectedInertia [i][j] == btScalar(0.0f)) { - error = mesh._inertia[i][j] - expectedInertia[i][j]; - if (fabsf(error) > acceptableAbsoluteError) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR : inertia[" << i << "][" << j << "] off by " - << error << " absolute"<< std::endl; - } - } else { - error = (mesh._inertia[i][j] - expectedInertia[i][j]) / expectedInertia[i][j]; - if (fabsf(error) > acceptableRelativeError) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR : inertia[" << i << "][" << j << "] off by " - << error << std::endl; - } - } - } - } + + // do this twice to avoid divide-by-zero? + QFUZZY_COMPARE(mesh._inertia, expectedInertia, acceptableAbsoluteError); + QCOMPARE_WITH_RELATIVE_ERROR(mesh._inertia, expectedInertia, acceptableRelativeError); +// for (int i = 0; i < 3; ++i) { +// for (int j = 0; j < 3; ++j) { +// if (expectedInertia [i][j] == btScalar(0.0f)) { +// error = mesh._inertia[i][j] - expectedInertia[i][j]; +// if (fabsf(error) > acceptableAbsoluteError) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR : inertia[" << i << "][" << j << "] off by " +// << error << " absolute"<< std::endl; +// } +// } else { +// error = (mesh._inertia[i][j] - expectedInertia[i][j]) / expectedInertia[i][j]; +// if (fabsf(error) > acceptableRelativeError) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR : inertia[" << i << "][" << j << "] off by " +// << error << std::endl; +// } +// } +// } +// } -#ifdef VERBOSE_UNIT_TESTS - std::cout << "expected volume = " << expectedVolume << std::endl; - std::cout << "measured volume = " << mesh._volume << std::endl; - std::cout << "expected center of mass = < " - << expectedCenterOfMass[0] << ", " - << expectedCenterOfMass[1] << ", " - << expectedCenterOfMass[2] << "> " << std::endl; - std::cout << "computed center of mass = < " - << mesh._centerOfMass[0] << ", " - << mesh._centerOfMass[1] << ", " - << mesh._centerOfMass[2] << "> " << std::endl; - printMatrix("expected inertia", expectedInertia); - printMatrix("computed inertia", mesh._inertia); -#endif // VERBOSE_UNIT_TESTS +//#ifdef VERBOSE_UNIT_TESTS +// std::cout << "expected volume = " << expectedVolume << std::endl; +// std::cout << "measured volume = " << mesh._volume << std::endl; +// std::cout << "expected center of mass = < " +// << expectedCenterOfMass[0] << ", " +// << expectedCenterOfMass[1] << ", " +// << expectedCenterOfMass[2] << "> " << std::endl; +// std::cout << "computed center of mass = < " +// << mesh._centerOfMass[0] << ", " +// << mesh._centerOfMass[1] << ", " +// << mesh._centerOfMass[2] << "> " << std::endl; +// printMatrix("expected inertia", expectedInertia); +// printMatrix("computed inertia", mesh._inertia); +//#endif // VERBOSE_UNIT_TESTS } - -//void MeshMassPropertiesTests::runAllTests() { -// testParallelAxisTheorem(); -// testTetrahedron(); -// testOpenTetrahedonMesh(); -// testClosedTetrahedronMesh(); -// testBoxAsMesh(); -// //testWithCube(); -//} diff --git a/tests/physics/src/MeshMassPropertiesTests.h b/tests/physics/src/MeshMassPropertiesTests.h index 6d0b2bae4b..6ebe016535 100644 --- a/tests/physics/src/MeshMassPropertiesTests.h +++ b/tests/physics/src/MeshMassPropertiesTests.h @@ -32,17 +32,17 @@ private slots: // Define comparison + printing functions for the data types we need -inline float fuzzyCompare (const glm::vec3 & a, const glm::vec3 & b) { +inline float fuzzyCompare(const glm::vec3 & a, const glm::vec3 & b) { return glm::distance(a, b); } inline QTextStream & operator << (QTextStream & stream, const glm::vec3 & v) { return stream << "glm::vec3 { " << v.x << ", " << v.y << ", " << v.z << " }"; } -inline btScalar fuzzyCompare (const btScalar & a, const btScalar & b) { +inline btScalar fuzzyCompare(const btScalar & a, const btScalar & b) { return fabs(a - b); } -// uh... how do we compare matrices? -// Guess we'll just do this element-wise for the time being + +// Matrices are compared element-wise -- if the error value for any element > epsilon, then fail inline btScalar fuzzyCompare (const btMatrix3x3 & a, const btMatrix3x3 & b) { btScalar totalDiff = 0; btScalar maxDiff = 0; @@ -56,6 +56,7 @@ inline btScalar fuzzyCompare (const btMatrix3x3 & a, const btMatrix3x3 & b) { // return totalDiff; return maxDiff; } + inline QTextStream & operator << (QTextStream & stream, const btMatrix3x3 & matrix) { stream << "[\n\t\t"; for (int i = 0; i < 3; ++i) { @@ -68,7 +69,32 @@ inline QTextStream & operator << (QTextStream & stream, const btMatrix3x3 & matr return stream; } +inline btScalar fuzzyCompare(const btVector3 & a, const btVector3 & b) +{ + return (a - b).length(); +} +inline QTextStream & operator << (QTextStream & stream, const btVector3 & v) { + return stream << "btVector3 { " << v.x() << ", " << v.y() << ", " << v.z() << " }"; +} +// Produces a relative error test for btMatrix3x3 usable with QCOMPARE_WITH_LAMBDA +inline auto errorTest (const btMatrix3x3 & actual, const btMatrix3x3 & expected, const btScalar acceptableRelativeError) +-> std::function +{ + return [&actual, &expected, acceptableRelativeError] () { + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + auto err = (actual[i][j] - expected[i][j]) / expected[i][j]; + if (fabsf(err) > acceptableRelativeError) + return false; + } + } + return true; + }; +} + +#define QCOMPARE_WITH_RELATIVE_ERROR(actual, expected, relativeError) \ + QCOMPARE_WITH_LAMBDA(actual, expected, errorTest(actual, expected, relativeError)) // These hook into this (and must be defined first...) diff --git a/tests/physics/src/ShapeColliderTests.cpp b/tests/physics/src/ShapeColliderTests.cpp index 37fcef4915..4a896ca8a4 100644 --- a/tests/physics/src/ShapeColliderTests.cpp +++ b/tests/physics/src/ShapeColliderTests.cpp @@ -36,6 +36,10 @@ QTEST_MAIN(ShapeColliderTests) +void ShapeColliderTests::initTestCase() { + ShapeCollider::initDispatchTable(); +} + void ShapeColliderTests::sphereMissesSphere() { // non-overlapping spheres of unequal size float radiusA = 7.0f; @@ -219,13 +223,13 @@ void ShapeColliderTests::sphereTouchesCapsule() { // contactPoint is on surface of sphereA glm::vec3 expectedContactPoint = sphereA.getTranslation() - radiusA * yAxis; - - inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); - if (fabsf(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad contactPoint: expected = " << expectedContactPoint - << " actual = " << collision->_contactPoint << std::endl; - } + QFUZZY_COMPARE(collision->_contactPoint, expectedContactPoint, EPSILON); +// inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); +// if (fabsf(inaccuracy) > EPSILON) { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: bad contactPoint: expected = " << expectedContactPoint +// << " actual = " << collision->_contactPoint << std::endl; +// } // capsuleB collides with sphereA if (!ShapeCollider::collideShapes(&capsuleB, &sphereA, collisions)) @@ -243,12 +247,13 @@ void ShapeColliderTests::sphereTouchesCapsule() { // the ShapeCollider swapped the order of the shapes expectedPenetration *= -1.0f; } - inaccuracy = glm::length(collision->_penetration - expectedPenetration); - if (fabsf(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad penetration: expected = " << expectedPenetration - << " actual = " << collision->_penetration << std::endl; - } + QFUZZY_COMPARE(collision->_penetration, expectedPenetration, EPSILON); +// inaccuracy = glm::length(collision->_penetration - expectedPenetration); +// if (fabsf(inaccuracy) > EPSILON) { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: bad penetration: expected = " << expectedPenetration +// << " actual = " << collision->_penetration << std::endl; +// } // contactPoint is on surface of capsuleB glm::vec3 endPoint; @@ -258,12 +263,14 @@ void ShapeColliderTests::sphereTouchesCapsule() { // the ShapeCollider swapped the order of the shapes expectedContactPoint = axialOffset - radiusA * yAxis; } - inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); - if (fabsf(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad contactPoint: expected = " << expectedContactPoint - << " actual = " << collision->_contactPoint << std::endl; - } + + QFUZZY_COMPARE(collision->_contactPoint, expectedContactPoint, EPSILON); +// inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); +// if (fabsf(inaccuracy) > EPSILON) { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: bad contactPoint: expected = " << expectedContactPoint +// << " actual = " << collision->_contactPoint << std::endl; +// } } { // sphereA hits start cap at axis glm::vec3 axialOffset = - (halfHeightB + alpha * radiusA + beta * radiusB) * yAxis; @@ -280,21 +287,24 @@ void ShapeColliderTests::sphereTouchesCapsule() { // penetration points from sphereA into capsuleB CollisionInfo* collision = collisions.getCollision(numCollisions - 1); glm::vec3 expectedPenetration = ((1.0f - alpha) * radiusA + (1.0f - beta) * radiusB) * yAxis; - float inaccuracy = glm::length(collision->_penetration - expectedPenetration); - if (fabsf(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad penetration: expected = " << expectedPenetration - << " actual = " << collision->_penetration << std::endl; - } + + QFUZZY_COMPARE(collision->_penetration, expectedPenetration, EPSILON); +// float inaccuracy = glm::length(collision->_penetration - expectedPenetration); +// if (fabsf(inaccuracy) > EPSILON) { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: bad penetration: expected = " << expectedPenetration +// << " actual = " << collision->_penetration << std::endl; +// } // contactPoint is on surface of sphereA glm::vec3 expectedContactPoint = sphereA.getTranslation() + radiusA * yAxis; - inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); - if (fabsf(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad contactPoint: expected = " << expectedContactPoint - << " actual = " << collision->_contactPoint << std::endl; - } + QFUZZY_COMPARE(collision->_contactPoint, expectedContactPoint, EPSILON); +// inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); +// if (fabsf(inaccuracy) > EPSILON) { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: bad contactPoint: expected = " << expectedContactPoint +// << " actual = " << collision->_contactPoint << std::endl; +// } // capsuleB collides with sphereA if (!ShapeCollider::collideShapes(&capsuleB, &sphereA, collisions)) @@ -312,12 +322,13 @@ void ShapeColliderTests::sphereTouchesCapsule() { // the ShapeCollider swapped the order of the shapes expectedPenetration *= -1.0f; } - inaccuracy = glm::length(collision->_penetration - expectedPenetration); - if (fabsf(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad penetration: expected = " << expectedPenetration - << " actual = " << collision->_penetration << std::endl; - } + QFUZZY_COMPARE(collision->_penetration, expectedPenetration, EPSILON); +// inaccuracy = glm::length(collision->_penetration - expectedPenetration); +// if (fabsf(inaccuracy) > EPSILON) { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: bad penetration: expected = " << expectedPenetration +// << " actual = " << collision->_penetration << std::endl; +// } // contactPoint is on surface of capsuleB glm::vec3 startPoint; @@ -327,12 +338,13 @@ void ShapeColliderTests::sphereTouchesCapsule() { // the ShapeCollider swapped the order of the shapes expectedContactPoint = axialOffset + radiusA * yAxis; } - inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); - if (fabsf(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad contactPoint: expected = " << expectedContactPoint - << " actual = " << collision->_contactPoint << std::endl; - } + QFUZZY_COMPARE(collision->_contactPoint, expectedContactPoint, EPSILON); +// inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); +// if (fabsf(inaccuracy) > EPSILON) { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: bad contactPoint: expected = " << expectedContactPoint +// << " actual = " << collision->_contactPoint << std::endl; +// } } if (collisions.size() != numCollisions) { std::cout << __FILE__ << ":" << __LINE__ @@ -358,49 +370,57 @@ void ShapeColliderTests::capsuleMissesCapsule() { // side by side capsuleB.setTranslation((1.01f * totalRadius) * xAxis); - if (ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions)) - { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: capsule and capsule should NOT touch" << std::endl; - } - if (ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions)) - { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: capsule and capsule should NOT touch" << std::endl; - } + QCOMPARE(ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions), false); + QCOMPARE(ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions), false); +// if (ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions)) +// { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: capsule and capsule should NOT touch" << std::endl; +// } +// if (ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions)) +// { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: capsule and capsule should NOT touch" << std::endl; +// } // end to end capsuleB.setTranslation((1.01f * totalHalfLength) * xAxis); - if (ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions)) - { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: capsule and capsule should NOT touch" << std::endl; - } - if (ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions)) - { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: capsule and capsule should NOT touch" << std::endl; - } + QCOMPARE(ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions), false); + QCOMPARE(ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions), false); +// if (ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions)) +// { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: capsule and capsule should NOT touch" << std::endl; +// } +// if (ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions)) +// { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: capsule and capsule should NOT touch" << std::endl; +// } // rotate B and move it to the side glm::quat rotation = glm::angleAxis(PI_OVER_TWO, zAxis); capsuleB.setRotation(rotation); capsuleB.setTranslation((1.01f * (totalRadius + capsuleB.getHalfHeight())) * xAxis); - if (ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions)) - { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: capsule and capsule should NOT touch" << std::endl; - } - if (ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions)) - { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: capsule and capsule should NOT touch" << std::endl; - } + + QCOMPARE(ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions), false); + QCOMPARE(ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions), false); +// if (ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions)) +// { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: capsule and capsule should NOT touch" << std::endl; +// } +// if (ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions)) +// { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: capsule and capsule should NOT touch" << std::endl; +// } - if (collisions.size() > 0) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: expected empty collision list but size is " << collisions.size() << std::endl; - } + QCOMPARE(collisions.size(), 0); +// if (collisions.size() > 0) { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: expected empty collision list but size is " << collisions.size() << std::endl; +// } } void ShapeColliderTests::capsuleTouchesCapsule() { @@ -421,39 +441,45 @@ void ShapeColliderTests::capsuleTouchesCapsule() { { // side by side capsuleB.setTranslation((0.99f * totalRadius) * xAxis); - if (!ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions)) - { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: capsule and capsule should touch" << std::endl; - } else { - ++numCollisions; - } - if (!ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions)) - { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: capsule and capsule should touch" << std::endl; - } else { - ++numCollisions; - } + QCOMPARE(ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions), true); + QCOMPARE(ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions), true); + numCollisions += 2; +// if (!ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions)) +// { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: capsule and capsule should touch" << std::endl; +// } else { +// ++numCollisions; +// } +// if (!ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions)) +// { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: capsule and capsule should touch" << std::endl; +// } else { +// ++numCollisions; +// } } { // end to end capsuleB.setTranslation((0.99f * totalHalfLength) * yAxis); - - if (!ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions)) - { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: capsule and capsule should touch" << std::endl; - } else { - ++numCollisions; - } - if (!ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions)) - { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: capsule and capsule should touch" << std::endl; - } else { - ++numCollisions; - } + + QCOMPARE(ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions), true); + QCOMPARE(ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions), true); + numCollisions += 2; +// if (!ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions)) +// { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: capsule and capsule should touch" << std::endl; +// } else { +// ++numCollisions; +// } +// if (!ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions)) +// { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: capsule and capsule should touch" << std::endl; +// } else { +// ++numCollisions; +// } } { // rotate B and move it to the side @@ -461,20 +487,23 @@ void ShapeColliderTests::capsuleTouchesCapsule() { capsuleB.setRotation(rotation); capsuleB.setTranslation((0.99f * (totalRadius + capsuleB.getHalfHeight())) * xAxis); - if (!ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions)) - { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: capsule and capsule should touch" << std::endl; - } else { - ++numCollisions; - } - if (!ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions)) - { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: capsule and capsule should touch" << std::endl; - } else { - ++numCollisions; - } + QCOMPARE(ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions), true); + QCOMPARE(ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions), true); + numCollisions += 2; +// if (!ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions)) +// { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: capsule and capsule should touch" << std::endl; +// } else { +// ++numCollisions; +// } +// if (!ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions)) +// { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: capsule and capsule should touch" << std::endl; +// } else { +// ++numCollisions; +// } } { // again, but this time check collision details @@ -483,58 +512,66 @@ void ShapeColliderTests::capsuleTouchesCapsule() { capsuleB.setRotation(rotation); glm::vec3 positionB = ((totalRadius + capsuleB.getHalfHeight()) - overlap) * xAxis; capsuleB.setTranslation(positionB); - + // capsuleA vs capsuleB - if (!ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions)) - { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: capsule and capsule should touch" << std::endl; - } else { - ++numCollisions; - } + QCOMPARE(ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions), true); + ++numCollisions; +// if (!ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions)) +// { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: capsule and capsule should touch" << std::endl; +// } else { +// ++numCollisions; +// } CollisionInfo* collision = collisions.getCollision(numCollisions - 1); glm::vec3 expectedPenetration = overlap * xAxis; - float inaccuracy = glm::length(collision->_penetration - expectedPenetration); - if (fabsf(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad penetration: expected = " << expectedPenetration - << " actual = " << collision->_penetration << std::endl; - } + + QFUZZY_COMPARE(collision->_penetration, expectedPenetration, EPSILON); +// float inaccuracy = glm::length(collision->_penetration - expectedPenetration); +// if (fabsf(inaccuracy) > EPSILON) { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: bad penetration: expected = " << expectedPenetration +// << " actual = " << collision->_penetration << std::endl; +// } glm::vec3 expectedContactPoint = capsuleA.getTranslation() + radiusA * xAxis; - inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); - if (fabsf(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad contactPoint: expected = " << expectedContactPoint - << " actual = " << collision->_contactPoint << std::endl; - } + QFUZZY_COMPARE(collision->_contactPoint, expectedContactPoint, EPSILON); +// inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); +// if (fabsf(inaccuracy) > EPSILON) { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: bad contactPoint: expected = " << expectedContactPoint +// << " actual = " << collision->_contactPoint << std::endl; +// } // capsuleB vs capsuleA - if (!ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions)) - { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: capsule and capsule should touch" << std::endl; - } else { - ++numCollisions; - } - + QCOMPARE(ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions), true); + ++numCollisions; +// if (!ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions)) +// { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: capsule and capsule should touch" << std::endl; +// } else { +// ++numCollisions; +// } collision = collisions.getCollision(numCollisions - 1); expectedPenetration = - overlap * xAxis; - inaccuracy = glm::length(collision->_penetration - expectedPenetration); - if (fabsf(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad penetration: expected = " << expectedPenetration - << " actual = " << collision->_penetration << std::endl; - } + QFUZZY_COMPARE(collision->_penetration, expectedPenetration, EPSILON); +// inaccuracy = glm::length(collision->_penetration - expectedPenetration); +// if (fabsf(inaccuracy) > EPSILON) { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: bad penetration: expected = " << expectedPenetration +// << " actual = " << collision->_penetration << std::endl; +// } expectedContactPoint = capsuleB.getTranslation() - (radiusB + halfHeightB) * xAxis; - inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); - if (fabsf(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad contactPoint: expected = " << expectedContactPoint - << " actual = " << collision->_contactPoint << std::endl; - } + QFUZZY_COMPARE(collision->_contactPoint, expectedContactPoint, EPSILON); +// inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); +// if (fabsf(inaccuracy) > EPSILON) { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: bad contactPoint: expected = " << expectedContactPoint +// << " actual = " << collision->_contactPoint << std::endl; +// } } { // collide cylinder wall against cylinder wall @@ -546,30 +583,33 @@ void ShapeColliderTests::capsuleTouchesCapsule() { capsuleB.setTranslation(positionB); // capsuleA vs capsuleB - if (!ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions)) - { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: capsule and capsule should touch" << std::endl; - } else { - ++numCollisions; - } + QCOMPARE(ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions), true); +// if (!ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions)) +// { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: capsule and capsule should touch" << std::endl; +// } else { +// ++numCollisions; +// } CollisionInfo* collision = collisions.getCollision(numCollisions - 1); glm::vec3 expectedPenetration = overlap * zAxis; - float inaccuracy = glm::length(collision->_penetration - expectedPenetration); - if (fabsf(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad penetration: expected = " << expectedPenetration - << " actual = " << collision->_penetration << std::endl; - } + QFUZZY_COMPARE(collision->_penetration, expectedPenetration, EPSILON); +// float inaccuracy = glm::length(collision->_penetration - expectedPenetration); +// if (fabsf(inaccuracy) > EPSILON) { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: bad penetration: expected = " << expectedPenetration +// << " actual = " << collision->_penetration << std::endl; +// } glm::vec3 expectedContactPoint = capsuleA.getTranslation() + radiusA * zAxis + shift * yAxis; - inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); - if (fabsf(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad contactPoint: expected = " << expectedContactPoint - << " actual = " << collision->_contactPoint << std::endl; - } + QFUZZY_COMPARE(collision->_contactPoint, expectedContactPoint, EPSILON); +// inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); +// if (fabsf(inaccuracy) > EPSILON) { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: bad contactPoint: expected = " << expectedContactPoint +// << " actual = " << collision->_contactPoint << std::endl; +// } } } @@ -578,8 +618,9 @@ void ShapeColliderTests::sphereMissesAACube() { float sphereRadius = 1.0f; glm::vec3 sphereCenter(0.0f); + + glm::vec3 cubeCenter(1.5f, 0.0f, 0.0f); - glm::vec3 cubeCenter(1.23f, 4.56f, 7.89f); float cubeSide = 2.0f; glm::vec3 faceNormals[] = {xAxis, yAxis, zAxis}; @@ -598,8 +639,10 @@ void ShapeColliderTests::sphereMissesAACube() { cubeCenter, cubeSide, collisions); if (collision) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should NOT collide with cube face." - << " faceNormal = " << faceNormal << std::endl; + QFAIL_WITH_MESSAGE("sphere should NOT collide with cube face.\n\t\t" + << "faceNormal = " << faceNormal); +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should NOT collide with cube face." +// << " faceNormal = " << faceNormal << std::endl; } } } @@ -638,8 +681,10 @@ void ShapeColliderTests::sphereMissesAACube() { cubeCenter, cubeSide, collisions); if (collision) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should NOT collide with cube edge." - << " edgeNormal = " << edgeNormal << std::endl; + QFAIL_WITH_MESSAGE("sphere should NOT collide with cube edge.\n\t\t" + << "edgeNormal = " << edgeNormal); +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should NOT collide with cube edge." +// << " edgeNormal = " << edgeNormal << std::endl; } } @@ -676,8 +721,11 @@ void ShapeColliderTests::sphereMissesAACube() { cubeCenter, cubeSide, collisions); if (collision) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should NOT collide with cube corner." - << " cornerNormal = " << cornerNormal << std::endl; + + QFAIL_WITH_MESSAGE("sphere should NOT collide with cube corner\n\t\t" << + "cornerNormal = " << cornerNormal); +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should NOT collide with cube corner." +// << "cornerNormal = " << cornerNormal << std::endl; break; } } @@ -724,29 +772,37 @@ void ShapeColliderTests::sphereTouchesAACubeFaces() { cubeCenter, cubeSide, collisions); if (!collision) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should collide outside cube face." - << " faceNormal = " << faceNormal - << std::endl; + + QFAIL_WITH_MESSAGE("sphere should collide outside cube face\n\t\t" << + "faceNormal = " << faceNormal); +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should collide outside cube face." +// << " faceNormal = " << faceNormal +// << std::endl; break; } - if (glm::distance(expectedPenetration, collision->_penetration) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: penetration = " << collision->_penetration - << " expected " << expectedPenetration << " faceNormal = " << faceNormal << std::endl; - } + QFUZZY_COMPARE(collision->_penetration, expectedPenetration, EPSILON); +// if (glm::distance(expectedPenetration, collision->_penetration) > EPSILON) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: penetration = " << collision->_penetration +// << " expected " << expectedPenetration << " faceNormal = " << faceNormal << std::endl; +// } + glm::vec3 expectedContact = sphereCenter - sphereRadius * faceNormal; - if (glm::distance(expectedContact, collision->_contactPoint) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: contactaPoint = " << collision->_contactPoint - << " expected " << expectedContact << " faceNormal = " << faceNormal << std::endl; - } + QFUZZY_COMPARE(collision->_contactPoint, expectedContact, EPSILON); +// if (glm::distance(expectedContact, collision->_contactPoint) > EPSILON) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: contactaPoint = " << collision->_contactPoint +// << " expected " << expectedContact << " faceNormal = " << faceNormal << std::endl; +// } - if (collision->getShapeA()) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: collision->_shapeA should be NULL" << std::endl; - } - if (collision->getShapeB()) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: collision->_shapeB should be NULL" << std::endl; - } + QCOMPARE(collision->getShapeA(), (Shape*)nullptr); +// if (collision->getShapeA()) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: collision->_shapeA should be NULL" << std::endl; +// } + QCOMPARE(collision->getShapeB(), (Shape*)nullptr); +// if (collision->getShapeB()) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: collision->_shapeB should be NULL" << std::endl; +// } } } @@ -761,22 +817,26 @@ void ShapeColliderTests::sphereTouchesAACubeFaces() { cubeCenter, cubeSide, collisions); if (!collision) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should collide inside cube face." - << " faceNormal = " << faceNormal << std::endl; + QFAIL_WITH_MESSAGE("sphere should collide inside cube face.\n\t\t" + << "faceNormal = " << faceNormal); +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should collide inside cube face." +// << " faceNormal = " << faceNormal << std::endl; break; } glm::vec3 expectedPenetration = - overlap * faceNormal; - if (glm::distance(expectedPenetration, collision->_penetration) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: penetration = " << collision->_penetration - << " expected " << expectedPenetration << " faceNormal = " << faceNormal << std::endl; - } + QFUZZY_COMPARE(collision->_penetration, expectedPenetration, EPSILON); +// if (glm::distance(expectedPenetration, collision->_penetration) > EPSILON) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: penetration = " << collision->_penetration +// << " expected " << expectedPenetration << " faceNormal = " << faceNormal << std::endl; +// } glm::vec3 expectedContact = sphereCenter - sphereRadius * faceNormal; - if (glm::distance(expectedContact, collision->_contactPoint) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: contactaPoint = " << collision->_contactPoint - << " expected " << expectedContact << " faceNormal = " << faceNormal << std::endl; - } + QFUZZY_COMPARE(collision->_contactPoint, expectedContact, EPSILON); +// if (glm::distance(expectedContact, collision->_contactPoint) > EPSILON) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: contactaPoint = " << collision->_contactPoint +// << " expected " << expectedContact << " faceNormal = " << faceNormal << std::endl; +// } } } } @@ -831,21 +891,24 @@ void ShapeColliderTests::sphereTouchesAACubeEdges() { cubeCenter, cubeSide, collisions); if (!collision) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should collide with cube edge." - << " edgeNormal = " << edgeNormal << std::endl; + QFAIL_WITH_MESSAGE("sphere should collide with cube edge.\n\t\t" + << "edgeNormal = " << edgeNormal); +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should collide with cube edge." +// << " edgeNormal = " << edgeNormal << std::endl; break; } - - if (glm::distance(expectedPenetration, collision->_penetration) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: penetration = " << collision->_penetration - << " expected " << expectedPenetration << " edgeNormal = " << edgeNormal << std::endl; - } + QFUZZY_COMPARE(collision->_penetration, expectedPenetration, EPSILON); +// if (glm::distance(expectedPenetration, collision->_penetration) > EPSILON) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: penetration = " << collision->_penetration +// << " expected " << expectedPenetration << " edgeNormal = " << edgeNormal << std::endl; +// } glm::vec3 expectedContact = sphereCenter - sphereRadius * edgeNormal; - if (glm::distance(expectedContact, collision->_contactPoint) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: contactaPoint = " << collision->_contactPoint - << " expected " << expectedContact << " edgeNormal = " << edgeNormal << std::endl; - } + QFUZZY_COMPARE(collision->_contactPoint, expectedContact, EPSILON); +// if (glm::distance(expectedContact, collision->_contactPoint) > EPSILON) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: contactaPoint = " << collision->_contactPoint +// << " expected " << expectedContact << " edgeNormal = " << edgeNormal << std::endl; +// } } } } @@ -894,22 +957,24 @@ void ShapeColliderTests::sphereTouchesAACubeCorners() { cubeCenter, cubeSide, collisions); if (!collision) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should collide with cube corner." - << " cornerNormal = " << cornerNormal << std::endl; + QFAIL_WITH_MESSAGE("sphere should collide with cube corner.\n\t\t" + << "cornerNormal = " << cornerNormal); break; } glm::vec3 expectedPenetration = - overlap * offsetAxis; - if (glm::distance(expectedPenetration, collision->_penetration) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: penetration = " << collision->_penetration - << " expected " << expectedPenetration << " cornerNormal = " << cornerNormal << std::endl; - } + QFUZZY_COMPARE(collision->_penetration, expectedPenetration, EPSILON); +// if (glm::distance(expectedPenetration, collision->_penetration) > EPSILON) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: penetration = " << collision->_penetration +// << " expected " << expectedPenetration << " cornerNormal = " << cornerNormal << std::endl; +// } glm::vec3 expectedContact = sphereCenter - sphereRadius * offsetAxis; - if (glm::distance(expectedContact, collision->_contactPoint) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: contactaPoint = " << collision->_contactPoint - << " expected " << expectedContact << " cornerNormal = " << cornerNormal << std::endl; - } + QFUZZY_COMPARE(collision->_contactPoint, expectedContact, EPSILON); +// if (glm::distance(expectedContact, collision->_contactPoint) > EPSILON) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: contactaPoint = " << collision->_contactPoint +// << " expected " << expectedContact << " cornerNormal = " << cornerNormal << std::endl; +// } } } } @@ -958,10 +1023,11 @@ void ShapeColliderTests::capsuleMissesAACube() { CapsuleShape capsule(capsuleRadius, startPoint, endPoint); // collide capsule with cube - if (ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should NOT collide with cube face." - << " faceNormal = " << faceNormal << std::endl; - } + QCOMPARE(ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions), false); +// if (ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should NOT collide with cube face." +// << " faceNormal = " << faceNormal << std::endl; +// } } } @@ -1007,11 +1073,11 @@ void ShapeColliderTests::capsuleMissesAACube() { CapsuleShape capsule(capsuleRadius, startPoint, endPoint); // collide capsule with cube - bool hit = ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions); - if (hit) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should NOT collide with cube face." - << " edgeNormal = " << edgeNormal << std::endl; - } + QCOMPARE(ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions), false); +// if (hit) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should NOT collide with cube face." +// << " edgeNormal = " << edgeNormal << std::endl; +// } } } } @@ -1049,10 +1115,11 @@ void ShapeColliderTests::capsuleMissesAACube() { CapsuleShape capsule(capsuleRadius, startPoint, endPoint); // collide capsule with cube - if (ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should NOT collide with cube face." - << " cornerNormal = " << cornerNormal << std::endl; - } + QCOMPARE(ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions), false); +// if (ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should NOT collide with cube face." +// << " cornerNormal = " << cornerNormal << std::endl; +// } } } } @@ -1104,10 +1171,11 @@ void ShapeColliderTests::capsuleMissesAACube() { CapsuleShape capsule(capsuleRadius, startPoint, endPoint); // collide capsule with cube - if (ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should NOT collide with cube" - << " edgeNormal = " << edgeNormal << std::endl; - } + QCOMPARE(ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions), false); +// if (ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should NOT collide with cube" +// << " edgeNormal = " << edgeNormal << std::endl; +// } } } } @@ -1153,10 +1221,11 @@ void ShapeColliderTests::capsuleMissesAACube() { CapsuleShape capsule(capsuleRadius, startPoint, endPoint); // collide capsule with cube - if (ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should NOT collide with cube" - << " cornerNormal = " << cornerNormal << std::endl; - } + QCOMPARE(ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions), false); +// if (ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should NOT collide with cube" +// << " cornerNormal = " << cornerNormal << std::endl; +// } } } } @@ -1189,11 +1258,12 @@ void ShapeColliderTests::capsuleMissesAACube() { CapsuleShape capsule(capsuleRadius, startPoint, endPoint); // collide capsule with cube - if (ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should NOT collide with cube" - << " faceNormal = " << faceNormal << std::endl; - break; - } + QCOMPARE(ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions), false); +// if (ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should NOT collide with cube" +// << " faceNormal = " << faceNormal << std::endl; +// break; +// } } } } @@ -1245,40 +1315,44 @@ void ShapeColliderTests::capsuleTouchesAACube() { CapsuleShape capsule(capsuleRadius, startPoint, endPoint); // collide capsule with cube - if (!ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should collide with cube" - << " faceNormal = " << faceNormal << std::endl; - break; - } + QCOMPARE(ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions), true); +// if (!ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should collide with cube" +// << " faceNormal = " << faceNormal << std::endl; +// break; +// } CollisionInfo* collision = collisions.getLastCollision(); - if (!collision) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: null collision with faceNormal = " << faceNormal << std::endl; - return; - } + QCOMPARE(collision != nullptr, true); +// if (!collision) { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: null collision with faceNormal = " << faceNormal << std::endl; +// return; +// } // penetration points from capsule into cube glm::vec3 expectedPenetration = - overlap * faceNormal; - float inaccuracy = glm::length(collision->_penetration - expectedPenetration); - if (fabsf(inaccuracy) > allowableError) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad penetration: expected = " << expectedPenetration - << " actual = " << collision->_penetration - << " faceNormal = " << faceNormal - << std::endl; - } + QFUZZY_COMPARE(collision->_penetration, expectedPenetration, allowableError); +// float inaccuracy = glm::length(collision->_penetration - expectedPenetration); +// if (fabsf(inaccuracy) > allowableError) { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: bad penetration: expected = " << expectedPenetration +// << " actual = " << collision->_penetration +// << " faceNormal = " << faceNormal +// << std::endl; +// } // contactPoint is on surface of capsule glm::vec3 expectedContactPoint = collidingPoint - capsuleRadius * faceNormal; - inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); - if (fabsf(inaccuracy) > allowableError) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad contactPoint: expected = " << expectedContactPoint - << " actual = " << collision->_contactPoint - << " faceNormal = " << faceNormal - << std::endl; - } + QFUZZY_COMPARE(collision->_contactPoint, expectedContactPoint, allowableError); +// inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); +// if (fabsf(inaccuracy) > allowableError) { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: bad contactPoint: expected = " << expectedContactPoint +// << " actual = " << collision->_contactPoint +// << " faceNormal = " << faceNormal +// << std::endl; +// } } } @@ -1325,39 +1399,43 @@ void ShapeColliderTests::capsuleTouchesAACube() { CapsuleShape capsule(capsuleRadius, startPoint, endPoint); // collide capsule with cube - if (!ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should collide with cube" - << " edgeNormal = " << edgeNormal << std::endl; - } + QCOMPARE(ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions), true); +// if (!ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should collide with cube" +// << " edgeNormal = " << edgeNormal << std::endl; +// } CollisionInfo* collision = collisions.getLastCollision(); - if (!collision) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: null collision with edgeNormal = " << edgeNormal << std::endl; - return; - } + QCOMPARE(collision != nullptr, true); +// if (!collision) { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: null collision with edgeNormal = " << edgeNormal << std::endl; +// return; +// } // penetration points from capsule into cube glm::vec3 expectedPenetration = - overlap * edgeNormal; - float inaccuracy = glm::length(collision->_penetration - expectedPenetration); - if (fabsf(inaccuracy) > allowableError) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad penetration: expected = " << expectedPenetration - << " actual = " << collision->_penetration - << " edgeNormal = " << edgeNormal - << std::endl; - } + QFUZZY_COMPARE(collision->_penetration, expectedPenetration, allowableError); +// float inaccuracy = glm::length(collision->_penetration - expectedPenetration); +// if (fabsf(inaccuracy) > allowableError) { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: bad penetration: expected = " << expectedPenetration +// << " actual = " << collision->_penetration +// << " edgeNormal = " << edgeNormal +// << std::endl; +// } // contactPoint is on surface of capsule glm::vec3 expectedContactPoint = collidingPoint - capsuleRadius * edgeNormal; - inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); - if (fabsf(inaccuracy) > allowableError) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad contactPoint: expected = " << expectedContactPoint - << " actual = " << collision->_contactPoint - << " edgeNormal = " << edgeNormal - << std::endl; - } + QFUZZY_COMPARE(collision->_contactPoint, expectedContactPoint, allowableError); +// inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); +// if (fabsf(inaccuracy) > allowableError) { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: bad contactPoint: expected = " << expectedContactPoint +// << " actual = " << collision->_contactPoint +// << " edgeNormal = " << edgeNormal +// << std::endl; +// } } } } @@ -1396,39 +1474,43 @@ void ShapeColliderTests::capsuleTouchesAACube() { CapsuleShape capsule(capsuleRadius, startPoint, endPoint); // collide capsule with cube - if (!ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should collide with cube" - << " cornerNormal = " << cornerNormal << std::endl; - } + QCOMPARE(ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions), true); +// if (!ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should collide with cube" +// << " cornerNormal = " << cornerNormal << std::endl; +// } CollisionInfo* collision = collisions.getLastCollision(); - if (!collision) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: null collision with cornerNormal = " << cornerNormal << std::endl; - return; - } + QCOMPARE(collision != nullptr, true); +// if (!collision) { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: null collision with cornerNormal = " << cornerNormal << std::endl; +// return; +// } // penetration points from capsule into cube glm::vec3 expectedPenetration = - overlap * cornerNormal; - float inaccuracy = glm::length(collision->_penetration - expectedPenetration); - if (fabsf(inaccuracy) > allowableError) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad penetration: expected = " << expectedPenetration - << " actual = " << collision->_penetration - << " cornerNormal = " << cornerNormal - << std::endl; - } + QFUZZY_COMPARE(collision->_penetration, expectedPenetration, allowableError); +// float inaccuracy = glm::length(collision->_penetration - expectedPenetration); +// if (fabsf(inaccuracy) > allowableError) { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: bad penetration: expected = " << expectedPenetration +// << " actual = " << collision->_penetration +// << " cornerNormal = " << cornerNormal +// << std::endl; +// } // contactPoint is on surface of capsule glm::vec3 expectedContactPoint = collidingPoint - capsuleRadius * cornerNormal; - inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); - if (fabsf(inaccuracy) > allowableError) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad contactPoint: expected = " << expectedContactPoint - << " actual = " << collision->_contactPoint - << " cornerNormal = " << cornerNormal - << std::endl; - } + QFUZZY_COMPARE(collision->_contactPoint, expectedContactPoint, allowableError); +// inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); +// if (fabsf(inaccuracy) > allowableError) { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: bad contactPoint: expected = " << expectedContactPoint +// << " actual = " << collision->_contactPoint +// << " cornerNormal = " << cornerNormal +// << std::endl; +// } } } } @@ -1480,39 +1562,43 @@ void ShapeColliderTests::capsuleTouchesAACube() { CapsuleShape capsule(capsuleRadius, startPoint, endPoint); // collide capsule with cube - if (!ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should collide with cube" - << " edgeNormal = " << edgeNormal << std::endl; - } + QCOMPARE(ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions), true); +// if (!ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should collide with cube" +// << " edgeNormal = " << edgeNormal << std::endl; +// } CollisionInfo* collision = collisions.getLastCollision(); - if (!collision) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: null collision with edgeNormal = " << edgeNormal << std::endl; - return; - } + QCOMPARE(collision != nullptr, true); +// if (!collision) { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: null collision with edgeNormal = " << edgeNormal << std::endl; +// return; +// } // penetration points from capsule into cube glm::vec3 expectedPenetration = - overlap * deflectedNormal; - float inaccuracy = glm::length(collision->_penetration - expectedPenetration); - if (fabsf(inaccuracy) > allowableError / capsuleLength) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad penetration: expected = " << expectedPenetration - << " actual = " << collision->_penetration - << " edgeNormal = " << edgeNormal - << std::endl; - } + QFUZZY_COMPARE(collision->_penetration, expectedPenetration, allowableError); +// float inaccuracy = glm::length(collision->_penetration - expectedPenetration); +// if (fabsf(inaccuracy) > allowableError / capsuleLength) { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: bad penetration: expected = " << expectedPenetration +// << " actual = " << collision->_penetration +// << " edgeNormal = " << edgeNormal +// << std::endl; +// } // contactPoint is on surface of capsule glm::vec3 expectedContactPoint = axisPoint - capsuleRadius * deflectedNormal; - inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); - if (fabsf(inaccuracy) > allowableError / capsuleLength) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad contactPoint: expected = " << expectedContactPoint - << " actual = " << collision->_contactPoint - << " edgeNormal = " << edgeNormal - << std::endl; - } + QFUZZY_COMPARE(collision->_contactPoint, expectedContactPoint, allowableError); +// inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); +// if (fabsf(inaccuracy) > allowableError / capsuleLength) { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: bad contactPoint: expected = " << expectedContactPoint +// << " actual = " << collision->_contactPoint +// << " edgeNormal = " << edgeNormal +// << std::endl; +// } } } } @@ -1559,39 +1645,43 @@ void ShapeColliderTests::capsuleTouchesAACube() { CapsuleShape capsule(capsuleRadius, startPoint, endPoint); // collide capsule with cube - if (!ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should collide with cube" - << " cornerNormal = " << cornerNormal << std::endl; - } + QCOMPARE(ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions), true); +// if (!ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should collide with cube" +// << " cornerNormal = " << cornerNormal << std::endl; +// } CollisionInfo* collision = collisions.getLastCollision(); - if (!collision) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: null collision with cornerNormal = " << cornerNormal << std::endl; - return; - } + QCOMPARE(collision != nullptr, true); +// if (!collision) { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: null collision with cornerNormal = " << cornerNormal << std::endl; +// return; +// } // penetration points from capsule into cube glm::vec3 expectedPenetration = overlap * penetrationNormal; - float inaccuracy = glm::length(collision->_penetration - expectedPenetration); - if (fabsf(inaccuracy) > allowableError) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad penetration: expected = " << expectedPenetration - << " actual = " << collision->_penetration - << " cornerNormal = " << cornerNormal - << std::endl; - } + QFUZZY_COMPARE(collision->_penetration, expectedPenetration, allowableError); +// float inaccuracy = glm::length(collision->_penetration - expectedPenetration); +// if (fabsf(inaccuracy) > allowableError) { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: bad penetration: expected = " << expectedPenetration +// << " actual = " << collision->_penetration +// << " cornerNormal = " << cornerNormal +// << std::endl; +// } // contactPoint is on surface of capsule glm::vec3 expectedContactPoint = collidingPoint + capsuleRadius * penetrationNormal; - inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); - if (fabsf(inaccuracy) > allowableError) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad contactPoint: expected = " << expectedContactPoint - << " actual = " << collision->_contactPoint - << " cornerNormal = " << cornerNormal - << std::endl; - } + QFUZZY_COMPARE(collision->_contactPoint, expectedContactPoint, allowableError); +// inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); +// if (fabsf(inaccuracy) > allowableError) { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: bad contactPoint: expected = " << expectedContactPoint +// << " actual = " << collision->_contactPoint +// << " cornerNormal = " << cornerNormal +// << std::endl; +// } } } } @@ -1624,20 +1714,22 @@ void ShapeColliderTests::capsuleTouchesAACube() { CapsuleShape capsule(capsuleRadius, startPoint, endPoint); // collide capsule with cube - if (!ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should collide with cube" - << " faceNormal = " << faceNormal << std::endl; - break; - } + QCOMPARE(ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions), true); +// if (!ShapeCollider::capsuleVsAACube(&capsule, &cube, collisions)) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule should collide with cube" +// << " faceNormal = " << faceNormal << std::endl; +// break; +// } - int numCollisions = collisions.size(); - if (numCollisions != 2) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: capsule should hit cube face at two spots." - << " Expected collisions size of 2 but is actually " << numCollisions - << ". faceNormal = " << faceNormal << std::endl; - break; - } + QCOMPARE(collisions.size(), 2); +// int numCollisions = collisions.size(); +// if (numCollisions != 2) { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: capsule should hit cube face at two spots." +// << " Expected collisions size of 2 but is actually " << numCollisions +// << ". faceNormal = " << faceNormal << std::endl; +// break; +// } // compute the expected contact points // NOTE: whether the startPoint or endPoint are expected to collide depends the relative values @@ -1662,14 +1754,15 @@ void ShapeColliderTests::capsuleTouchesAACube() { CollisionInfo* collision = collisions.getCollision(k); // penetration points from capsule into cube glm::vec3 expectedPenetration = - overlap * faceNormal; - float inaccuracy = glm::length(collision->_penetration - expectedPenetration); - if (fabsf(inaccuracy) > allowableError) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad penetration: expected = " << expectedPenetration - << " actual = " << collision->_penetration - << " faceNormal = " << faceNormal - << std::endl; - } + QFUZZY_COMPARE(collision->_penetration, expectedPenetration, allowableError); +// float inaccuracy = glm::length(collision->_penetration - expectedPenetration); +// if (fabsf(inaccuracy) > allowableError) { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: bad penetration: expected = " << expectedPenetration +// << " actual = " << collision->_penetration +// << " faceNormal = " << faceNormal +// << std::endl; +// } // the order of the final contact points is undefined, so we // figure out which expected contact point is the closest to the real one @@ -1678,14 +1771,15 @@ void ShapeColliderTests::capsuleTouchesAACube() { float length1 = glm::length(collision->_contactPoint - expectedContactPoints[1]); glm::vec3 expectedContactPoint = (length0 < length1) ? expectedContactPoints[0] : expectedContactPoints[1]; // contactPoint is on surface of capsule - inaccuracy = (length0 < length1) ? length0 : length1; - if (fabsf(inaccuracy) > allowableError) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad contact: expectedContactPoint[" << k << "] = " << expectedContactPoint - << " actual = " << collision->_contactPoint - << " faceNormal = " << faceNormal - << std::endl; - } + QFUZZY_COMPARE(collision->_contactPoint, expectedContactPoint, allowableError); +// inaccuracy = (length0 < length1) ? length0 : length1; +// if (fabsf(inaccuracy) > allowableError) { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: bad contact: expectedContactPoint[" << k << "] = " << expectedContactPoint +// << " actual = " << collision->_contactPoint +// << " faceNormal = " << faceNormal +// << std::endl; +// } } } } @@ -1706,19 +1800,22 @@ void ShapeColliderTests::rayHitsSphere() { intersection._rayStart = -startDistance * xAxis; intersection._rayDirection = xAxis; - if (!sphere.findRayIntersection(intersection)) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should intersect sphere" << std::endl; - } - + QCOMPARE(sphere.findRayIntersection(intersection), true); +// if (!sphere.findRayIntersection(intersection)) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should intersect sphere" << std::endl; +// } + float expectedDistance = startDistance - radius; - float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; - if (relativeError > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray sphere intersection distance error = " << relativeError << std::endl; - } - if (intersection._hitShape != &sphere) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray intersection._hitShape should point at sphere" - << std::endl; - } + QFUZZY_COMPARE(intersection._hitDistance, expectedDistance, startDistance * EPSILON); +// float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; +// if (relativeError > EPSILON) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray sphere intersection distance error = " << relativeError << std::endl; +// } + QCOMPARE(intersection._hitShape, &sphere); +// if (intersection._hitShape != &sphere) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray intersection._hitShape should point at sphere" +// << std::endl; +// } } // ray along a diagonal axis @@ -1726,16 +1823,17 @@ void ShapeColliderTests::rayHitsSphere() { RayIntersectionInfo intersection; intersection._rayStart = glm::vec3(startDistance, startDistance, 0.0f); intersection._rayDirection = - glm::normalize(intersection._rayStart); - - if (!sphere.findRayIntersection(intersection)) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should intersect sphere" << std::endl; - } + QCOMPARE(sphere.findRayIntersection(intersection), true); +// if (!sphere.findRayIntersection(intersection)) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should intersect sphere" << std::endl; +// } float expectedDistance = SQUARE_ROOT_OF_2 * startDistance - radius; - float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; - if (relativeError > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray sphere intersection distance error = " << relativeError << std::endl; - } + QFUZZY_COMPARE(intersection._hitDistance, expectedDistance, startDistance * EPSILON); +// float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; +// if (relativeError > EPSILON) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray sphere intersection distance error = " << relativeError << std::endl; +// } } // rotated and displaced ray and sphere @@ -1757,16 +1855,18 @@ void ShapeColliderTests::rayHitsSphere() { sphere.setRadius(radius); sphere.setTranslation(rotation * translation); - if (!sphere.findRayIntersection(intersection)) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should intersect sphere" << std::endl; - } + QCOMPARE(sphere.findRayIntersection(intersection), true); +// if (!sphere.findRayIntersection(intersection)) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should intersect sphere" << std::endl; +// } float expectedDistance = startDistance - radius; - float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; - if (relativeError > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray sphere intersection distance error = " - << relativeError << std::endl; - } + QFUZZY_COMPARE(intersection._hitDistance, expectedDistance, startDistance * EPSILON); +// float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; +// if (relativeError > EPSILON) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray sphere intersection distance error = " +// << relativeError << std::endl; +// } } } @@ -1784,13 +1884,15 @@ void ShapeColliderTests::rayBarelyHitsSphere() { intersection._rayDirection = xAxis; // very simple ray along xAxis - if (!sphere.findRayIntersection(intersection)) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should just barely hit sphere" << std::endl; - } - if (intersection._hitShape != &sphere) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray intersection._hitShape should point at sphere" - << std::endl; - } + QCOMPARE(sphere.findRayIntersection(intersection), true); +// if (!sphere.findRayIntersection(intersection)) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should just barely hit sphere" << std::endl; +// } + QCOMPARE(intersection._hitShape, &sphere); +// if (intersection._hitShape != &sphere) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray intersection._hitShape should point at sphere" +// << std::endl; +// } } { @@ -1806,9 +1908,10 @@ void ShapeColliderTests::rayBarelyHitsSphere() { sphere.setTranslation(rotation * translation); // ...and test again - if (!sphere.findRayIntersection(intersection)) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should just barely hit sphere" << std::endl; - } + QCOMPARE(sphere.findRayIntersection(intersection), true); +// if (!sphere.findRayIntersection(intersection)) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should just barely hit sphere" << std::endl; +// } } } @@ -1828,13 +1931,15 @@ void ShapeColliderTests::rayBarelyMissesSphere() { intersection._rayDirection = xAxis; // very simple ray along xAxis - if (sphere.findRayIntersection(intersection)) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should just barely miss sphere" << std::endl; - } - if (intersection._hitDistance != FLT_MAX) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: distance should be unchanged after intersection miss" - << std::endl; - } + QCOMPARE(sphere.findRayIntersection(intersection), true); +// if (sphere.findRayIntersection(intersection)) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should just barely miss sphere" << std::endl; +// } + QCOMPARE(intersection._hitDistance, FLT_MAX); +// if (intersection._hitDistance != FLT_MAX) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: distance should be unchanged after intersection miss" +// << std::endl; +// } } { @@ -1850,16 +1955,19 @@ void ShapeColliderTests::rayBarelyMissesSphere() { sphere.setTranslation(rotation * translation); // ...and test again - if (sphere.findRayIntersection(intersection)) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should just barely miss sphere" << std::endl; - } - if (intersection._hitDistance != FLT_MAX) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: distance should be unchanged after intersection miss" - << std::endl; - } - if (intersection._hitShape != NULL) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray intersection._hitShape should be NULL" << std::endl; - } + QCOMPARE(sphere.findRayIntersection(intersection), false); +// if (sphere.findRayIntersection(intersection)) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should just barely miss sphere" << std::endl; +// } + QCOMPARE(intersection._hitDistance != FLT_MAX, true); +// if (intersection._hitDistance != FLT_MAX) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: distance should be unchanged after intersection miss" +// << std::endl; +// } + QCOMPARE(intersection._hitShape == nullptr, true); +// if (intersection._hitShape != NULL) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray intersection._hitShape should be NULL" << std::endl; +// } } } @@ -1875,34 +1983,39 @@ void ShapeColliderTests::rayHitsCapsule() { RayIntersectionInfo intersection; intersection._rayStart = glm::vec3(startDistance, 0.0f, 0.0f); intersection._rayDirection = - xAxis; - if (!capsule.findRayIntersection(intersection)) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should hit capsule" << std::endl; - } + QCOMPARE(capsule.findRayIntersection(intersection), true); +// if (!capsule.findRayIntersection(intersection)) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should hit capsule" << std::endl; +// } float expectedDistance = startDistance - radius; - float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; - if (relativeError > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray capsule intersection distance error = " - << relativeError << std::endl; - } - if (intersection._hitShape != &capsule) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray intersection._hitShape should point at capsule" - << std::endl; - } + QFUZZY_COMPARE(intersection._hitDistance, expectedDistance, startDistance * EPSILON); +// float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; +// if (relativeError > EPSILON) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray capsule intersection distance error = " +// << relativeError << std::endl; +// } + QCOMPARE(intersection._hitShape, &capsule); +// if (intersection._hitShape != &capsule) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray intersection._hitShape should point at capsule" +// << std::endl; +// } } { // toward top of cylindrical wall RayIntersectionInfo intersection; intersection._rayStart = glm::vec3(startDistance, halfHeight, 0.0f); intersection._rayDirection = - xAxis; - if (!capsule.findRayIntersection(intersection)) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should hit capsule" << std::endl; - } + QCOMPARE(capsule.findRayIntersection(intersection), true); +// if (!capsule.findRayIntersection(intersection)) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should hit capsule" << std::endl; +// } float expectedDistance = startDistance - radius; - float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; - if (relativeError > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray capsule intersection distance error = " - << relativeError << std::endl; - } + QFUZZY_COMPARE(intersection._hitDistance, expectedDistance, startDistance * EPSILON); +// float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; +// if (relativeError > EPSILON) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray capsule intersection distance error = " +// << relativeError << std::endl; +// } } float delta = 2.0f * EPSILON; @@ -1910,15 +2023,17 @@ void ShapeColliderTests::rayHitsCapsule() { RayIntersectionInfo intersection; intersection._rayStart = glm::vec3(startDistance, halfHeight + delta, 0.0f); intersection._rayDirection = - xAxis; - if (!capsule.findRayIntersection(intersection)) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should hit capsule" << std::endl; - } + QCOMPARE(capsule.findRayIntersection(intersection), true); +// if (!capsule.findRayIntersection(intersection)) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should hit capsule" << std::endl; +// } float expectedDistance = startDistance - radius; - float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; - if (relativeError > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray capsule intersection distance error = " - << relativeError << std::endl; - } + QFUZZY_COMPARE(intersection._hitDistance, expectedDistance, startDistance * EPSILON); +// float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; +// if (relativeError > EPSILON) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray capsule intersection distance error = " +// << relativeError << std::endl; +// } } const float EDGE_CASE_SLOP_FACTOR = 20.0f; @@ -1926,48 +2041,54 @@ void ShapeColliderTests::rayHitsCapsule() { RayIntersectionInfo intersection; intersection._rayStart = glm::vec3(startDistance, halfHeight + radius - delta, 0.0f); intersection._rayDirection = - xAxis; - if (!capsule.findRayIntersection(intersection)) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should hit capsule" << std::endl; - } + QCOMPARE(capsule.findRayIntersection(intersection), true); +// if (!capsule.findRayIntersection(intersection)) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should hit capsule" << std::endl; +// } float expectedDistance = startDistance - radius * sqrtf(2.0f * delta); // using small angle approximation of cosine - float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; +// float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; // for edge cases we allow a LOT of error - if (relativeError > EDGE_CASE_SLOP_FACTOR * EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray capsule intersection distance error = " - << relativeError << std::endl; - } + QFUZZY_COMPARE(intersection._hitDistance, expectedDistance, startDistance * EDGE_CASE_SLOP_FACTOR * EPSILON); +// if (relativeError > EDGE_CASE_SLOP_FACTOR * EPSILON) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray capsule intersection distance error = " +// << relativeError << std::endl; +// } } { // toward tip of bottom cap RayIntersectionInfo intersection; intersection._rayStart = glm::vec3(startDistance, - halfHeight - radius + delta, 0.0f); intersection._rayDirection = - xAxis; - if (!capsule.findRayIntersection(intersection)) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should hit capsule" << std::endl; - } + QCOMPARE(capsule.findRayIntersection(intersection), true); +// if (!capsule.findRayIntersection(intersection)) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should hit capsule" << std::endl; +// } float expectedDistance = startDistance - radius * sqrtf(2.0f * delta); // using small angle approximation of cosine - float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; +// float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; // for edge cases we allow a LOT of error - if (relativeError > EDGE_CASE_SLOP_FACTOR * EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray capsule intersection distance error = " - << relativeError << std::endl; - } + QFUZZY_COMPARE(intersection._hitDistance, expectedDistance, startDistance * EPSILON * EDGE_CASE_SLOP_FACTOR); +// if (relativeError > EDGE_CASE_SLOP_FACTOR * EPSILON) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray capsule intersection distance error = " +// << relativeError << std::endl; +// } } { // toward edge of capsule cylindrical face RayIntersectionInfo intersection; intersection._rayStart = glm::vec3(startDistance, 0.0f, radius - delta); intersection._rayDirection = - xAxis; - if (!capsule.findRayIntersection(intersection)) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should hit capsule" << std::endl; - } + QCOMPARE(capsule.findRayIntersection(intersection), true); +// if (!capsule.findRayIntersection(intersection)) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should hit capsule" << std::endl; +// } float expectedDistance = startDistance - radius * sqrtf(2.0f * delta); // using small angle approximation of cosine float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; // for edge cases we allow a LOT of error - if (relativeError > EDGE_CASE_SLOP_FACTOR * EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray capsule intersection distance error = " - << relativeError << std::endl; - } + QFUZZY_COMPARE(intersection._hitDistance, expectedDistance, startDistance * EPSILON * EDGE_CASE_SLOP_FACTOR); +// if (relativeError > EDGE_CASE_SLOP_FACTOR * EPSILON) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray capsule intersection distance error = " +// << relativeError << std::endl; +// } } // TODO: test at steep angles near cylinder/cap junction } @@ -1990,39 +2111,46 @@ void ShapeColliderTests::rayMissesCapsule() { // over top cap intersection._rayStart.y = halfHeight + radius + delta; intersection._hitDistance = FLT_MAX; - if (capsule.findRayIntersection(intersection)) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should miss capsule" << std::endl; - } - if (intersection._hitDistance != FLT_MAX) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: distance should be unchanged after intersection miss" - << std::endl; - } + QCOMPARE(capsule.findRayIntersection(intersection), false); +// if (capsule.findRayIntersection(intersection)) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should miss capsule" << std::endl; +// } + QCOMPARE(intersection._hitDistance, FLT_MAX); +// if (intersection._hitDistance != FLT_MAX) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: distance should be unchanged after intersection miss" +// << std::endl; +// } // below bottom cap intersection._rayStart.y = - halfHeight - radius - delta; intersection._hitDistance = FLT_MAX; - if (capsule.findRayIntersection(intersection)) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should miss capsule" << std::endl; - } - if (intersection._hitDistance != FLT_MAX) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: distance should be unchanged after intersection miss" - << std::endl; - } + QCOMPARE(capsule.findRayIntersection(intersection), false); +// if (capsule.findRayIntersection(intersection)) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should miss capsule" << std::endl; +// } + QCOMPARE(intersection._hitDistance, FLT_MAX); +// if (intersection._hitDistance != FLT_MAX) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: distance should be unchanged after intersection miss" +// << std::endl; +// } // past edge of capsule cylindrical face intersection._rayStart.y = 0.0f; intersection._rayStart.z = radius + delta; intersection._hitDistance = FLT_MAX; - if (capsule.findRayIntersection(intersection)) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should miss capsule" << std::endl; - } - if (intersection._hitDistance != FLT_MAX) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: distance should be unchanged after intersection miss" - << std::endl; - } - if (intersection._hitShape != NULL) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray intersection._hitShape should be NULL" << std::endl; - } + QCOMPARE(capsule.findRayIntersection(intersection), false); +// if (capsule.findRayIntersection(intersection)) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should miss capsule" << std::endl; +// } + QCOMPARE(intersection._hitDistance, FLT_MAX); +// if (intersection._hitDistance != FLT_MAX) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: distance should be unchanged after intersection miss" +// << std::endl; +// } + QCOMPARE(intersection._hitShape, (Shape*)nullptr); +// if (intersection._hitShape != NULL) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray intersection._hitShape should be NULL" << std::endl; +// } } // TODO: test at steep angles near edge } @@ -2042,20 +2170,24 @@ void ShapeColliderTests::rayHitsPlane() { intersection._rayStart = -startDistance * xAxis; intersection._rayDirection = glm::normalize(glm::vec3(1.0f, 1.0f, 1.0f)); - if (!plane.findRayIntersection(intersection)) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should hit plane" << std::endl; - } + QCOMPARE(plane.findRayIntersection(intersection), true); +// if (!plane.findRayIntersection(intersection)) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should hit plane" << std::endl; +// } float expectedDistance = SQUARE_ROOT_OF_3 * planeDistanceFromOrigin; - float relativeError = fabsf(intersection._hitDistance - expectedDistance) / planeDistanceFromOrigin; - if (relativeError > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray plane intersection distance error = " - << relativeError << std::endl; - } - if (intersection._hitShape != &plane) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray intersection._hitShape should point at plane" - << std::endl; - } + + QFUZZY_COMPARE(intersection._hitDistance, expectedDistance, planeDistanceFromOrigin * EPSILON); +// float relativeError = fabsf(intersection._hitDistance - expectedDistance) / planeDistanceFromOrigin; +// if (relativeError > EPSILON) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray plane intersection distance error = " +// << relativeError << std::endl; +// } + QCOMPARE(intersection._hitShape, &plane); +// if (intersection._hitShape != &plane) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray intersection._hitShape should point at plane" +// << std::endl; +// } } { // rotate the whole system and try again @@ -2069,16 +2201,18 @@ void ShapeColliderTests::rayHitsPlane() { intersection._rayStart = rotation * (-startDistance * xAxis); intersection._rayDirection = rotation * glm::normalize(glm::vec3(1.0f, 1.0f, 1.0f)); - if (!plane.findRayIntersection(intersection)) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should hit plane" << std::endl; - } + QCOMPARE(plane.findRayIntersection(intersection), true); +// if (!plane.findRayIntersection(intersection)) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should hit plane" << std::endl; +// } float expectedDistance = SQUARE_ROOT_OF_3 * planeDistanceFromOrigin; - float relativeError = fabsf(intersection._hitDistance - expectedDistance) / planeDistanceFromOrigin; - if (relativeError > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray plane intersection distance error = " - << relativeError << std::endl; - } + QFUZZY_COMPARE(intersection._hitDistance, expectedDistance, planeDistanceFromOrigin * EPSILON); +// float relativeError = fabsf(intersection._hitDistance - expectedDistance) / planeDistanceFromOrigin; +// if (relativeError > EPSILON) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray plane intersection distance error = " +// << relativeError << std::endl; +// } } } @@ -2095,13 +2229,15 @@ void ShapeColliderTests::rayMissesPlane() { intersection._rayStart = glm::vec3(-startDistance, 0.0f, 0.0f); intersection._rayDirection = glm::normalize(glm::vec3(-1.0f, 0.0f, -1.0f)); - if (plane.findRayIntersection(intersection)) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should miss plane" << std::endl; - } - if (intersection._hitDistance != FLT_MAX) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: distance should be unchanged after intersection miss" - << std::endl; - } + QCOMPARE(plane.findRayIntersection(intersection), false); +// if (plane.findRayIntersection(intersection)) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should miss plane" << std::endl; +// } + QCOMPARE(intersection._hitDistance, FLT_MAX); +// if (intersection._hitDistance != FLT_MAX) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: distance should be unchanged after intersection miss" +// << std::endl; +// } // rotate the whole system and try again float angle = 37.8f; @@ -2115,16 +2251,19 @@ void ShapeColliderTests::rayMissesPlane() { intersection._rayDirection = rotation * intersection._rayDirection; intersection._hitDistance = FLT_MAX; - if (plane.findRayIntersection(intersection)) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should miss plane" << std::endl; - } - if (intersection._hitDistance != FLT_MAX) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: distance should be unchanged after intersection miss" - << std::endl; - } - if (intersection._hitShape != NULL) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray intersection._hitShape should be NULL" << std::endl; - } + QCOMPARE(plane.findRayIntersection(intersection), false); +// if (plane.findRayIntersection(intersection)) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should miss plane" << std::endl; +// } + QCOMPARE(intersection._hitDistance, FLT_MAX); +// if (intersection._hitDistance != FLT_MAX) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: distance should be unchanged after intersection miss" +// << std::endl; +// } + QCOMPARE(intersection._hitShape, (Shape*)nullptr); +// if (intersection._hitShape != NULL) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray intersection._hitShape should be NULL" << std::endl; +// } } { // make a simple ray that points away from plane @@ -2135,13 +2274,15 @@ void ShapeColliderTests::rayMissesPlane() { intersection._rayDirection = glm::normalize(glm::vec3(-1.0f, -1.0f, -1.0f)); intersection._hitDistance = FLT_MAX; - if (plane.findRayIntersection(intersection)) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should miss plane" << std::endl; - } - if (intersection._hitDistance != FLT_MAX) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: distance should be unchanged after intersection miss" - << std::endl; - } + QCOMPARE(plane.findRayIntersection(intersection), false); +// if (plane.findRayIntersection(intersection)) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should miss plane" << std::endl; +// } + QCOMPARE(intersection._hitDistance, FLT_MAX); +// if (intersection._hitDistance != FLT_MAX) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: distance should be unchanged after intersection miss" +// << std::endl; +// } // rotate the whole system and try again float angle = 37.8f; @@ -2155,13 +2296,15 @@ void ShapeColliderTests::rayMissesPlane() { intersection._rayDirection = rotation * intersection._rayDirection; intersection._hitDistance = FLT_MAX; - if (plane.findRayIntersection(intersection)) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should miss plane" << std::endl; - } - if (intersection._hitDistance != FLT_MAX) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: distance should be unchanged after intersection miss" - << std::endl; - } + QCOMPARE(plane.findRayIntersection(intersection), false); +// if (plane.findRayIntersection(intersection)) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should miss plane" << std::endl; +// } + QCOMPARE(intersection._hitDistance, FLT_MAX); +// if (intersection._hitDistance != FLT_MAX) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: distance should be unchanged after intersection miss" +// << std::endl; +// } } } @@ -2203,28 +2346,32 @@ void ShapeColliderTests::rayHitsAACube() { intersection._rayLength = 1.0001f * glm::distance(rayStart, facePoint); // cast the ray - bool hit = cube.findRayIntersection(intersection); +// bool hit = cube.findRayIntersection(intersection); // validate - if (!hit) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should hit cube face" << std::endl; - break; - } - if (glm::abs(1.0f - glm::dot(faceNormal, intersection._hitNormal)) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: ray should hit cube face with normal " << faceNormal - << " but found different normal " << intersection._hitNormal << std::endl; - } - if (glm::distance(facePoint, intersection.getIntersectionPoint()) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: ray should hit cube face at " << facePoint - << " but actually hit at " << intersection.getIntersectionPoint() - << std::endl; - } - if (intersection._hitShape != &cube) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray intersection._hitShape should point at cube" - << std::endl; - } + QCOMPARE(cube.findRayIntersection(intersection), true); +// if (!hit) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should hit cube face" << std::endl; +// break; +// } + QFUZZY_COMPARE(glm::dot(faceNormal, intersection._hitNormal), 1.0f, EPSILON); +// if (glm::abs(1.0f - glm::dot(faceNormal, intersection._hitNormal)) > EPSILON) { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: ray should hit cube face with normal " << faceNormal +// << " but found different normal " << intersection._hitNormal << std::endl; +// } + QFUZZY_COMPARE(facePoint, intersection.getIntersectionPoint(), EPSILON); +// if (glm::distance(facePoint, intersection.getIntersectionPoint()) > EPSILON) { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: ray should hit cube face at " << facePoint +// << " but actually hit at " << intersection.getIntersectionPoint() +// << std::endl; +// } + QCOMPARE(intersection._hitShape, &cube); +// if (intersection._hitShape != &cube) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray intersection._hitShape should point at cube" +// << std::endl; +// } } } } @@ -2273,10 +2420,11 @@ void ShapeColliderTests::rayMissesAACube() { intersection._rayLength = (1.0f - SOME_SMALL_NUMBER) * glm::distance(rayStart, facePoint); // cast the ray - if (cube.findRayIntersection(intersection)) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should NOT hit cube face " - << faceNormal << std::endl; - } + QCOMPARE(cube.findRayIntersection(intersection), false); +// if (cube.findRayIntersection(intersection)) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should NOT hit cube face " +// << faceNormal << std::endl; +// } } } } @@ -2315,10 +2463,11 @@ void ShapeColliderTests::rayMissesAACube() { intersection._rayDirection = glm::normalize(sidePoint - rayStart); // cast the ray - if (cube.findRayIntersection(intersection)) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should NOT hit cube face " - << faceNormal << std::endl; - } + QCOMPARE(cube.findRayIntersection(intersection), false); +// if (cube.findRayIntersection(intersection)) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should NOT hit cube face " +// << faceNormal << std::endl; +// } } } } @@ -2358,10 +2507,11 @@ void ShapeColliderTests::rayMissesAACube() { intersection._rayDirection = rayDirection; // cast the ray - if (cube.findRayIntersection(intersection)) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should NOT hit cube face " - << faceNormal << std::endl; - } + QCOMPARE(cube.findRayIntersection(intersection), false); +// if (cube.findRayIntersection(intersection)) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR: ray should NOT hit cube face " +// << faceNormal << std::endl; +// } } } } @@ -2370,6 +2520,9 @@ void ShapeColliderTests::rayMissesAACube() { } void ShapeColliderTests::measureTimeOfCollisionDispatch() { + + // use QBENCHMARK for this + /* KEEP for future manual testing // create two non-colliding spheres float radiusA = 7.0f; diff --git a/tests/physics/src/ShapeColliderTests.h b/tests/physics/src/ShapeColliderTests.h index 85d907b440..73e2b972a9 100644 --- a/tests/physics/src/ShapeColliderTests.h +++ b/tests/physics/src/ShapeColliderTests.h @@ -18,6 +18,8 @@ class ShapeColliderTests : public QObject { Q_OBJECT private slots: + void initTestCase(); + void sphereMissesSphere(); void sphereTouchesSphere();