// Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors. // All rights reserved. // Code licensed under the BSD License. // http://www.anki3d.org/LICENSE #include #include "anki/Math.h" using namespace anki; /// Test the common perators between a vector and another vector template void operatorsSame() { const U size = Vec::COMPONENT_COUNT; using T = typename Vec::Scalar; Vec a, b; Array add, sub, mul, div; for(U i = 0; i < size; i++) { T v0 = T(F64(i * 10) / 2.0 + 1.0); T v1 = T(F64(i * 1000) / 5.123 + 1.0); a[i] = v0; b[i] = v1; add[i] = v0 + v1; sub[i] = v0 - v1; mul[i] = v0 * v1; div[i] = v0 / v1; } Vec c = a + b; Vec d = a - b; Vec e = a * b; Vec f = a / b; for(U i = 0; i < size; i++) { ANKI_TEST_EXPECT_EQ(c[i], add[i]); ANKI_TEST_EXPECT_EQ(d[i], sub[i]); ANKI_TEST_EXPECT_EQ(e[i], mul[i]); ANKI_TEST_EXPECT_EQ(f[i], div[i]); } c = a; c += b; d = a; d -= b; e = a; e *= b; f = a; f /= b; for(U i = 0; i < size; i++) { ANKI_TEST_EXPECT_EQ(c[i], add[i]); ANKI_TEST_EXPECT_EQ(d[i], sub[i]); ANKI_TEST_EXPECT_EQ(e[i], mul[i]); ANKI_TEST_EXPECT_EQ(f[i], div[i]); } } /// Test the dot prods template void dot() { const U size = Vec::COMPONENT_COUNT; using T = typename Vec::Scalar; T res = 0; Vec vec; for(U i = 0; i < size; i++) { T x = T(i * 666 + 1); vec[i] = x; res += x * x; } ANKI_TEST_EXPECT_EQ(vec.dot(vec), res); } /// Test length and normalization template void length() { using T = typename Vec::Scalar; U size = Vec::COMPONENT_COUNT; Vec vec; T res = 0; for(U i = 0; i < size; i++) { T x = T(i * 666); vec[i] = x; res += x * x; } res = T(sqrt(F32(res))); ANKI_TEST_EXPECT_EQ(vec.getLength(), res); if(Vec::IS_INTEGER) { ANKI_TEST_EXPECT_EQ(vec.getNormalized(), vec / res); } else { auto a = vec / res; auto b = vec.getNormalized(); for(U i = 0; i < size; i++) { ANKI_TEST_EXPECT_NEAR(a[i], b[i], 0.0001); } } } template void comparision() { U size = Vec::COMPONENT_COUNT; using Scalar = typename Vec::Scalar; Vec a, a1, b; for(U i = 0; i < size; i++) { a[i] = Scalar(i * 666); a1[i] = a[i]; b[i] = a[i] + 1; } ANKI_TEST_EXPECT_EQ(a == a1, true); ANKI_TEST_EXPECT_EQ(a != a1, false); ANKI_TEST_EXPECT_EQ(a < a1, false); ANKI_TEST_EXPECT_EQ(a <= a1, true); ANKI_TEST_EXPECT_EQ(a > a1, false); ANKI_TEST_EXPECT_EQ(a >= a1, true); ANKI_TEST_EXPECT_EQ(a == b, false); ANKI_TEST_EXPECT_EQ(a != b, true); ANKI_TEST_EXPECT_EQ(a < b, true); ANKI_TEST_EXPECT_EQ(a <= b, true); ANKI_TEST_EXPECT_EQ(a > b, false); ANKI_TEST_EXPECT_EQ(a >= b, false); } /// Common vector tests template void commonVecTests() { operatorsSame(); dot(); length(); comparision(); } ANKI_TEST(Math, Vec2) { commonVecTests(); commonVecTests(); commonVecTests(); } ANKI_TEST(Math, Vec3) { commonVecTests(); commonVecTests(); commonVecTests(); } ANKI_TEST(Math, Vec4) { commonVecTests(); commonVecTests(); commonVecTests(); } /// Test the common operators between a matrices template void matOperatorsSame() { const U size = Mat::SIZE; using T = typename Mat::Scalar; Mat a, b; Array add, sub; for(U i = 0; i < size; i++) { T v0 = T(i * 10 / 2); T v1 = T(F64(i * 1000) / 5.123); a[i] = v0; b[i] = v1; add[i] = v0 + v1; sub[i] = v0 - v1; } Mat c = a + b; Mat d = a - b; for(U i = 0; i < size; i++) { ANKI_TEST_EXPECT_EQ(c[i], add[i]); ANKI_TEST_EXPECT_EQ(d[i], sub[i]); } c = a; c += b; d = a; d -= b; for(U i = 0; i < size; i++) { ANKI_TEST_EXPECT_EQ(c[i], add[i]); ANKI_TEST_EXPECT_EQ(d[i], sub[i]); } } /// Get a filled matrix template Mat getNonEmptyMat(typename Mat::Scalar offset = 0) { Mat out; for(U i = 0; i < Mat::SIZE; i++) { out[i] = typename Mat::Scalar(i) + offset; } return out; } /// Some getters setters template void matSettersGetters() { using T = typename Mat::Scalar; Mat m(T(0)); m.setRow(1, RowVec(1.0)); ANKI_TEST_EXPECT_EQ(m.getRow(1), RowVec(1.0)); m.setColumn(1, ColVec(2.0)); m.setColumn(2, ColVec(3.0)); ANKI_TEST_EXPECT_EQ(m.getColumn(1), ColVec(2.0)); ANKI_TEST_EXPECT_EQ(m.getColumn(2), ColVec(3.0)); ANKI_TEST_EXPECT_EQ(m.getYAxis(), m.getColumn(1)); } /// Transpose template void transpose() { Mat a = getNonEmptyMat(); Mat b = a.getTransposed(); for(U j = 0; j < Mat::ROW_SIZE; j++) { for(U i = 0; i < Mat::COLUMN_SIZE; i++) { ANKI_TEST_EXPECT_EQ(a(j, i), b(i, j)); } } b.transposeRotationPart(); for(U j = 0; j < 3; j++) { for(U i = 0; i < 3; i++) { ANKI_TEST_EXPECT_EQ(a(j, i), b(j, i)); } } } /// Mat vector multiplication template void matVecMul() { using T = typename Mat::Scalar; Mat m = getNonEmptyMat(); VecIn v; for(U i = 0; i < VecIn::SIZE; i++) { v[i] = i; } VecOut out = m * v; VecOut out1; for(U j = 0; j < Mat::ROW_SIZE; j++) { T sum = 0; for(U i = 0; i < Mat::COLUMN_SIZE; i++) { sum += m(j, i) * v[j]; } out1[j] = sum; } ANKI_TEST_EXPECT_EQ(out1, out); } template void commonMatTests() { matOperatorsSame(); matSettersGetters(); } ANKI_TEST(Math, Mat3) { commonMatTests(); transpose(); // mat*mat { Mat3 a = getNonEmptyMat(0); Mat3 b = getNonEmptyMat(1); Mat3 c = a * b; Mat3 d = Mat3(18.000, 21.000, 24.000, 54.000, 66.000, 78.000, 90.000, 111.000, 132.000); ANKI_TEST_EXPECT_EQ(c, d); } // mat*vec { Mat3 m = getNonEmptyMat(1.0); Vec3 v(0.0, 1.0, 2.0); ANKI_TEST_EXPECT_EQ(m * v, Vec3(8, 17, 26)); } } ANKI_TEST(Math, Mat4) { commonMatTests(); transpose(); // mat*mat { Mat4 a = getNonEmptyMat(0); Mat4 b = getNonEmptyMat(1); Mat4 c = a * b; Mat4 d = Mat4(62.0, 68.0, 74.0, 80.0, 174.000, 196.000, 218.000, 240.000, 286.000, 324.000, 362.000, 400.000, 398.000, 452.000, 506.000, 560.000); ANKI_TEST_EXPECT_EQ(c, d); } // mat*vec { Mat4 m = getNonEmptyMat(1.0); Vec4 v(0.0, 1.0, 2.0, 3.0); ANKI_TEST_EXPECT_EQ(m * v, Vec4(20, 44, 68, 92)); } } ANKI_TEST(Math, Mat3x4) { commonMatTests(); // combine transforms { Mat3x4 a = getNonEmptyMat(0); Mat3x4 b = getNonEmptyMat(1); Mat3x4 c = a.combineTransformations(b); Mat3x4 d = Mat3x4(23.000, 26.000, 29.000, 35.000, 83.000, 98.000, 113.000, 135.000, 143.000, 170.000, 197.000, 235.000); ANKI_TEST_EXPECT_EQ(c, d); } // mat*vec { Mat3x4 m = getNonEmptyMat(1.0); Vec4 v(0.0, 1.0, 2.0, 3.0); ANKI_TEST_EXPECT_EQ(m * v, Vec3(20, 44, 68)); } }