From 2513f6556e30e7d98ca615ed769ad82f902f7137 Mon Sep 17 00:00:00 2001 From: Piotr Dziwinski Date: Tue, 1 May 2012 20:05:48 +0200 Subject: Structs continued Basic functions finished and tested for matrix and vector. --- src/math/test/CMakeLists.txt | 15 +- src/math/test/matrix_test.cpp | 424 +++++++++++++++++++++++------------------- src/math/test/vector_test.cpp | 126 +++++++++++++ 3 files changed, 367 insertions(+), 198 deletions(-) create mode 100644 src/math/test/vector_test.cpp (limited to 'src/math/test') diff --git a/src/math/test/CMakeLists.txt b/src/math/test/CMakeLists.txt index d82a9b9..af9bcca 100644 --- a/src/math/test/CMakeLists.txt +++ b/src/math/test/CMakeLists.txt @@ -4,11 +4,22 @@ set(CMAKE_BUILD_TYPE debug) set(CMAKE_CXX_FLAGS_DEBUG "-Wall -g -O0") add_executable(matrix_test matrix_test.cpp) +add_executable(vector_test vector_test.cpp) enable_testing() add_test(matrix_test ./matrix_test) +add_test(vector_test ./vector_test) -add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} DEPENDS matrix_test) +# 'make check' will compile the required test programs +# Note that 'make test' will still fail without compiled programs +add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} DEPENDS matrix_test vector_test) -add_custom_target(distclean COMMAND rm -rf ./matrix_test CMakeFiles Testing cmake_install.cmake CMakeCache.txt CTestTestfile.cmake Makefile) \ No newline at end of file +# Files to be removed in distclean +set(REMOVE_FILES + CMakeFiles Testing cmake_install.cmake CMakeCache.txt CTestTestfile.cmake Makefile + ./matrix_test + ./vector_test +) + +add_custom_target(distclean COMMAND rm -rf ${REMOVE_FILES}) \ No newline at end of file diff --git a/src/math/test/matrix_test.cpp b/src/math/test/matrix_test.cpp index c7e9c01..6ca92be 100644 --- a/src/math/test/matrix_test.cpp +++ b/src/math/test/matrix_test.cpp @@ -18,8 +18,8 @@ /* Unit tests for Matrix struct - Test data was randomly generated and the expected - results calculated using GNU Octave. + Test data was randomly generated and the expected results + calculated using GNU Octave. */ @@ -30,53 +30,77 @@ using namespace std; -const float TEST_TOLERANCE = 1e-5; +const float TEST_TOLERANCE = 1e-6; int TestCofactor() { - const float TEST_MATRIX[16] = - { - -0.306479, - -0.520207, - 0.127906, - 0.632922, - - -0.782876, - 0.015264, - 0.337479, - 1.466013, - - 0.072725, - -0.315123, - 1.613198, - -0.577377, - - 0.962397, - -1.320724, - 1.467588, - 0.579020 - }; + const Math::Matrix mat1( + (float[4][4]) + { + { 0.610630320796245, 1.059932357918312, -1.581674311378210, 1.782214448453331 }, + { 0.191028848211526, -0.813898708757524, 1.516114203870644, 0.395202639476002 }, + { 0.335142750345279, -0.346586619596529, 0.545382042472336, -0.879268918923072 }, + { 1.417588151657198, 1.450841789070141, 0.219080104196171, 0.378724047481655 } + } + ); + + const Math::Matrix expectedCofactors1( + (float[4][4]) + { + { -2.402679369186782, 2.282452509293019, 1.722732204057644, -0.746939701104385 }, + { -0.687677756877654, 1.168949180331164, -0.985354966837796, -1.334071111592705 }, + { -5.115621958424845, 4.229724770159009, 2.529000630782808, 1.481632618355891 }, + { 0.147480897398694, -2.140677680337111, -1.207189492265546, 0.151236920408051 } + } + ); - const float EXPECTED_RESULTS[4][4] = + for (int r = 0; r < 4; ++r) { - { 2.791599, -0.249952, 1.065075, -1.356570 }, - { 3.715943, -1.537511, 0.094812, -0.074520 }, - { 1.034500, -0.731752, -0.920756, -0.196235 }, - { 1.213928, -1.236857, 0.779741, -0.678482 } - }; + for (int c = 0; c < 4; ++c) + { + float ret = mat1.Cofactor(r, c); + float exp = expectedCofactors1.m[4*c+r]; + if (! Math::IsEqual(ret, exp, TEST_TOLERANCE)) + { + fprintf(stderr, "Cofactors 1 mismatch!\n"); + fprintf(stderr, "r=%d, c=%d, %f (returned) != %f (expected)\n", r, c, ret, exp); + return __LINE__; + } + } + } + + const Math::Matrix mat2( + (float[4][4]) + { + { 0.9845099464982393, -0.9091233416532389, -0.6272243714245945, 0.4645001858944354 }, + { -0.1333308471483736, 0.9128181433725897, -1.0937461393836190, 0.3180936795928376 }, + { -0.0654324396846289, 0.1014641705415945, 1.5107709042683430, -0.0240560430414690 }, + { 0.0179638644093347, -1.0695585982782767, -0.1741250853101032, 1.0803106709464336 } + } + ); + + const Math::Matrix expectedCofactors2( + (float[4][4]) + { + { 2.0861102207614466, 0.2989010779528912, 0.0746276150537432, 0.2732659822656097 }, + { 0.6850002886584565, 1.5513169659641379, -0.0503743176545917, 1.5163672441575642 }, + { 1.2385556680997216, 1.1827709562505695, 1.2282813085138962, 1.3483789679871401 }, + { -1.0710790241539783, -0.5589604503588883, 0.0100959837872308, 1.1897872684455839 } + } + ); - Math::Matrix mat(TEST_MATRIX); for (int r = 0; r < 4; ++r) { for (int c = 0; c < 4; ++c) { - float ret = mat.Cofactor(r, c); - float exp = EXPECTED_RESULTS[r][c]; + float ret = mat2.Cofactor(r, c); + float exp = expectedCofactors2.m[4*c+r]; if (! Math::IsEqual(ret, exp, TEST_TOLERANCE)) { - fprintf(stderr, "Cofactor r=%d, c=%d, %f (returned) != %f (expected)\n", r, c, ret, exp); - return 4*c+r; + fprintf(stderr, "Cofactors 2 mismatch!\n"); + fprintf(stderr, "r=%d, c=%d, %f (returned) != %f (expected)\n", r, c, ret, exp); + return __LINE__; } } } @@ -86,96 +110,105 @@ int TestCofactor() int TestDet() { - const float TEST_MATRIX[16] = + const Math::Matrix mat1( + (float[4][4]) + { + { -0.95880162984708284, 0.24004047608997131, -0.78172309932665407, -0.11604124457222834 }, + { -0.36230592086261376, -0.75778166876017261, 0.33041059404631740, -1.06001391941094836 }, + { 0.00260215210936187, 1.27485610196385113, -0.26149859846418033, -0.59669701186364876 }, + { 0.36899429848485432, 3.01720896813933104, 2.10311476609438719, -1.68627076626448269 } + } + ); + + const float expectedDet1 = 4.07415413729671; + + float ret1 = mat1.Det(); + if (! Math::IsEqual(ret1, expectedDet1, TEST_TOLERANCE)) { - 0.85554, - 0.11624, - 1.30411, - 0.81467, - - 0.49692, - -1.92483, - -1.33543, - 0.85042, - - -0.16775, - 0.35344, - 1.40673, - 0.13961, - - 1.40709, - 0.11731, - 0.69042, - 0.91216 - }; + fprintf(stderr, "Det mismatch!\n"); + fprintf(stderr, "%f (returned) != %f (expected)\n", ret1, expectedDet1); + return __LINE__; + } - const float EXPECTED_RESULT = 0.084360; + const Math::Matrix mat2( + (float[4][4]) + { + { -1.0860073221346871, 0.9150354098189495, -0.2723201933559999, 0.2922832160271507 }, + { -1.0248331304801788, -2.5081237461125205, -1.0277123574586633, -0.2254690663329798 }, + { -1.4227635282899367, -0.0403846809122684, 0.9216148477171653, 1.2517067488015878 }, + { -0.1160254467152022, 0.8270675274393656, 1.0327218739781614, -0.3674886870220400 } + } + ); - float ret = Math::Matrix(TEST_MATRIX).Det(); - if (! Math::IsEqual(ret, EXPECTED_RESULT, TEST_TOLERANCE)) + const float expectedDet2 = -6.35122307880942; + + float ret2 = mat2.Det(); + if (! Math::IsEqual(ret2, expectedDet2, TEST_TOLERANCE)) { - fprintf(stderr, "Det %f (returned) != %f (expected)\n", ret, EXPECTED_RESULT); - return 1; + fprintf(stderr, "Det mismatch!\n"); + fprintf(stderr, "%f (returned) != %f (expected)\n", ret2, expectedDet2); + return __LINE__; } return 0; } -int TestInvert() +int TestInverse() { - const float TEST_MATRIX[16] = - { - 1.4675123, - -0.2857923, - -0.0496217, - -1.2825408, - - -0.2804135, - -0.0826255, - -0.6825495, - 1.1661259, - - 0.0032798, - 0.5999200, - -1.8359883, - -1.1894424, - - -1.1501538, - -2.8792485, - 0.0299345, - 0.3730919 - }; + const Math::Matrix mat1( + (float[4][4]) + { + { -2.2829352811514658, -0.9103222363187888, 0.2792976509411680, -0.7984393573193174 }, + { 2.4823665798689589, -0.0599056759070980, 0.3832364352926366, -1.6404257204372739 }, + { -0.3841952272526398, -0.8377700696457873, -0.3416328338427138, 1.1746577275723329 }, + { 0.1746031241954947, -0.4952532117949962, 0.2155084379835037, -1.6586460437329220 } + } + ); + + const Math::Matrix expectedInverse1( + (float[4][4]) + { + { -0.119472603171041, 0.331675963276297, 0.187516809009720, -0.137720814290806 }, + { -0.387591686166085, -0.487284946727583, -0.798527541290274, 0.102991635972060 }, + { 2.601905603425902, 2.606899016264679, -0.528006148839176, -4.204703326522837 }, + { 0.441220327151392, 0.519128136207318, 0.189567009205522, -1.194469716136194 } + } + ); + + Math::Matrix inverse1 = mat1.Inverse(); - const float EXPECTED_RESULT[16] = + if (! Math::MatricesEqual(inverse1, expectedInverse1, TEST_TOLERANCE)) { - 0.685863, - 0.562274, - -0.229722, - -0.132079, - - -0.266333, - -0.139862, - 0.054211, - -0.305568, - - -0.130817, - -0.494076, - -0.358226, - -0.047477, - - 0.069486, - 0.693649, - -0.261074, - -0.081200 - }; + fprintf(stderr, "Inverse 1 mismatch!\n"); + return __LINE__; + } + + const Math::Matrix mat2( + (float[4][4]) + { + { -0.05464332404298505, -0.64357755258235749, -0.13017671677619302, -0.56742332785888006 }, + { 0.29048383600458222, -0.91517047043724875, 0.84517524415561684, 0.51628195547960565 }, + { 0.00946488004480186, -0.89077382212689293, 0.73565573766341397, -0.15932513521840930 }, + { -1.01244718912499132, -0.27840911963972276, -0.39189681211309862, 1.18315064340192055 } + } + ); - Math::Matrix mat(TEST_MATRIX); - mat.Invert(); + const Math::Matrix expectedInverse2( + (float[4][4]) + { + { 0.771302711132012, 1.587542278361995, -2.003075114445104, -0.592574156227379 }, + { -1.208929259769431, -0.786598967848473, 0.607335305808052, -0.154759693303324 }, + { -1.500037668208218, -0.774300278997914, 1.917800427261255, -0.123268572651291 }, + { -0.121314770937944, 0.916925149209746, -0.935924950785014, 0.260875394250671 } + } + ); + + Math::Matrix inverse2 = mat2.Inverse(); - if (! Math::MatricesEqual(mat, EXPECTED_RESULT, TEST_TOLERANCE)) + if (! Math::MatricesEqual(inverse2, expectedInverse2, TEST_TOLERANCE)) { - fprintf(stderr, "Invert mismatch\n"); - return 1; + fprintf(stderr, "Inverse 2 mismatch!\n"); + return __LINE__; } return 0; @@ -183,81 +216,78 @@ int TestInvert() int TestMultiply() { - const float TEST_MATRIX_A[16] = - { - -1.931420, - 0.843410, - 0.476929, - -0.493435, - 1.425659, - -0.176331, - 0.129096, - 0.551081, - -0.543530, - -0.190783, - -0.084744, - 1.379547, - -0.473377, - 1.643398, - 0.400539, - 0.702937 - }; + const Math::Matrix mat1A( + (float[4][4]) + { + { 0.6561727049162027, -1.4180263627131411, -0.8271026046117423, 2.3919331748512578 }, + { -0.6035665535146352, 0.0150827348790615, -0.7090794192822540, 0.9057604704594814 }, + { -0.9871045001223655, -0.4980646811455065, 0.3806177002298990, 0.1520583649240934 }, + { -0.2721911170792712, 0.7627928194552067, -0.1504091336784158, 0.9747545351840121 } + } + ); - const float TEST_MATRIX_B[16] = - { - 0.3517561, - 1.3903778, - -0.8048254, - -0.4090024, - - -1.5542159, - -0.6798636, - 1.6003393, - -0.1467117, - - 0.5043620, - -0.0068779, - 2.0697285, - -0.0463650, - - 0.9605451, - -0.4620149, - 1.2525952, - -1.3409909 - }; + const Math::Matrix mat1B( + (float[4][4]) + { + { -0.2643735892448818, -0.7542994492819621, 0.6082322350568750, 0.0581733424861419 }, + { 1.0293246070431237, 0.1979285388251341, -0.2932031385332818, 0.8838407179018929 }, + { 0.3448687251553114, 0.5031654871245456, 0.7554693012922442, -0.4845315903845708 }, + { -1.8662838497278593, -0.7843850624747805, 0.1389026096476257, -1.3686415408300689 } + } + ); + + const Math::Matrix expectedMultiply1( + (float[4][4]) + { + { -6.382352236417988, -3.067984733682130, 0.522270304251466, -4.088079444498280 }, + { -1.759853366848825, -0.608994052024491, -0.781406179437379, -0.917870775786188 }, + { -0.404226802169062, 0.718232546720114, -0.145688356880835, -0.890167707987175 }, + { -1.013918490922430, -0.483971504099758, -0.367442194643757, -0.602858486133615 } + } + ); - const float EXPECTED_RESULT[16] = + Math::Matrix multiply1 = Math::MultiplyMatrices(mat1A, mat1B); + if (! Math::MatricesEqual(multiply1, expectedMultiply1, TEST_TOLERANCE ) ) { - 1.933875, - -0.467099, - 0.251638, - -0.805156, - - 1.232207, - -1.737383, - -1.023401, - 2.496859, - - -2.086953, - -0.044468, - 0.045688, - 2.570036, - - -2.559921, - -1.551155, - -0.244802, - 0.056808 - }; + fprintf(stderr, "Multiply 1 mismath!\n"); + return __LINE__; + } + + const Math::Matrix mat2A( + (float[4][4]) + { + { 0.8697203025776754, 2.1259475710644935, 1.7856691009707812, -2.1563963348328126 }, + { 1.5888074489288735, -0.0794849733953615, 0.7307782768677457, 0.7943129159612630 }, + { 0.2859761537233830, -0.6231231890384962, -0.0496743172880377, -0.8137857518646087 }, + { 1.2670547229512983, -0.5305171374831831, -0.4987412674062375, -1.1257327113869595 } + } + ); - Math::Matrix matA(TEST_MATRIX_A); - Math::Matrix matB(TEST_MATRIX_B); + const Math::Matrix mat2B( + (float[4][4]) + { + { 1.1321105701165317, 0.1759563504574463, -2.0675778912000418, 1.4840339814245538 }, + { -1.5117280888829916, -0.0933013188828093, -0.2079262944351640, 0.9575727579539316 }, + { 0.3615378398970173, 1.2465163589027248, 1.1326150997082589, 0.9921208694352303 }, + { -0.7357104529373861, -0.4774022005969588, -0.2118739096676499, 1.1427567093270703 } + } + ); + + const Math::Matrix expectedMultiply2( + (float[4][4]) + { + { 0.00283516267056338, 3.21001319965989307, 0.23910503934370686, 2.63380716363006107 }, + { 1.59868505822469742, 0.81869715594617765, -2.60905981088293570, 3.91445839239110294 }, + { 1.84650099286297942, 0.43504079532852930, -0.34555619012424243, -1.15152951542451487 }, + { 2.88434318563174585, 0.18818239851585700, -2.83579436909308980, -0.40890672198610400 } + } + ); - Math::Matrix mat; - Math::MultiplyMatrices(matA, matB, mat); - if (! Math::MatricesEqual(mat, Math::Matrix(EXPECTED_RESULT), TEST_TOLERANCE ) ) + Math::Matrix multiply2 = Math::MultiplyMatrices(mat2A, mat2B); + if (! Math::MatricesEqual(multiply2, expectedMultiply2, TEST_TOLERANCE ) ) { - fprintf(stderr, "Multiply mismath!\n"); - return 1; + fprintf(stderr, "Multiply 2 mismath!\n"); + return __LINE__; } return 0; @@ -265,23 +295,25 @@ int TestMultiply() int main() { - int result = 0; - - result = TestCofactor(); - if (result != 0) - return result; - - result = TestDet(); - if (result != 0) - return result; + // Functions to test + int (*TESTS[])() = + { + TestCofactor, + TestDet, + TestInverse, + TestMultiply + }; + const int TESTS_SIZE = sizeof(TESTS) / sizeof(*TESTS); - result = TestInvert(); - if (result != 0) - return result; + int result = 0; + for (int i = 0; i < TESTS_SIZE; ++i) + { + result = TESTS[i](); + if (result != 0) + return result; + } - result = TestMultiply(); - if (result != 0) - return result; + fprintf(stderr, "All tests successful\n"); - return result; + return 0; } diff --git a/src/math/test/vector_test.cpp b/src/math/test/vector_test.cpp new file mode 100644 index 0000000..2f4dd09 --- /dev/null +++ b/src/math/test/vector_test.cpp @@ -0,0 +1,126 @@ +// * This file is part of the COLOBOT source code +// * Copyright (C) 2012, Polish Portal of Colobot (PPC) +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have received a copy of the GNU General Public License +// * along with this program. If not, see http://www.gnu.org/licenses/. + +// math/test/vector_test.cpp + +/* Unit tests for Vector struct + + Test data was randomly generated and the expected results + calculated using GNU Octave. + + */ + +#include "../func.h" +#include "../vector.h" + +#include + +using namespace std; + +const float TEST_TOLERANCE = 1e-6; + +int TestLength() +{ + Math::Vector vec(-1.288447945923275, 0.681452565308134, -0.633761098985957); + const float expectedLength = 1.58938001708428; + + if (! Math::IsEqual(vec.Length(), expectedLength, TEST_TOLERANCE) ) + { + fprintf(stderr, "Length mismatch!\n"); + return __LINE__; + } + + return 0; +} + +int TestNormalize() +{ + Math::Vector vec(1.848877241804398, -0.157262961268577, -1.963031403332377); + const Math::Vector expectedNormalized(0.6844609421393856, -0.0582193085618106, -0.7267212194481797); + + vec.Normalize(); + + if (! Math::VectorsEqual(vec, expectedNormalized, TEST_TOLERANCE)) + { + fprintf(stderr, "Normalize mismatch!\n"); + return __LINE__; + } + + return 0; +} + +int TestDot() +{ + Math::Vector vecA(0.8202190530968309, 0.0130926060162780, 0.2411914183883510); + Math::Vector vecB(-0.0524083951404069, 1.5564932716738220, -0.8971342631500536); + + float expectedDot = -0.238988896477326; + + if (! Math::IsEqual(Math::DotProduct(vecA, vecB), expectedDot, TEST_TOLERANCE) ) + { + fprintf(stderr, "Dot product mismatch!\n"); + return __LINE__; + } + + return 0; +} + +int TestCross() +{ + Math::Vector vecA(1.37380499798567, 1.18054518384682, 1.95166361293121); + Math::Vector vecB(0.891657855926886, 0.447591335394532, -0.901604070087823); + + Math::Vector expectedCross(-1.937932065431669, 2.978844370287636, -0.437739173833581); + Math::Vector expectedReverseCross = -expectedCross; + + if (! Math::VectorsEqual(vecA.CrossMultiply(vecB), expectedCross, TEST_TOLERANCE) ) + { + fprintf(stderr, "Cross product mismatch!\n"); + return __LINE__; + } + + if (! Math::VectorsEqual(vecB.CrossMultiply(vecA), expectedReverseCross, TEST_TOLERANCE) ) + { + fprintf(stderr, "Reverse cross product mismatch!\n"); + return __LINE__; + } + + return 0; +} + +int main() +{ + // Functions to test + int (*TESTS[])() = + { + TestNormalize, + TestDot, + TestCross + }; + const int TESTS_SIZE = sizeof(TESTS) / sizeof(*TESTS); + + int result = 0; + for (int i = 0; i < TESTS_SIZE; ++i) + { + result = TESTS[i](); + if (result != 0) + return result; + } + + fprintf(stderr, "All tests successful\n"); + + return 0; +} -- cgit v1.2.3-1-g7c22