// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen // SPDX-License-Identifier: BSD-3-Clause // // Note if you fix this test to fill in all the empty tests // then remove the cppcheck suppression in VTKcppcheckSuppressions.txt // #include "vtkDataArrayRange.h" #include "vtkIntArray.h" #include "vtkMath.h" #include "vtkMathUtilities.h" #include "vtkSmartPointer.h" #include "vtkType.h" #include "vtkUnsignedCharArray.h" #include "vtkUnsignedShortArray.h" #include #include #include #include static int TestPi(); static int TestDegreesFromRadians(); static int TestRound(); static int TestFloor(); static int TestCeil(); static int TestCeilLog2(); static int TestIsPowerOfTwo(); static int TestNearestPowerOfTwo(); static int TestFactorial(); static int TestBinomial(); static int TestRandom(); static int TestAddSubtract(); static int TestMultiplyScalar(); static int TestMultiplyScalar2D(); static int TestDot(); static int TestOuter(); static int TestCross(); static int TestNorm(); static int TestNormalize(); static int TestPerpendiculars(); static int TestProjectVector(); static int TestProjectVector2D(); static int TestDistance2BetweenPoints(); static int TestAngleBetweenVectors(); static int TestGaussianAmplitude(); static int TestGaussianWeight(); static int TestDot2D(); static int TestNorm2D(); static int TestNormalize2D(); static int TestDeterminant2x2(); static int TestDeterminant3x3(); static int TestLUFactor3x3(); static int TestLUSolve3x3(); static int TestLinearSolve3x3(); static int TestMultiply3x3(); static int TestMultiplyMatrix(); static int TestTranspose3x3(); static int TestInvert3x3(); static int TestInvertMatrix(); static int TestIdentity3x3(); static int TestQuaternionToMatrix3x3(); static int TestMatrix3x3ToQuaternion(); static int TestMultiplyQuaternion(); static int TestOrthogonalize3x3(); static int TestDiagonalize3x3(); static int TestSingularValueDecomposition3x3(); static int TestSolveLinearSystem(); static int TestSolveLeastSquares(); static int TestSolveHomogeneousLeastSquares(); static int TestLUSolveLinearSystemEstimateMatrixCondition(); static int TestJacobiN(); static int TestClampValue(); static int TestClampValues(); static int TestClampAndNormalizeValue(); static int TestTensorFromSymmetricTensor(); static int TestGetScalarTypeFittingRange(); static int TestGetAdjustedScalarRange(); static int TestExtentIsWithinOtherExtent(); static int TestBoundsIsWithinOtherBounds(); static int TestPointIsWithinBounds(); static int TestSolve3PointCircle(); static int TestRGBToHSV(); static int TestInf(); static int TestNegInf(); static int TestNan(); static int TestMetaMultiplyMatrix(); static int TestMetaMultiplyMatrixWithVector(); static int TestMetaDot(); static int TestMetaDeterminant(); static int TestMetaInvertMatrix(); static int TestMetaLinearSolve(); int UnitTestMath(int, char*[]) { int status = 0; status += TestPi(); status += TestDegreesFromRadians(); status += TestRound(); status += TestFloor(); status += TestCeil(); status += TestCeilLog2(); status += TestIsPowerOfTwo(); status += TestNearestPowerOfTwo(); status += TestFactorial(); status += TestBinomial(); status += TestRandom(); status += TestAddSubtract(); status += TestMultiplyScalar(); status += TestMultiplyScalar2D(); status += TestDot(); status += TestOuter(); status += TestCross(); status += TestNorm(); status += TestNormalize(); status += TestPerpendiculars(); status += TestProjectVector(); status += TestProjectVector2D(); status += TestDistance2BetweenPoints(); status += TestAngleBetweenVectors(); status += TestGaussianAmplitude(); status += TestGaussianWeight(); status += TestDot2D(); status += TestNorm2D(); status += TestNormalize2D(); status += TestDeterminant2x2(); status += TestDeterminant3x3(); status += TestLUFactor3x3(); status += TestLUSolve3x3(); status += TestLinearSolve3x3(); status += TestMultiply3x3(); status += TestMultiplyMatrix(); status += TestTranspose3x3(); status += TestInvert3x3(); status += TestInvertMatrix(); status += TestIdentity3x3(); status += TestQuaternionToMatrix3x3(); status += TestMatrix3x3ToQuaternion(); status += TestMultiplyQuaternion(); status += TestOrthogonalize3x3(); status += TestDiagonalize3x3(); status += TestSingularValueDecomposition3x3(); status += TestSolveLinearSystem(); status += TestSolveLeastSquares(); status += TestSolveHomogeneousLeastSquares(); status += TestLUSolveLinearSystemEstimateMatrixCondition(); status += TestJacobiN(); status += TestClampValue(); status += TestClampValues(); status += TestClampAndNormalizeValue(); status += TestTensorFromSymmetricTensor(); status += TestGetScalarTypeFittingRange(); status += TestGetAdjustedScalarRange(); status += TestExtentIsWithinOtherExtent(); status += TestBoundsIsWithinOtherBounds(); status += TestPointIsWithinBounds(); status += TestSolve3PointCircle(); status += TestRGBToHSV(); status += TestInf(); status += TestNegInf(); status += TestNan(); status += TestMetaMultiplyMatrix(); status += TestMetaMultiplyMatrixWithVector(); status += TestMetaDot(); status += TestMetaDeterminant(); status += TestMetaInvertMatrix(); status += TestMetaLinearSolve(); if (status != 0) { return EXIT_FAILURE; } vtkSmartPointer math = vtkSmartPointer::New(); math->Print(std::cout); return EXIT_SUCCESS; } // Validate by comparing to atan/4 int TestPi() { int status = 0; std::cout << "Pi.."; if (vtkMath::Pi() != std::atan(1.0) * 4.0) { std::cout << "Expected " << vtkMath::Pi() << " but got " << std::atan(1.0) * 4.0; ++status; } if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } // Validate against RadiansFromDegrees int TestDegreesFromRadians() { int status = 0; std::cout << "DegreesFromRadians.."; unsigned int numSamples = 1000; for (unsigned int i = 0; i < numSamples; ++i) { float floatDegrees = vtkMath::Random(-180.0, 180.0); float floatRadians = vtkMath::RadiansFromDegrees(floatDegrees); float result = vtkMath::DegreesFromRadians(floatRadians); if (!vtkMathUtilities::FuzzyCompare( result, floatDegrees, std::numeric_limits::epsilon() * 128.0f)) { std::cout << "Float Expected " << floatDegrees << " but got " << result << " difference is " << result - floatDegrees << " "; std::cout << "eps ratio is: " << (result - floatDegrees) / std::numeric_limits::epsilon() << std::endl; ++status; } } for (unsigned int i = 0; i < numSamples; ++i) { double doubleDegrees = vtkMath::Random(-180.0, 180.0); double doubleRadians = vtkMath::RadiansFromDegrees(doubleDegrees); double result = vtkMath::DegreesFromRadians(doubleRadians); if (!vtkMathUtilities::FuzzyCompare( result, doubleDegrees, std::numeric_limits::epsilon() * 256.0)) { std::cout << " Double Expected " << doubleDegrees << " but got " << result << " difference is " << result - doubleDegrees; std::cout << " eps ratio is: " << (result - doubleDegrees) / std::numeric_limits::epsilon() << std::endl; ++status; } } if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } // Validate with http://en.wikipedia.org/wiki/Rounding#Rounding_to_integer int TestRound() { int status = 0; std::cout << "Round.."; int result; { std::vector values; std::vector expecteds; values.push_back(23.67f); expecteds.push_back(24); values.push_back(23.50f); expecteds.push_back(24); values.push_back(23.35f); expecteds.push_back(23); values.push_back(23.00f); expecteds.push_back(23); values.push_back(0.00f); expecteds.push_back(0); values.push_back(-23.00f); expecteds.push_back(-23); values.push_back(-23.35f); expecteds.push_back(-23); values.push_back(-23.50f); expecteds.push_back(-24); values.push_back(-23.67f); expecteds.push_back(-24); for (size_t i = 0; i < values.size(); ++i) { result = vtkMath::Round(values[i]); if (result != expecteds[i]) { std::cout << " Float Round(" << values[i] << ") got " << result << " but expected " << expecteds[i]; ++status; } } } { std::vector values; std::vector expecteds; values.push_back(23.67); expecteds.push_back(24); values.push_back(23.50); expecteds.push_back(24); values.push_back(23.35); expecteds.push_back(23); values.push_back(23.00); expecteds.push_back(23); values.push_back(0.00); expecteds.push_back(0); values.push_back(-23.00); expecteds.push_back(-23); values.push_back(-23.35); expecteds.push_back(-23); values.push_back(-23.50); expecteds.push_back(-24); values.push_back(-23.67); expecteds.push_back(-24); for (size_t i = 0; i < values.size(); ++i) { result = vtkMath::Round(values[i]); if (result != expecteds[i]) { std::cout << " Double Round(" << values[i] << ") got " << result << " but expected " << expecteds[i]; ++status; } } } if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } // Validate with http://en.wikipedia.org/wiki/Floor_and_ceiling_functions int TestFloor() { int status = 0; std::cout << "Floor.."; int result; std::vector values; std::vector expecteds; values.push_back(2.4); expecteds.push_back(2); values.push_back(2.7); expecteds.push_back(2); values.push_back(-2.7); expecteds.push_back(-3); values.push_back(-2.0); expecteds.push_back(-2); for (size_t i = 0; i < values.size(); ++i) { result = vtkMath::Floor(values[i]); if (result != expecteds[i]) { std::cout << " Floor(" << values[i] << ") got " << result << " but expected " << expecteds[i]; ++status; } } if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } // Validate with http://en.wikipedia.org/wiki/Floor_and_ceiling_functions int TestCeil() { int status = 0; std::cout << "Ceil.."; int result; std::vector values; std::vector expecteds; values.push_back(2.4); expecteds.push_back(3); values.push_back(2.7); expecteds.push_back(3); values.push_back(-2.7); expecteds.push_back(-2); values.push_back(-2.0); expecteds.push_back(-2); for (size_t i = 0; i < values.size(); ++i) { result = vtkMath::Ceil(values[i]); if (result != expecteds[i]) { std::cout << " Ceil(" << values[i] << ") got " << result << " but expected " << expecteds[i]; ++status; } } if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } // Validate by powers of 2 perturbations int TestCeilLog2() { int status = 0; std::cout << "CeilLog2.."; int result; std::vector values; std::vector expecteds; for (unsigned int p = 0; p < 30; ++p) { vtkTypeUInt64 shifted = (2 << p) + 1; values.push_back(shifted); expecteds.push_back(p + 2); shifted = (2 << p); values.push_back(shifted); expecteds.push_back(p + 1); } for (size_t i = 0; i < values.size(); ++i) { result = vtkMath::CeilLog2(values[i]); if (result != expecteds[i]) { std::cout << " CeilLog2(" << values[i] << ") got " << result << " but expected " << expecteds[i]; ++status; } } if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } // Validate by powers of 2 perturbations int TestIsPowerOfTwo() { int status = 0; std::cout << "IsPowerOfTwo.."; bool result; std::vector values; std::vector expecteds; int largestPower = std::numeric_limits::digits; vtkTypeUInt64 shifted = 1; for (int p = 1; p < largestPower - 1; ++p) { shifted *= 2; values.push_back(shifted); expecteds.push_back(true); if (shifted != 2) { values.push_back(shifted - 1); expecteds.push_back(false); } if (shifted < std::numeric_limits::max() - 1) { values.push_back(shifted + 1); expecteds.push_back(false); } } for (size_t i = 0; i < values.size(); ++i) { result = vtkMath::IsPowerOfTwo(values[i]); if (result != expecteds[i]) { std::cout << " IsPowerOfTwo(" << values[i] << ") got " << result << " but expected " << expecteds[i]; ++status; } } if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } // Validate by powers of 2 perturbations int TestNearestPowerOfTwo() { int status = 0; std::cout << "NearestPowerOfTwo.."; std::vector values; std::vector expecteds; values.push_back(0); expecteds.push_back(1); int numDigits = std::numeric_limits::digits; vtkTypeUInt64 shifted = 1; for (int p = 0; p < numDigits; ++p) { values.push_back(shifted); expecteds.push_back(shifted); if (shifted <= INT_MAX / 2) { values.push_back(shifted + 1); expecteds.push_back(shifted * 2); } if (shifted != 2) { values.push_back(shifted - 1); expecteds.push_back(shifted); } shifted *= 2; } values.push_back(INT_MAX); expecteds.push_back(INT_MIN); for (size_t i = 0; i < values.size(); ++i) { int result = vtkMath::NearestPowerOfTwo(values[i]); if (result != expecteds[i]) { std::cout << " NearestPowerOfTwo(" << values[i] << ") got " << result << " but expected " << expecteds[i]; ++status; } } if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } // Validate by alternate computation int TestFactorial() { int status = 0; std::cout << "Factorial.."; std::vector values; std::vector expecteds; vtkTypeInt64 expected = 1; for (int f = 2; f < 10; ++f) { expected *= f; values.push_back(f); expecteds.push_back(expected); } for (size_t i = 0; i < values.size(); ++i) { int result = vtkMath::Factorial(values[i]); if (result != expecteds[i]) { std::cout << " Factorial(" << values[i] << ") got " << result << " but expected " << expecteds[i]; ++status; } } if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } // Validate by alternative computations int TestBinomial() { int status = 0; int m; int n; std::cout << "Binomial.."; std::vector mvalues; std::vector nvalues; std::vector expecteds; double expected; for (m = 1; m < 31; ++m) { for (n = 1; n <= m; ++n) { mvalues.push_back(m); nvalues.push_back(n); expected = 1; for (int i = 1; i <= n; ++i) { expected *= static_cast(m - i + 1) / i; } expecteds.push_back(static_cast(expected)); } } for (size_t i = 0; i < mvalues.size(); ++i) { int result = vtkMath::Binomial(mvalues[i], nvalues[i]); if (result != expecteds[i]) { std::cout << " Binomial(" << mvalues[i] << ", " << nvalues[i] << ") got " << result << " but expected " << expecteds[i]; ++status; } } // Now test the combination iterator m = 6; n = 3; int more = 1; int count = 0; int* comb; // First, m < n should produce 0 comb = vtkMath::BeginCombination(n, m); if (comb != nullptr) { ++status; std::cout << " Combinations(" << n << ", " << m << ") should return 0 " << " but got " << comb; } comb = vtkMath::BeginCombination(m, n); while (more) { ++count; more = vtkMath::NextCombination(m, n, comb); } vtkMath::FreeCombination(comb); if (count != vtkMath::Binomial(m, n)) { ++status; std::cout << " Combinations(" << m << ", " << n << ") got " << count << " but expected " << vtkMath::Binomial(m, n); } if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } // No validation int TestRandom() { int status = 0; std::cout << "Random.."; // Not really a test of randomness, just covering code int n = 1000; vtkMath::RandomSeed(8775070); vtkMath::GetSeed(); // just for coverage double accum = 0.0; for (int i = 0; i < n; ++i) { float random = vtkMath::Random(); accum += random; if (random < 0.0 || random > 1.0) { std::cout << "Random(): " << random << " out of range" << std::endl; ++status; } random = vtkMath::Gaussian(); accum += random; random = vtkMath::Gaussian(0.0, 1.0); accum += random; random = vtkMath::Random(-1000.0, 1000.0); accum += random; if (random < -1000.0 || random > 1000.0) { std::cout << "Random (-1000.0, 1000.0): " << random << " out of range" << std::endl; ++status; } } if (accum == 0.0) { ++status; } if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } template int AddSubtract() { int status = 0; T da[3], db[3], dc[3], dd[3]; for (int n = 0; n < 100000; ++n) { for (int i = 0; i < 3; ++i) { da[i] = vtkMath::Random(-10.0, 10.0); db[i] = vtkMath::Random(-10.0, 10.0); } vtkMath::Add(da, db, dc); vtkMath::Subtract(dc, db, dd); for (int i = 0; i < 3; ++i) { if (!vtkMathUtilities::FuzzyCompare( da[i], dd[i], std::numeric_limits::epsilon() * (T)256.0)) { std::cout << " Add/Subtract got " << dd[i] << " but expected " << da[i]; ++status; } } } return status; } // Validate by a + b - b = a int TestAddSubtract() { int status = 0; std::cout << "AddSubtract.."; status += AddSubtract(); status += AddSubtract(); if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } template int MultiplyScalar() { int status = 0; // first T T da[3], db[3]; for (int n = 0; n < 100000; ++n) { for (int i = 0; i < 3; ++i) { da[i] = vtkMath::Random(-10.0, 10.0); db[i] = da[i]; } T scale = vtkMath::Random(); vtkMath::MultiplyScalar(da, scale); for (int i = 0; i < 3; ++i) { if (!vtkMathUtilities::FuzzyCompare( da[i], db[i] * scale, std::numeric_limits::epsilon() * (T)256.0)) { std::cout << " MultiplyScalar got " << da[i] << " but expected " << db[i] * scale; ++status; } } } return status; } int TestMultiplyScalar() { int status = 0; std::cout << "MultiplyScalar.."; status += MultiplyScalar(); status += MultiplyScalar(); if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } int TestMultiplyScalar2D() { int status = 0; std::cout << "MultiplyScalar2D.."; // now 2D // first double double da[2], db[2]; for (int n = 0; n < 100000; ++n) { for (int i = 0; i < 2; ++i) { da[i] = vtkMath::Random(-10.0, 10.0); db[i] = da[i]; } double scale = vtkMath::Random(); vtkMath::MultiplyScalar2D(da, scale); for (int i = 0; i < 2; ++i) { if (!vtkMathUtilities::FuzzyCompare( da[i], db[i] * scale, std::numeric_limits::epsilon() * 256.0)) { std::cout << " MultiplyScalar2D got " << da[i] << " but expected " << db[i] * scale; ++status; } } } // then float float fa[2], fb[2]; for (int n = 0; n < 100000; ++n) { for (int i = 0; i < 2; ++i) { fa[i] = vtkMath::Random(-10.0, 10.0); fb[i] = fa[i]; } float scale = vtkMath::Random(); vtkMath::MultiplyScalar2D(fa, scale); for (int i = 0; i < 2; ++i) { if (!vtkMathUtilities::FuzzyCompare( fa[i], fb[i] * scale, std::numeric_limits::epsilon() * 256.0f)) { std::cout << " MultiplyScalar2D got " << fa[i] << " but expected " << fb[i] * scale; ++status; } } } if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } class valueDouble3D { public: valueDouble3D() = default; valueDouble3D(double aa[3], double bb[3]) { for (int i = 0; i < 3; ++i) { a[i] = aa[i]; b[i] = bb[i]; } } double a[3]; double b[3]; }; class valueFloat3D { public: valueFloat3D() = default; valueFloat3D(float aa[3], float bb[3]) { for (int i = 0; i < 3; ++i) { a[i] = aa[i]; b[i] = bb[i]; } } float a[3]; float b[3]; }; int TestDot() { int status = 0; std::cout << "Dot.."; { std::vector values; std::vector expecteds; for (int n = 0; n < 100; ++n) { valueDouble3D v; double dot = 0.0; for (int i = 0; i < 3; ++i) { v.a[i] = vtkMath::Random(); v.b[i] = vtkMath::Random(); dot += (v.a[i] * v.b[i]); } values.push_back(v); expecteds.push_back(dot); } valueDouble3D test; test.a[0] = 0.0; test.a[1] = 0.0; test.a[2] = 1.0; test.b[0] = 1.0; test.b[1] = 0.0; test.b[2] = 0.0; values.push_back(test); expecteds.push_back(0.0); test.a[0] = 0.0; test.a[1] = 0.0; test.a[2] = 1.0; test.b[0] = 0.0; test.b[1] = 1.0; test.b[2] = 0.0; values.push_back(test); expecteds.push_back(0.0); test.a[0] = 1.0; test.a[1] = 0.0; test.a[2] = 0.0; test.b[0] = 0.0; test.b[1] = 1.0; test.b[2] = 0.0; values.push_back(test); expecteds.push_back(0.0); for (size_t i = 0; i < values.size(); ++i) { double result = vtkMath::Dot(values[i].a, values[i].b); if (!vtkMathUtilities::FuzzyCompare( result, expecteds[i], std::numeric_limits::epsilon() * 128.0)) { std::cout << " Dot got " << result << " but expected " << expecteds[i]; ++status; } } } // now float { std::vector values; std::vector expecteds; for (int n = 0; n < 100; ++n) { valueFloat3D v; float dot = 0.0; for (int i = 0; i < 3; ++i) { v.a[i] = vtkMath::Random(); v.b[i] = vtkMath::Random(); dot += (v.a[i] * v.b[i]); } values.push_back(v); expecteds.push_back(dot); } valueFloat3D test; test.a[0] = 0.0; test.a[1] = 0.0; test.a[2] = 1.0; test.b[0] = 1.0; test.b[1] = 0.0; test.b[2] = 0.0; values.push_back(test); expecteds.push_back(0.0); test.a[0] = 0.0; test.a[1] = 0.0; test.a[2] = 1.0; test.b[0] = 0.0; test.b[1] = 1.0; test.b[2] = 0.0; values.push_back(test); expecteds.push_back(0.0); test.a[0] = 1.0; test.a[1] = 0.0; test.a[2] = 0.0; test.b[0] = 0.0; test.b[1] = 1.0; test.b[2] = 0.0; values.push_back(test); expecteds.push_back(0.0); for (size_t i = 0; i < values.size(); ++i) { float result = vtkMath::Dot(values[i].a, values[i].b); if (!vtkMathUtilities::FuzzyCompare( result, expecteds[i], std::numeric_limits::epsilon() * 128.0f)) { std::cout << " Dot got " << result << " but expected " << expecteds[i]; ++status; } } } if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } int TestOuter() { int status = 0; std::cout << "Outer.."; if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } // Verify by anticommutative property template int Cross() { int status = 0; T a[3]; T b[3]; T c[3]; T d[3]; for (int n = 0; n < 1000; ++n) { for (int i = 0; i < 3; ++i) { a[i] = vtkMath::Random(-1.0, 1.0); b[i] = vtkMath::Random(-1.0, 1.0); } vtkMath::Cross(a, b, c); vtkMath::MultiplyScalar(b, (T)-1.0); vtkMath::Cross(b, a, d); // a x b = -b x a for (int i = 0; i < 3; ++i) { if (!vtkMathUtilities::FuzzyCompare(c[i], d[i], std::numeric_limits::epsilon() * (T)128.0)) { std::cout << " Cross expected " << c[i] << " but got " << d[i]; std::cout << "eps ratio is: " << (c[i] - d[i]) / std::numeric_limits::epsilon() << std::endl; ++status; } } } return status; } int TestCross() { int status = 0; std::cout << "Cross.."; status += Cross(); status += Cross(); if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } template int Norm() { int status = 0; T x[NDimension]; for (int n = 0; n < 1000; ++n) { for (int i = 0; i < NDimension; ++i) { x[i] = (T)vtkMath::Random(-10.0, 10.0); } T norm = vtkMath::Norm(x, NDimension); for (int i = 0; i < NDimension; ++i) { x[i] /= norm; } T unitNorm = vtkMath::Norm(x, NDimension); if (!vtkMathUtilities::FuzzyCompare( unitNorm, (T)1.0, std::numeric_limits::epsilon() * (T)128.0)) { std::cout << "Norm Expected " << 1.0 << " but got " << unitNorm; std::cout << " eps ratio is: " << ((T)1.0 - unitNorm) / std::numeric_limits::epsilon() << std::endl; ++status; } } return status; } int TestNorm() { int status = 0; std::cout << "Norm.."; status += Norm(); status += Norm(); status += Norm(); status += Norm(); status += Norm(); status += Norm(); if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } // Validate compute Norm, should be 1.0 template int Normalize() { int status = 0; for (int n = 0; n < 1000; ++n) { T a[3]; for (int i = 0; i < 3; ++i) { a[i] = vtkMath::Random(-10000.0, 10000.0); } vtkMath::Normalize(a); T value = vtkMath::Norm(a); T expected = 1.0; if (!vtkMathUtilities::FuzzyCompare( value, expected, std::numeric_limits::epsilon() * (T)128.0)) { std::cout << " Normalize expected " << expected << " but got " << value; std::cout << "eps ratio is: " << value - expected / std::numeric_limits::epsilon() << std::endl; ++status; } } return status; } int TestNormalize() { int status = 0; std::cout << "Normalize.."; status += Normalize(); status += Normalize(); if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } int TestPerpendiculars() { int status = 0; std::cout << "Perpendiculars.."; { // first double double x[3], y[3], z[3]; std::vector values; std::vector expecteds; for (int n = 0; n < 100; ++n) { for (int i = 0; i < 3; ++i) { x[i] = vtkMath::Random(-10.0, 10.0); } vtkMath::Perpendiculars(x, y, z, vtkMath::Random(-vtkMath::Pi(), vtkMath::Pi())); { valueDouble3D value(x, y); values.push_back(value); expecteds.push_back(0.0); } { valueDouble3D value(x, z); values.push_back(value); expecteds.push_back(0.0); } { valueDouble3D value(y, z); values.push_back(value); expecteds.push_back(0.0); } vtkMath::Perpendiculars(x, y, z, 0.0); { valueDouble3D value(x, y); values.push_back(value); expecteds.push_back(0.0); } } for (size_t i = 0; i < values.size(); ++i) { double test = vtkMath::Dot(values[i].a, values[i].b); if (!vtkMathUtilities::FuzzyCompare( expecteds[i], test, std::numeric_limits::epsilon() * 256.0)) { std::cout << " Perpendiculars got " << test << " but expected " << expecteds[i]; ++status; } } } { // then floats float x[3], y[3], z[3]; std::vector values; std::vector expecteds; for (int n = 0; n < 100; ++n) { for (int i = 0; i < 3; ++i) { x[i] = vtkMath::Random(-10.0, 10.0); } vtkMath::Perpendiculars(x, y, z, vtkMath::Random(-vtkMath::Pi(), vtkMath::Pi())); { valueFloat3D value(x, y); values.push_back(value); expecteds.push_back(0.0); } { valueFloat3D value(x, z); values.push_back(value); expecteds.push_back(0.0); } { valueFloat3D value(y, z); values.push_back(value); expecteds.push_back(0.0); } vtkMath::Perpendiculars(x, y, z, 0.0); { valueFloat3D value(x, y); values.push_back(value); expecteds.push_back(0.0); } } for (size_t i = 0; i < values.size(); ++i) { float test = vtkMath::Dot(values[i].a, values[i].b); if (!vtkMathUtilities::FuzzyCompare( expecteds[i], test, std::numeric_limits::epsilon() * 256.0f)) { std::cout << " Perpendiculars got " << test << " but expected " << expecteds[i]; ++status; } } } if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } template int ProjectVector() { int status = 0; T a[3], b[3], c[3]; for (int i = 0; i < 3; ++i) { a[i] = 0.0; b[i] = 0.0; } if (vtkMath::ProjectVector(a, b, c)) { std::cout << "ProjectVector of a 0 vector should return false "; ++status; } return status; } // Validate 0 vector case. TestMath does the rest int TestProjectVector() { int status = 0; std::cout << "ProjectVector.."; status += ProjectVector(); status += ProjectVector(); if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } template int ProjectVector2D() { int status = 0; T a[2], b[2], c[2]; for (int i = 0; i < 2; ++i) { a[i] = 0.0; b[i] = 0.0; } if (vtkMath::ProjectVector2D(a, b, c)) { std::cout << "ProjectVector2D of a 0 vector should return false "; ++status; } return status; } // Validate 0 vector case. TestMath does the rest int TestProjectVector2D() { int status = 0; std::cout << "ProjectVector2D.."; status += ProjectVector2D(); status += ProjectVector2D(); if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } int TestDistance2BetweenPoints() { int status = 0; std::cout << "Distance2BetweenPoints.."; if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } int TestAngleBetweenVectors() { int status = 0; std::cout << "AngleBetweenVectors.."; if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } int TestGaussianAmplitude() { int status = 0; std::cout << "GaussianAmplitude.."; if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } int TestGaussianWeight() { int status = 0; std::cout << "GaussianWeight.."; if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } class valueDouble2D { public: double a[2]; double b[2]; }; class valueFloat2D { public: float a[2]; float b[2]; }; int TestDot2D() { int status = 0; std::cout << "Dot2D.."; { std::vector values; std::vector expecteds; for (int n = 0; n < 100; ++n) { valueDouble2D v; double dot = 0.0; for (int i = 0; i < 2; ++i) { v.a[i] = vtkMath::Random(); v.b[i] = vtkMath::Random(); dot += (v.a[i] * v.b[i]); } values.push_back(v); expecteds.push_back(dot); } valueDouble2D test; test.a[0] = 1.0; test.a[1] = 0.0; test.b[0] = 0.0; test.b[1] = 1.0; values.push_back(test); expecteds.push_back(0.0); for (size_t i = 0; i < values.size(); ++i) { double result = vtkMath::Dot2D(values[i].a, values[i].b); if (!vtkMathUtilities::FuzzyCompare( result, expecteds[i], std::numeric_limits::epsilon() * 128.0)) { std::cout << " Dot got " << result << " but expected " << expecteds[i]; ++status; } } } // now float { std::vector values; std::vector expecteds; for (int n = 0; n < 100; ++n) { valueFloat2D v; float dot = 0.0; for (int i = 0; i < 2; ++i) { v.a[i] = vtkMath::Random(); v.b[i] = vtkMath::Random(); dot += (v.a[i] * v.b[i]); } values.push_back(v); expecteds.push_back(dot); } valueFloat2D test; test.a[0] = 0.0; test.a[1] = 1.0; test.b[0] = 1.0; test.b[1] = 0.0; values.push_back(test); expecteds.push_back(0.0); for (size_t i = 0; i < values.size(); ++i) { float result = vtkMath::Dot2D(values[i].a, values[i].b); if (!vtkMathUtilities::FuzzyCompare( result, expecteds[i], std::numeric_limits::epsilon() * 128.0f)) { std::cout << " Dot got " << result << " but expected " << expecteds[i]; ++status; } } } if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } int TestNorm2D() { int status = 0; std::cout << "Norm2D.."; if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } int TestNormalize2D() { int status = 0; std::cout << "Normalize2D.."; if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } int TestDeterminant2x2() { int status = 0; std::cout << "Determinant2x2.."; // Frank Matrix { double a[2][2]; for (int i = 1; i <= 2; ++i) { for (int j = 1; j <= 2; ++j) { if (j < i - 2) { a[i - 1][j - 1] = 0.0; } else if (j == (i - 1)) { a[i - 1][j - 1] = 2 + 1 - i; } else { a[i - 1][j - 1] = 2 + 1 - j; } } } if (vtkMath::Determinant2x2(a[0], a[1]) != 1.0) { std::cout << "Determinant2x2 expected " << 1.0 << " but got " << vtkMath::Determinant2x2(a[0], a[1]) << std::endl; ++status; } } { float a[2][2]; for (int i = 1; i <= 2; ++i) { for (int j = 1; j <= 2; ++j) { if (j < i - 2) { a[i - 1][j - 1] = 0.0; } else if (j == (i - 1)) { a[i - 1][j - 1] = 2 + 1 - i; } else { a[i - 1][j - 1] = 2 + 1 - j; } } } if (vtkMath::Determinant2x2(a[0], a[1]) != 1.0) { std::cout << "Determinant2x2 expected " << 1.0 << " but got " << vtkMath::Determinant2x2(a[0], a[1]) << std::endl; ++status; } } if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } int TestDeterminant3x3() { int status = 0; std::cout << "Determinant3x3.."; // Frank Matrix { double a[3][3]; for (int i = 1; i <= 3; ++i) { for (int j = 1; j <= 3; ++j) { if (j < i - 3) { a[i - 1][j - 1] = 0.0; } else if (j == (i - 1)) { a[i - 1][j - 1] = 3 + 1 - i; } else { a[i - 1][j - 1] = 3 + 1 - j; } } } if (vtkMath::Determinant3x3(a[0], a[1], a[2]) != 1.0) { std::cout << "Determinant3x3 expected " << 1.0 << " but got " << vtkMath::Determinant3x3(a[0], a[1], a[2]) << std::endl; ++status; } } { float a[3][3]; for (int i = 1; i <= 3; ++i) { for (int j = 1; j <= 3; ++j) { if (j < i - 3) { a[i - 1][j - 1] = 0.0; } else if (j == (i - 1)) { a[i - 1][j - 1] = 3 + 1 - i; } else { a[i - 1][j - 1] = 3 + 1 - j; } } } if (vtkMath::Determinant3x3(a[0], a[1], a[2]) != 1.0) { std::cout << "Determinant3x3 expected " << 1.0 << " but got " << vtkMath::Determinant3x3(a[0], a[1], a[2]) << std::endl; ++status; } } if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } template int LUFactor3x3() { int status = 0; T A[3][3]; int index[3]; for (int n = 0; n < 1000; ++n) { for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { A[i][j] = vtkMath::Random(-10.0, 10.0); } } vtkMath::LUFactor3x3(A, index); } return status; } // Just for coverage, validated as part of TestLUSolve3x3 int TestLUFactor3x3() { int status = 0; std::cout << "LUFactor3x3.."; status += LUFactor3x3(); if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } template int LUSolve3x3() { int status = 0; // Generate a Hilbert Matrix T mat[3][3]; int index[3]; T lhs[3]; T rhs[3]; for (int n = 0; n < 1000; ++n) { for (int i = 0; i < 3; ++i) { lhs[i] = vtkMath::Random(-1.0, 1.0); } for (int i = 1; i <= 3; ++i) { rhs[i - 1] = 0.0; for (int j = 1; j <= 3; ++j) { mat[i - 1][j - 1] = 1.0 / (i + j - 1); rhs[i - 1] += (mat[i - 1][j - 1] * lhs[j - 1]); } } vtkMath::LUFactor3x3(mat, index); vtkMath::LUSolve3x3(mat, index, rhs); for (int i = 0; i < 3; ++i) { if (!vtkMathUtilities::FuzzyCompare( lhs[i], rhs[i], std::numeric_limits::epsilon() * (T)256.0)) { std::cout << " LUSolve3x3(T) expected " << lhs[i] << " but got " << rhs[i]; ++status; } } } return status; } int TestLUSolve3x3() { int status = 0; std::cout << "LUSolve3x3.."; status += LUSolve3x3(); status += LUSolve3x3(); if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } template int LinearSolve3x3() { int status = 0; // Generate a Hilbert Matrix T mat[3][3]; T lhs[3]; T rhs[3]; T solution[3]; for (int n = 0; n < 2; ++n) { for (int i = 0; i < 3; ++i) { lhs[i] = vtkMath::Random(-1.0, 1.0); } for (int i = 1; i <= 3; ++i) { rhs[i - 1] = 0.0; for (int j = 1; j <= 3; ++j) { mat[i - 1][j - 1] = 1.0 / (i + j - 1); rhs[i - 1] += (mat[i - 1][j - 1] * lhs[j - 1]); } } vtkMath::LinearSolve3x3(mat, rhs, solution); for (int i = 0; i < 3; ++i) { if (!vtkMathUtilities::FuzzyCompare( lhs[i], solution[i], std::numeric_limits::epsilon() * (T)512.0)) { std::cout << " LinearSolve3x3(T) expected " << lhs[i] << " but got " << solution[i]; ++status; } } } return status; } int TestLinearSolve3x3() { int status = 0; std::cout << "LinearSolve3x3.."; status += LinearSolve3x3(); status += LinearSolve3x3(); if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } template int Multiply3x3() { int status = 0; T A[3][3]; T V[3]; T U[3]; for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { A[i][j] = vtkMath::Random(-10.0, 10.0); } V[i] = vtkMath::Random(-10.0, 10.0); } vtkMath::Multiply3x3(A, V, U); return status; } int TestMultiply3x3() { int status = 0; std::cout << "Multiply3x3.."; status += Multiply3x3(); status += Multiply3x3(); if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } // For coverage only. Validated as part of TestInvertMatrix int TestMultiplyMatrix() { int status = 0; std::cout << "MultiplyMatrix.."; double a[3][3] = { { 1.0, 2.0, 3.0 }, { 4.0, 5.0, 6.0 }, { 7.0, 8.0, 9.0 } }; double b[3][3] = { { 1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 } }; double c[3][3]; double* aa[3]; double* bb[3]; double* cc[3]; for (int i = 0; i < 3; ++i) { aa[i] = a[i]; bb[i] = b[i]; cc[i] = c[i]; } vtkMath::MultiplyMatrix(aa, bb, 3, 3, 3, 3, cc); // WARNING: Number of columns of A must match number of rows of B. vtkMath::MultiplyMatrix(aa, bb, 3, 2, 3, 3, cc); if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } int TestTranspose3x3() { int status = 0; std::cout << "Transpose3x3.."; if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } int TestInvert3x3() { int status = 0; std::cout << "Invert3x3.."; { // Generate a Hilbert Matrix double mat[3][3]; double matI[3][3]; double expected[3][3] = { { 9.0, -36.0, 30.0 }, { -36.0, 192.0, -180.0 }, { 30.0, -180.0, 180.0 } }; for (int i = 1; i <= 3; ++i) { for (int j = 1; j <= 3; ++j) { mat[i - 1][j - 1] = 1.0 / (i + j - 1); } } vtkMath::Invert3x3(mat, matI); for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { if (!vtkMathUtilities::FuzzyCompare( matI[i][j], expected[i][j], std::numeric_limits::epsilon() * 16384.0)) { std::cout << " Invert3x3(double) expected " << expected[i][j] << " but got " << matI[i][j]; ++status; } } } } { // Generate a Hilbert Matrix float mat[3][3]; float matI[3][3]; float expected[3][3] = { { 9.0f, -36.0f, 30.0f }, { -36.0f, 192.0f, -180.0f }, { 30.0f, -180.0f, 180.0f } }; for (int i = 1; i <= 3; ++i) { for (int j = 1; j <= 3; ++j) { mat[i - 1][j - 1] = 1.0 / (i + j - 1); } } vtkMath::Invert3x3(mat, matI); for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { if (!vtkMathUtilities::FuzzyCompare( matI[i][j], expected[i][j], std::numeric_limits::epsilon() * 8192.0f)) { std::cout << " Invert3x3(single) expected " << expected[i][j] << " but got " << matI[i][j]; ++status; } } } } if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } template int InvertMatrix() { int status = 0; // Generate a Hilbert Matrix T** mat = new T*[NDimension]; T** orig = new T*[NDimension]; T** matI = new T*[NDimension]; T** ident = new T*[NDimension]; int* tmp1 = new int[NDimension]; T* tmp2 = new T[NDimension]; for (int i = 1; i <= NDimension; ++i) { mat[i - 1] = new T[NDimension]; matI[i - 1] = new T[NDimension]; orig[i - 1] = new T[NDimension]; ident[i - 1] = new T[NDimension]; for (int j = 1; j <= NDimension; ++j) { orig[i - 1][j - 1] = mat[i - 1][j - 1] = 1.0 / (i + j - 1); } } if (vtkMath::InvertMatrix(mat, matI, NDimension, tmp1, tmp2) == 0) { delete[] mat; delete[] orig; delete[] matI; delete[] ident; delete[] tmp1; delete[] tmp2; return status; } vtkMath::MultiplyMatrix(orig, matI, NDimension, NDimension, NDimension, NDimension, ident); T expected; for (int i = 0; i < NDimension; ++i) { for (int j = 0; j < NDimension; ++j) { if (i == j) { expected = 1.0; } else { expected = 0.0; } if (!vtkMathUtilities::FuzzyCompare( *(ident[i] + j), expected, std::numeric_limits::epsilon() * (T)100000.0)) { std::cout << " InvertMatrix(T) expected " << expected << " but got " << *(ident[i] + j); std::cout << "eps ratio is: " << (*(ident[i] + j) - expected) / std::numeric_limits::epsilon() << std::endl; ++status; } } } for (int i = 0; i < NDimension; i++) { delete[] mat[i]; delete[] orig[i]; delete[] matI[i]; delete[] ident[i]; } delete[] mat; delete[] orig; delete[] matI; delete[] ident; delete[] tmp1; delete[] tmp2; return status; } int TestInvertMatrix() { int status = 0; status += InvertMatrix(); status += InvertMatrix(); status += InvertMatrix(); if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } int TestIdentity3x3() { int status = 0; std::cout << "Identity3x3.."; double m[3][3]; vtkMath::Identity3x3(m); double expected; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (i == j) { expected = 1.0; } else { expected = 0.0; } if (expected != m[i][j]) { std::cout << " Identity expected " << expected << " but got " << m[i][j] << std::endl; ++status; } } } if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } template int Matrix3x3ToQuaternion() { int status = 0; T A[3][3]; T quat[4]; for (int n = 0; n < 1000; ++n) { for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { A[i][j] = vtkMath::Random(-1.0, 1.0); } } vtkMath::Matrix3x3ToQuaternion(A, quat); } return status; } int TestMatrix3x3ToQuaternion() { int status = 0; std::cout << "Matrix3x3ToQuaternion.."; status += Matrix3x3ToQuaternion(); status += Matrix3x3ToQuaternion(); if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } template int QuaternionToMatrix3x3() { int status = 0; T A[3][3]; T quat[4]; for (int n = 0; n < 1000; ++n) { quat[0] = vtkMath::Random(-vtkMath::Pi(), vtkMath::Pi()); for (int i = 1; i < 4; ++i) { quat[i] = vtkMath::Random(-10.0, 10.0); } vtkMath::QuaternionToMatrix3x3(quat, A); } return status; } int TestQuaternionToMatrix3x3() { int status = 0; std::cout << "QuaternionToMatrix3x3.."; status += QuaternionToMatrix3x3(); status += QuaternionToMatrix3x3(); if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } template int MultiplyQuaternion() { int status = 0; T q1[4]; T q2[4]; T q3[4]; for (int n = 0; n < 1000; ++n) { q1[0] = vtkMath::Random(-vtkMath::Pi(), vtkMath::Pi()); q2[0] = vtkMath::Random(-vtkMath::Pi(), vtkMath::Pi()); vtkMath::MultiplyQuaternion(q1, q2, q3); } return status; } int TestMultiplyQuaternion() { int status = 0; std::cout << "MultiplyQuaternion.."; status += MultiplyQuaternion(); status += MultiplyQuaternion(); if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } int TestOrthogonalize3x3() { int status = 0; std::cout << "Orthogonalize3x3.."; { // Generate a random matrix double mat[3][3]; double matO[3][3]; double matI[3][3]; for (int n = 0; n < 1000; ++n) { for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { mat[i][j] = vtkMath::Random(); } } vtkMath::Orthogonalize3x3(mat, matO); vtkMath::Transpose3x3(matO, mat); vtkMath::Multiply3x3(mat, matO, matI); double identity[3][3]; vtkMath::Identity3x3(identity); for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { if (!vtkMathUtilities::FuzzyCompare( matI[i][j], identity[i][j], std::numeric_limits::epsilon() * 128.0)) { std::cout << " Orthogonalize3x3 expected " << identity[i][j] << " but got " << matI[i][j]; ++status; } } } } } { // Generate a random matrix float mat[3][3]; float matO[3][3]; float matI[3][3]; for (int n = 0; n < 1000; ++n) { for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { mat[i][j] = vtkMath::Random(); } } vtkMath::Orthogonalize3x3(mat, matO); vtkMath::Transpose3x3(matO, mat); vtkMath::Multiply3x3(mat, matO, matI); float identity[3][3]; vtkMath::Identity3x3(identity); for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { if (!vtkMathUtilities::FuzzyCompare( matI[i][j], identity[i][j], std::numeric_limits::epsilon() * 128.0f)) { std::cout << " Orthogonalize3x3 expected " << identity[i][j] << " but got " << matI[i][j]; ++status; } } } } } if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } template int Diagonalize3x3() { int status = 0; T mat[3][3]; T eigenVector[3][3], eigenVectorT[3][3]; T temp[3][3]; T result[3][3]; T eigen[3]; for (int n = 0; n < 0; ++n) { for (int i = 0; i < 3; ++i) { for (int j = i; j < 3; ++j) { mat[i][j] = mat[j][i] = vtkMath::Random(-1.0, 1.0); } } vtkMath::Diagonalize3x3(mat, eigen, eigenVector); // Pt * A * P = diagonal matrix with eigenvalues on diagonal vtkMath::Multiply3x3(mat, eigenVector, temp); vtkMath::Invert3x3(eigenVector, eigenVectorT); vtkMath::Multiply3x3(eigenVectorT, temp, result); T expected; for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { if (i == j) { expected = eigen[i]; } else { expected = 0.0; } if (!vtkMathUtilities::FuzzyCompare( result[i][j], expected, std::numeric_limits::epsilon() * (T)128.0)) { std::cout << " Diagonalize3x3 expected " << expected << " but got " << result[i][j]; ++status; } } } } // Now test for 2 and 3 equal eigenvalues vtkMath::Identity3x3(mat); mat[0][0] = 5.0; mat[1][1] = 5.0; mat[2][2] = 1.0; vtkMath::Diagonalize3x3(mat, eigen, eigenVector); std::cout << "eigen: " << eigen[0] << "," << eigen[1] << "," << eigen[2] << std::endl; vtkMath::Identity3x3(mat); mat[0][0] = 2.0; mat[1][1] = 2.0; mat[2][2] = 2.0; vtkMath::Diagonalize3x3(mat, eigen, eigenVector); std::cout << "eigen: " << eigen[0] << "," << eigen[1] << "," << eigen[2] << std::endl; return status; } // Validate Pt * A * P = diagonal matrix with eigenvalues on diagonal int TestDiagonalize3x3() { int status = 0; std::cout << "Diagonalize3x3.."; status += Diagonalize3x3(); status += Diagonalize3x3(); if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } template int SingularValueDecomposition3x3() { int status = 0; T a[3][3]; T orig[3][3]; T u[3][3]; T w[3]; T vt[3][3]; for (int n = 0; n < 1000; ++n) { for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { orig[i][j] = a[i][j] = vtkMath::Random(-10.0, 10.0); } } vtkMath::SingularValueDecomposition3x3(a, u, w, vt); T m[3][3]; T W[3][3]; vtkMath::Identity3x3(W); W[0][0] = w[0]; W[1][1] = w[1]; W[2][2] = w[2]; vtkMath::Multiply3x3(u, W, m); vtkMath::Multiply3x3(m, vt, m); for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { if (!vtkMathUtilities::FuzzyCompare( m[i][j], orig[i][j], std::numeric_limits::epsilon() * (T)128.0)) { std::cout << " SingularValueDecomposition3x3 expected " << orig[i][j] << " but got " << m[i][j]; std::cout << " eps ratio is: " << (m[i][j] - orig[i][j]) / std::numeric_limits::epsilon() << std::endl; ++status; } } } } return status; } // Validate u * w * vt = m int TestSingularValueDecomposition3x3() { int status = 0; std::cout << "SingularValueDecomposition3x3.."; status += SingularValueDecomposition3x3(); status += SingularValueDecomposition3x3(); if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } template int SolveLinearSystem() { int status = 0; for (int n = 0; n < 100; ++n) { // Generate a Random Matrix T** mat = new T*[NDimension]; T* lhs = new T[NDimension]; T* rhs = new T[NDimension]; for (int i = 0; i < NDimension; ++i) { mat[i] = new T[NDimension]; lhs[i] = vtkMath::Random(-1.0, 1.0); for (int j = 0; j < NDimension; ++j) { *(mat[i] + j) = vtkMath::Random(-1.0, 1.0); } } for (int i = 0; i < NDimension; ++i) { rhs[i] = 0.0; for (int j = 0; j < NDimension; ++j) { rhs[i] += (*(mat[i] + j) * lhs[j]); } } vtkMath::SolveLinearSystem(mat, rhs, NDimension); for (int i = 0; i < NDimension; ++i) { if (!vtkMathUtilities::FuzzyCompare( lhs[i], rhs[i], std::numeric_limits::epsilon() * 32768.0)) { std::cout << " SolveLinearSystem(double) expected " << lhs[i] << " but got " << rhs[i]; std::cout << " eps ratio is: " << (lhs[i] - rhs[i]) / std::numeric_limits::epsilon() << std::endl; ++status; } } if (NDimension == 1 || NDimension == 2) { for (int i = 0; i < NDimension; ++i) { for (int j = 0; j < NDimension; ++j) { *(mat[i] + j) = 0.0; } } if (vtkMath::SolveLinearSystem(mat, rhs, NDimension) != 0.0) { std::cout << " SolveLinearSystem for a zero matrix expected " << 0 << " but got 1"; ++status; } } for (int i = 0; i < NDimension; i++) { delete[] mat[i]; } delete[] mat; delete[] rhs; delete[] lhs; } return status; } // Validate with a known left hand side int TestSolveLinearSystem() { int status = 0; std::cout << "SolveLinearSystem.."; status += SolveLinearSystem(); status += SolveLinearSystem(); status += SolveLinearSystem(); status += SolveLinearSystem(); if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } // Validate with a known solution int TestSolveLeastSquares() { int status = 0; std::cout << "SolveLeastSquares.."; double** m = new double*[2]; double** x = new double*[3]; double** y = new double*[3]; for (int i = 0; i < 2; ++i) { m[i] = new double[1]; } for (int i = 0; i < 3; ++i) { x[i] = new double[2]; } x[0][0] = 1; x[0][1] = 4; x[1][0] = 1; x[1][1] = 2; x[2][0] = 2; x[2][1] = 3; for (int i = 0; i < 3; ++i) { y[i] = new double[1]; } y[0][0] = -2; y[1][0] = 6; y[2][0] = 1; vtkMath::SolveLeastSquares(3, x, 2, y, 1, m); std::vector results; std::vector expecteds; expecteds.push_back(3.0); results.push_back(m[0][0]); expecteds.push_back(-1.0); results.push_back(m[1][0]); for (size_t i = 0; i < results.size(); ++i) { if (!vtkMathUtilities::FuzzyCompare( results[i], expecteds[i], std::numeric_limits::epsilon() * 128.0)) { std::cout << " Solve Least Squares got " << results[i] << " but expected " << expecteds[i]; ++status; } } // Now make one solution homogeous y[0][0] = 0.0; vtkMath::SolveLeastSquares(3, x, 2, y, 1, m); // Now make all homogeous y[0][0] = 0.0; y[1][0] = 0.0; y[2][0] = 0.0; vtkMath::SolveLeastSquares(3, x, 2, y, 1, m); // Insufficient number of samples. Underdetermined. if (vtkMath::SolveLeastSquares(1, x, 2, y, 1, m) != 0) { std::cout << " Solve Least Squares got " << 1 << " but expected " << 0; ++status; } if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } for (int i = 0; i < 3; i++) { delete[] x[i]; delete[] y[i]; } for (int i = 0; i < 2; i++) { delete[] m[i]; } delete[] x; delete[] y; delete[] m; return status; } // Only warning cases validate // No validation, just coverage int TestSolveHomogeneousLeastSquares() { int status = 0; std::cout << "SolveHomogeneousLeastSquares.."; double** m = new double*[2]; double** x = new double*[3]; double** y = new double*[3]; for (int i = 0; i < 2; ++i) { m[i] = new double[1]; } for (int i = 0; i < 3; ++i) { x[i] = new double[2]; y[i] = new double[1]; } x[0][0] = 1; x[0][1] = 2; x[1][0] = 2; x[1][1] = 4; x[2][0] = 3; x[2][1] = 6; vtkMath::SolveHomogeneousLeastSquares(3, x, 1, m); vtkMath::MultiplyMatrix(x, m, 3, 2, 2, 1, y); std::vector results; std::vector expecteds; for (size_t i = 0; i < results.size(); ++i) { if (!vtkMathUtilities::FuzzyCompare( results[i], expecteds[i], std::numeric_limits::epsilon() * 128.0)) { std::cout << " SolveHomogeneousLeastSquares got " << results[i] << " but expected " << expecteds[i]; ++status; } } // Insufficient number of samples. Underdetermined. if (vtkMath::SolveHomogeneousLeastSquares(3, x, 5, m) != 0) { std::cout << " SolveHomogeneousLeastSquares got " << 1 << " but expected " << 0; ++status; } if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } for (int i = 0; i < 3; i++) { delete[] x[i]; delete[] y[i]; } for (int i = 0; i < 2; i++) { delete[] m[i]; } delete[] x; delete[] y; delete[] m; return status; } template int LUSolveLinearSystemEstimateMatrixCondition() { int status = 0; // Generate a Hilbert Matrix T** mat = new T*[NDimension]; int index[NDimension]; for (int i = 1; i <= NDimension; ++i) { mat[i - 1] = new T[NDimension]; for (int j = 1; j <= NDimension; ++j) { mat[i - 1][j - 1] = 1.0 / (i + j - 1); } } vtkMath::LUFactorLinearSystem(mat, index, NDimension); T condition = vtkMath::EstimateMatrixCondition(mat, NDimension); std::cout << "Condition is: " << condition << std::endl; T expected = condition; if (!vtkMathUtilities::FuzzyCompare( condition, expected, std::numeric_limits::epsilon() * (T)128.0)) { std::cout << " EstimateMatrixCondition(T) expected " << expected << " but got " << condition; std::cout << "eps ratio is: " << condition - expected / std::numeric_limits::epsilon() << std::endl; ++status; } for (int i = 0; i < NDimension; i++) { delete[] mat[i]; } delete[] mat; return status; } // Validate by observation that the condition of a hilbert matrix // increases with dimension int TestLUSolveLinearSystemEstimateMatrixCondition() { int status = 0; std::cout << "LUSolveLinearSystemEstimateMatrixCondition.."; status += LUSolveLinearSystemEstimateMatrixCondition(); status += LUSolveLinearSystemEstimateMatrixCondition(); status += LUSolveLinearSystemEstimateMatrixCondition(); status += LUSolveLinearSystemEstimateMatrixCondition(); status += LUSolveLinearSystemEstimateMatrixCondition(); if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } template int JacobiN() { int status = 0; T mat[NDimension][NDimension]; T orig[NDimension][NDimension]; T eigenVector[NDimension][NDimension], eigenVectorT[NDimension][NDimension]; T temp[NDimension][NDimension]; T result[NDimension][NDimension]; T eigen[NDimension]; for (int n = 0; n < 10; ++n) { for (int i = 0; i < NDimension; ++i) { for (int j = i; j < NDimension; ++j) { mat[i][j] = mat[j][i] = vtkMath::Random(0.0, 1.0); orig[i][j] = orig[j][i] = mat[i][j]; } } // convert to jacobiN format T* origJ[NDimension]; T* matJ[NDimension]; T* eigenVectorJ[NDimension]; T* eigenVectorTJ[NDimension]; T* resultJ[NDimension]; T* tempJ[NDimension]; for (int i = 0; i < NDimension; ++i) { matJ[i] = mat[i]; origJ[i] = orig[i]; eigenVectorJ[i] = eigenVector[i]; eigenVectorTJ[i] = eigenVectorT[i]; tempJ[i] = temp[i]; resultJ[i] = result[i]; } if (NDimension == 3) { vtkMath::Jacobi(matJ, eigen, eigenVectorJ); } else { vtkMath::JacobiN(matJ, NDimension, eigen, eigenVectorJ); } // P^-1 * A * P = diagonal matrix with eigenvalues on diagonal vtkMath::MultiplyMatrix( origJ, eigenVectorJ, NDimension, NDimension, NDimension, NDimension, tempJ); vtkMath::InvertMatrix(eigenVectorJ, eigenVectorTJ, NDimension); vtkMath::MultiplyMatrix( eigenVectorTJ, tempJ, NDimension, NDimension, NDimension, NDimension, resultJ); T expected; for (int i = 0; i < NDimension; ++i) { for (int j = 0; j < NDimension; ++j) { if (i == j) { expected = eigen[i]; } else { expected = 0.0; } if (!vtkMathUtilities::FuzzyCompare( result[i][j], expected, std::numeric_limits::epsilon() * (T)256.0)) { std::cout << " JacobiN expected " << expected << " but got " << result[i][j]; std::cout << "eps ratio is: " << (result[i][j] - expected) / std::numeric_limits::epsilon() << std::endl; ++status; } } } } return status; } // Validate P^-1 * A * P = diagonal matrix with eigenvalues on diagonal int TestJacobiN() { int status = 0; std::cout << "JacobiN.."; status += JacobiN(); status += JacobiN(); status += JacobiN(); if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } template int RGBToHSV() { int status = 0; T R, G, B; T H, S, V; T CR, CG, CB; for (int n = 0; n < 1000; ++n) { std::vector values; std::vector expecteds; R = (T)vtkMath::Random(0.0, 1.0); G = (T)vtkMath::Random(0.0, 1.0); B = (T)vtkMath::Random(0.0, 1.0); vtkMath::RGBToHSV(R, G, B, &H, &S, &V); vtkMath::HSVToRGB(H, S, V, &CR, &CG, &CB); values.push_back(CR); values.push_back(CG); values.push_back(CB); expecteds.push_back(R); expecteds.push_back(G); expecteds.push_back(B); for (size_t i = 0; i < values.size(); ++i) { if (!vtkMathUtilities::FuzzyCompare( values[i], expecteds[i], std::numeric_limits::epsilon() * (T)128.0)) { std::cout << " RGBToHSV got " << values[i] << " but expected " << expecteds[i]; std::cout << " eps ratio is: " << (values[i] - expecteds[i]) / std::numeric_limits::epsilon() << std::endl; ++status; } } } return status; } // Validate by rgb->hsv->rgb int TestRGBToHSV() { int status = 0; std::cout << "RGBToHSV.."; status += RGBToHSV(); status += RGBToHSV(); if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } // Validate with known solutions int TestClampValue() { int status = 0; std::cout << "ClampValue.."; double value; double clampedValue; double range[2] = { -1.0, 1.0 }; value = -800.0; clampedValue = vtkMath::ClampValue(value, range[0], range[1]); if (clampedValue != range[0]) { std::cout << " ClampValue expected " << range[0] << " but got " << value; ++status; } value = 900.0; clampedValue = vtkMath::ClampValue(value, range[0], range[1]); if (clampedValue != range[1]) { std::cout << " ClampValue expected " << range[1] << " but got " << value; ++status; } value = 0.0; clampedValue = vtkMath::ClampValue(value, range[0], range[1]); if (clampedValue != 0.0) { std::cout << " ClampValue expected " << 0.0 << " but got " << value; ++status; } value = -100.0; vtkMath::ClampValue(&value, range); if (value != range[0]) { std::cout << " ClampValue expected " << range[0] << " but got " << value; ++status; } value = 100.0; vtkMath::ClampValue(&value, range); if (value != range[1]) { std::cout << " ClampValue expected " << range[1] << " but got " << value; ++status; } value = -100.0; vtkMath::ClampValue(value, range, &clampedValue); if (clampedValue != range[0]) { std::cout << " ClampValue expected " << range[0] << " but got " << clampedValue; ++status; } value = 100.0; vtkMath::ClampValue(value, range, &clampedValue); if (clampedValue != range[1]) { std::cout << " ClampValue expected " << range[1] << " but got " << clampedValue; ++status; } value = 0.0; vtkMath::ClampValue(value, range, &clampedValue); if (clampedValue != value) { std::cout << " ClampValue expected " << value << " but got " << clampedValue; ++status; } if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } // Validate with known solutions int TestClampValues() { int status = 0; std::cout << "ClampValues.."; double values[1000]; double clampedValues[1000]; for (int n = 0; n < 1000; ++n) { values[n] = vtkMath::Random(-2.0, 2.0); } double range[2] = { -1.0, 1.0 }; vtkMath::ClampValues(values, 1000, range, clampedValues); vtkMath::ClampValues(values, 1000, range); for (int n = 0; n < 1000; ++n) { if (values[n] != clampedValues[n]) { ++status; } } vtkMath::ClampValues(nullptr, 1000, nullptr); vtkMath::ClampValues(nullptr, 1000, nullptr, nullptr); if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } // Validate with known solutions int TestClampAndNormalizeValue() { int status = 0; std::cout << "ClampAndNormalizeValue.."; double value; double result; double range[3] = { -1.0, 1.0 }; value = -100.0; result = vtkMath::ClampAndNormalizeValue(value, range); if (result != 0.0) { std::cout << " ClampAndNormalizeValue expected " << 0.0 << " but got " << result; ++status; } value = 100.0; result = vtkMath::ClampAndNormalizeValue(value, range); if (result != 1.0) { std::cout << " ClampAndNormalizeValue expected " << 1.0 << " but got " << result; ++status; } range[0] = 0.0; range[1] = 1.0; value = 0.5; result = vtkMath::ClampAndNormalizeValue(value, range); if (result != 0.5) { std::cout << " ClampValue expected " << 0.5 << " but got " << result; ++status; } range[0] = 1.0; range[1] = 1.0; value = 1.0; result = vtkMath::ClampAndNormalizeValue(value, range); if (result != 0.0) { std::cout << " ClampValue expected " << 0.0 << " but got " << result; ++status; } if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } // Validate by checking symmetric tensor values // are in correct places int TestTensorFromSymmetricTensor() { int status = 0; std::cout << "TensorFromSymmetricTensor.."; double symmTensor[9]; for (int i = 0; i < 6; i++) { symmTensor[i] = vtkMath::Random(); } double tensor[9]; vtkMath::TensorFromSymmetricTensor(symmTensor, tensor); if (tensor[0] != symmTensor[0] || tensor[1] != symmTensor[3] || tensor[2] != symmTensor[5] || tensor[3] != symmTensor[3] || tensor[4] != symmTensor[1] || tensor[5] != symmTensor[4] || tensor[6] != symmTensor[5] || tensor[7] != symmTensor[4] || tensor[8] != symmTensor[2]) { std::cout << " Unexpected results from TensorFromSymmetricTensor " << std::endl; ++status; } vtkMath::TensorFromSymmetricTensor(symmTensor); for (int i = 0; i < 9; i++) { if (symmTensor[i] != tensor[i]) { std::cout << " Unexpected results from in place TensorFromSymmetricTensor " << std::endl; ++status; break; } } if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } // Validate by checking ranges with numeric_limits int TestGetScalarTypeFittingRange() { int status = 0; std::cout << "GetScalarTypeFittingRange.."; double rangeMin; double rangeMax; rangeMin = (double)std::numeric_limits::min(); rangeMax = (double)std::numeric_limits::max(); if (vtkMath::GetScalarTypeFittingRange(rangeMin, rangeMax, 1.0, 0.0) != VTK_CHAR) { std::cout << " Bad fitting range for VTK_CHAR" << std::endl; ++status; } #if CHAR_MIN < 0 auto expected_schar = VTK_CHAR; auto expected_uchar = VTK_UNSIGNED_CHAR; #else auto expected_schar = VTK_SIGNED_CHAR; auto expected_uchar = VTK_CHAR; #endif rangeMin = (double)std::numeric_limits::min(); rangeMax = (double)std::numeric_limits::max(); if (vtkMath::GetScalarTypeFittingRange(rangeMin, rangeMax, 1.0, 0.0) != expected_schar) { std::cout << " Bad fitting range for VTK_CHAR" << std::endl; ++status; } rangeMin = (double)std::numeric_limits::min(); rangeMax = (double)std::numeric_limits::max(); if (vtkMath::GetScalarTypeFittingRange(rangeMin, rangeMax, 1.0, 0.0) != expected_uchar) { std::cout << " Bad fitting range for VTK_UNSIGNED_CHAR " << std::endl; ++status; } rangeMin = (double)std::numeric_limits::min(); rangeMax = (double)std::numeric_limits::max(); if (vtkMath::GetScalarTypeFittingRange(rangeMin, rangeMax, 1.0, 0.0) != VTK_SHORT) { std::cout << " Bad fitting range for VTK_SHORT" << std::endl; ++status; } rangeMin = (double)std::numeric_limits::min(); rangeMax = (double)std::numeric_limits::max(); if (vtkMath::GetScalarTypeFittingRange(rangeMin, rangeMax, 1.0, 0.0) != VTK_UNSIGNED_SHORT) { std::cout << " Bad fitting range for VTK_UNSIGNED_SHORT" << std::endl; ++status; } rangeMin = (double)std::numeric_limits::min(); rangeMax = (double)std::numeric_limits::max(); if (vtkMath::GetScalarTypeFittingRange(rangeMin, rangeMax, 1.0, 0.0) != VTK_INT) { std::cout << " Bad fitting range for VTK_INT" << std::endl; ++status; } rangeMin = (double)std::numeric_limits::min(); rangeMax = (double)std::numeric_limits::max(); if (vtkMath::GetScalarTypeFittingRange(rangeMin, rangeMax, 1.0, 0.0) != VTK_UNSIGNED_INT) { std::cout << " Bad fitting range for VTK_UNSIGNED_INT" << std::endl; ++status; } rangeMin = (double)std::numeric_limits::min(); rangeMax = (double)std::numeric_limits::max(); int scalarType = vtkMath::GetScalarTypeFittingRange(rangeMin, rangeMax, 1.0, 0.0); if (sizeof(long) == sizeof(int)) { if (scalarType != VTK_INT) { std::cout << " Bad fitting range for VTK_LONG" << std::endl; std::cout << " Expected " << VTK_INT << " but got " << scalarType; ++status; } } else { if (scalarType != VTK_LONG) { std::cout << " Bad fitting range for VTK_LONG" << std::endl; std::cout << " Expected " << VTK_LONG << " but got " << scalarType; ++status; } } rangeMin = (double)std::numeric_limits::min(); rangeMax = (double)std::numeric_limits::max(); scalarType = vtkMath::GetScalarTypeFittingRange(rangeMin, rangeMax, 1.0, 0.0); if (sizeof(unsigned long) == sizeof(unsigned int)) { if (scalarType != VTK_UNSIGNED_INT) { std::cout << " Bad fitting range for VTK_UNSIGNED_LONG" << std::endl; std::cout << " Expected " << VTK_UNSIGNED_INT << " but got " << scalarType; ++status; } } else { if (scalarType != VTK_UNSIGNED_LONG) { std::cout << " Bad fitting range for VTK_UNSIGNED_LONG" << std::endl; std::cout << " Expected " << VTK_UNSIGNED_LONG << " but got " << scalarType; ++status; } } rangeMin = (double)std::numeric_limits::min(); rangeMax = (double)std::numeric_limits::max(); if (vtkMath::GetScalarTypeFittingRange(rangeMin, rangeMax, 1.1, 0.0) != VTK_FLOAT) { std::cout << " Bad fitting range for VTK_FLOAT" << std::endl; ++status; } if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } // Validate with known solutions int TestGetAdjustedScalarRange() { int status = 0; std::cout << "GetAdjustedScalarRange.."; vtkSmartPointer uc = vtkSmartPointer::New(); uc->SetNumberOfComponents(3); uc->SetNumberOfTuples(100); for (int i = 0; i < 100; ++i) { for (int j = 0; j < 3; ++j) { uc->SetComponent(i, j, vtkMath::Random( std::numeric_limits::min(), std::numeric_limits::max())); } } double range[2]; vtkMath::GetAdjustedScalarRange(uc, 1, range); if (range[0] != uc->GetDataTypeMin() || range[1] != uc->GetDataTypeMax()) { std::cout << " GetAdjustedScalarRange(unsigned char) expected " << uc->GetDataTypeMin() << ", " << uc->GetDataTypeMax() << " but got " << range[0] << ", " << range[1] << std::endl; ++status; } vtkSmartPointer us = vtkSmartPointer::New(); us->SetNumberOfComponents(3); us->SetNumberOfTuples(10000); for (int i = 0; i < 10000; ++i) { us->SetComponent(i, 0, vtkMath::Random( std::numeric_limits::min(), std::numeric_limits::max())); us->SetComponent(i, 1, vtkMath::Random(std::numeric_limits::min(), std::numeric_limits::max() + 100)); us->SetComponent(i, 2, vtkMath::Random( std::numeric_limits::min(), std::numeric_limits::max())); } vtkMath::GetAdjustedScalarRange(us, 0, range); if (range[0] != us->GetDataTypeMin() || range[1] != us->GetDataTypeMax()) { std::cout << " GetAdjustedScalarRange(unsigned short) expected " << us->GetDataTypeMin() << ", " << us->GetDataTypeMax() << " but got " << range[0] << ", " << range[1] << std::endl; ++status; } vtkMath::GetAdjustedScalarRange(us, 1, range); if (range[0] != us->GetDataTypeMin() || range[1] != 4095.0) { std::cout << " GetAdjustedScalarRange(unsigned short) expected " << us->GetDataTypeMin() << ", " << 4095.0 << " but got " << range[0] << ", " << range[1] << std::endl; ++status; } vtkMath::GetAdjustedScalarRange(us, 2, range); if (range[0] != us->GetDataTypeMin() || range[1] >= uc->GetDataTypeMax()) { std::cout << " GetAdjustedScalarRange(unsigned short) expected " << us->GetDataTypeMin() << ", " << ">= " << uc->GetDataTypeMax() << " but got " << range[0] << ", " << range[1] << std::endl; ++status; } // Test nullptr array if (vtkMath::GetAdjustedScalarRange(nullptr, 1000, nullptr)) { std::cout << " GetAdjustedScalarRange with a nullptr array expected " << 0 << " but got " << 1 << std::endl; ++status; } if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } // Validate with known solutions int TestExtentIsWithinOtherExtent() { int status = 0; std::cout << "ExtentIsWithinOtherExtent.."; if (vtkMath::ExtentIsWithinOtherExtent(nullptr, nullptr)) { std::cout << " ExtentIsWithinOtherExtent expected 0 but got 1" << std::endl; ++status; } int extent1[6]; int extent2[6]; extent1[0] = 100; extent1[1] = 101; extent1[2] = 100; extent1[3] = 101; extent1[4] = 100; extent1[5] = 101; extent2[0] = 100; extent2[1] = 101; extent2[2] = 100; extent2[3] = 101; extent2[4] = 100; extent2[5] = 101; if (!vtkMath::ExtentIsWithinOtherExtent(extent1, extent2)) { std::cout << " ExtentIsWithinOtherExtent expected 1 but got 0" << std::endl; ++status; } extent1[0] = 99; extent1[1] = 101; if (vtkMath::ExtentIsWithinOtherExtent(extent1, extent2)) { std::cout << " ExtentIsWithinOtherExtent expected 0 but got 1" << std::endl; ++status; } extent1[0] = 98; extent1[1] = 99; if (vtkMath::ExtentIsWithinOtherExtent(extent1, extent2)) { std::cout << " ExtentIsWithinOtherExtent expected 0 but got 1" << std::endl; ++status; } if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } // Validate with known solutions int TestBoundsIsWithinOtherBounds() { int status = 0; std::cout << "BoundsIsWithinOtherBounds.."; if (vtkMath::BoundsIsWithinOtherBounds(nullptr, nullptr, nullptr)) { std::cout << " BoundsIsWithinOtherBounds expected 0 but got 1" << std::endl; ++status; } double delta[3]; delta[0] = delta[1] = delta[2] = std::numeric_limits::epsilon(); double bounds1[6]; double bounds2[6]; bounds1[0] = 1 - delta[0]; bounds1[1] = 2 + delta[0]; bounds1[2] = 1; bounds1[3] = 2; bounds1[4] = 1; bounds1[5] = 2; bounds2[0] = 1; bounds2[1] = 2; bounds2[2] = 1; bounds2[3] = 2; bounds2[4] = 1; bounds2[5] = 2; if (!vtkMath::BoundsIsWithinOtherBounds(bounds1, bounds2, delta)) { std::cout << " BoundsIsWithinOtherBounds expected 1 but got 0" << std::endl; ++status; } bounds1[0] = 1 - 2.0 * delta[0]; bounds1[1] = 2 + 2.0 * delta[0]; if (vtkMath::BoundsIsWithinOtherBounds(bounds1, bounds2, delta)) { std::cout << " BoundsIsWithinOtherBounds expected 0 but got 1" << std::endl; ++status; } bounds1[0] = 1 - 4.0 * delta[0]; bounds1[1] = 1 - 2.0 * delta[0]; if (vtkMath::BoundsIsWithinOtherBounds(bounds1, bounds2, delta)) { std::cout << " BoundsIsWithinOtherBounds expected 0 but got 1" << std::endl; ++status; } if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } // Validate with known solutions int TestPointIsWithinBounds() { int status = 0; std::cout << "PointIsWithinBounds.."; if (vtkMath::PointIsWithinBounds(nullptr, nullptr, nullptr)) { std::cout << " PointIsWithinBounds expected 0 but got 1" << std::endl; ++status; } double delta[3]; delta[0] = std::numeric_limits::epsilon(); delta[1] = std::numeric_limits::epsilon() * 2.0; delta[2] = std::numeric_limits::epsilon() * 256.0; double bounds1[6]; bounds1[0] = 1.0; bounds1[1] = 2.0; bounds1[2] = 1.0; bounds1[3] = 2.0; bounds1[4] = 1.0; bounds1[5] = 2.0; double point[3]; point[0] = bounds1[0] - delta[0]; point[1] = bounds1[2] - delta[1]; point[2] = bounds1[4]; if (!vtkMath::PointIsWithinBounds(point, bounds1, delta)) { std::cout << " PointIsWithinBounds expected 1 but got 0" << std::endl; ++status; } point[0] = bounds1[0] - delta[0]; point[1] = bounds1[2] - delta[1]; point[2] = bounds1[4] - 2.0 * delta[2]; if (vtkMath::PointIsWithinBounds(point, bounds1, delta)) { std::cout << " PointIsWithinBounds expected 0 but got 1" << std::endl; ++status; } point[0] = bounds1[1] + delta[0]; point[1] = bounds1[3] + delta[1]; point[2] = bounds1[5] + 2.0 * delta[2]; if (vtkMath::PointIsWithinBounds(point, bounds1, delta)) { std::cout << " PointIsOtherBounds expected 0 but got 1" << std::endl; ++status; } if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } // Validate with with alternative solution int TestSolve3PointCircle() { int status = 0; std::cout << "Solve3PointCircle.."; for (int n = 0; n < 1000; ++n) { double A[3], B[3], C[3]; double center[3]; double a[3], b[3], aMinusb[3], aCrossb[3]; for (int i = 0; i < 3; ++i) { A[i] = vtkMath::Random(-1.0, 1.0); B[i] = vtkMath::Random(-1.0, 1.0); C[i] = vtkMath::Random(-1.0, 1.0); } vtkMath::Subtract(A, C, a); vtkMath::Subtract(B, C, b); vtkMath::Subtract(a, b, aMinusb); vtkMath::Cross(a, b, aCrossb); double expectedRadius; expectedRadius = (vtkMath::Norm(a) * vtkMath::Norm(b) * vtkMath::Norm(aMinusb)) / (2.0 * vtkMath::Norm(aCrossb)); double radius; radius = vtkMath::Solve3PointCircle(A, B, C, center); if (!vtkMathUtilities::FuzzyCompare( radius, expectedRadius, std::numeric_limits::epsilon() * 1024.0)) { std::cout << " Solve3PointCircle radius expected " << expectedRadius << " but got " << radius; std::cout << "eps ratio is: " << (expectedRadius - radius) / std::numeric_limits::epsilon() << std::endl; ++status; } double ab[3], ba[3]; double abMinusba[3]; double abMinusbaCrossaCrossb[3]; vtkMath::Subtract(B, C, ab); vtkMath::Subtract(A, C, ba); vtkMath::MultiplyScalar(ab, vtkMath::Norm(a) * vtkMath::Norm(a)); vtkMath::MultiplyScalar(ba, vtkMath::Norm(b) * vtkMath::Norm(b)); vtkMath::Subtract(ab, ba, abMinusba); vtkMath::Cross(abMinusba, aCrossb, abMinusbaCrossaCrossb); double expectedCenter[3]; vtkMath::MultiplyScalar( abMinusbaCrossaCrossb, 1.0 / (2.0 * vtkMath::Norm(aCrossb) * vtkMath::Norm(aCrossb))); vtkMath::Add(abMinusbaCrossaCrossb, C, expectedCenter); for (int i = 0; i < 3; ++i) { if (!vtkMathUtilities::FuzzyCompare( center[i], expectedCenter[i], std::numeric_limits::epsilon() * 1024.0)) { std::cout << " Solve3PointCircle center expected " << expectedCenter[i] << " but got " << center[i]; std::cout << "eps ratio is: " << (expectedCenter[i] - center[i]) / std::numeric_limits::epsilon() << std::endl; ++status; } } } if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } // Tested by TestMath int TestInf() { int status = 0; std::cout << "Inf.."; if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } // Tested by TestMath int TestNegInf() { int status = 0; std::cout << "NegInf.."; if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } // Tested by TestMath int TestNan() { int status = 0; std::cout << "Nan.."; if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } // Validate with known solutions int TestMetaMultiplyMatrix() { int status = 0; std::cout << "MetaMuliplyMatrix.."; vtkNew arrayM1, arrayM2, arrayM3; arrayM1->SetNumberOfComponents(25); arrayM1->SetNumberOfTuples(1); arrayM2->SetNumberOfComponents(10); arrayM2->SetNumberOfTuples(1); arrayM3->SetNumberOfComponents(25); arrayM3->SetNumberOfTuples(1); auto rangeM1 = vtk::DataArrayTupleRange<25>(arrayM1); auto rangeM2 = vtk::DataArrayTupleRange<10>(arrayM2); auto rangeM3 = vtk::DataArrayTupleRange<25>(arrayM3); auto M1 = rangeM1[0]; auto M2 = rangeM2[0]; auto M3 = rangeM3[0]; // We fill M1 and M2 with the beginning of the sequence of natural integers. std::iota(M1.begin(), M1.end(), 0); std::iota(M2.begin(), M2.end(), 0); // 0 1 2 3 4 0 1 60 70 // 5 6 7 8 9 2 3 160 195 // 10 11 12 13 14 x 4 5 = 260 320 // 15 16 17 18 19 6 7 360 445 // 20 21 22 23 24 8 9 460 570 vtkMath::MultiplyMatrix<5, 5, 2>(M1, M2, M3); if (M3[0] != 60 || M3[1] != 70 || M3[2] != 160 || M3[3] != 195 || M3[4] != 260 || M3[5] != 320 || M3[6] != 360 || M3[7] != 445 || M3[8] != 460 || M3[9] != 570) { status = 1; } // 0 5 10 15 20 // 0 1 2 3 4 1 6 11 16 21 60 160 260 360 460 // 5 6 7 8 9 x 2 7 12 17 22 = 70 195 320 445 570 // 3 8 13 18 23 // 4 9 14 19 24 vtkMath::MultiplyMatrix<2, 5, 5, vtkMatrixUtilities::Layout::Transpose, vtkMatrixUtilities::Layout::Transpose>(M2, M1, M3); if (M3[0] != 60 || M3[5] != 70 || M3[1] != 160 || M3[6] != 195 || M3[2] != 260 || M3[7] != 320 || M3[3] != 360 || M3[8] != 445 || M3[4] != 460 || M3[9] != 570) { status = 1; } // 0 4 8 12 16 0 1 240 280 // 1 5 9 13 17 2 3 260 305 // 2 6 10 14 18 x 4 5 = 280 330 // 3 7 11 15 19 6 7 300 355 // 8 9 vtkMath::MultiplyMatrix<4, 5, 2, vtkMatrixUtilities::Layout::Transpose, vtkMatrixUtilities::Layout::Identity>(M1, M2, M3); if (M3[0] != 240 || M3[1] != 280 || M3[2] != 260 || M3[3] != 305 || M3[4] != 280 || M3[5] != 330 || M3[6] != 300 || M3[7] != 355) { status = 1; } // 0 1 2 3 0 14 // 4 5 6 7 x 1 = 38 // 8 9 10 11 2 62 // 3 vtkMath::MultiplyMatrix<3, 4, 1>(M1, M2, M3); if (M3[0] != 14 || M3[1] != 38 || M3[2] != 62) { status = 1; } // 0 0 0 0 0 0 // 1 0 1 2 3 4 // 2 * 0 1 2 3 4 = 0 2 4 6 8 // 3 0 3 6 9 12 // 4 0 4 8 12 16 vtkMath::MultiplyMatrix<5, 1, 5, vtkMatrixUtilities::Layout::Transpose, vtkMatrixUtilities::Layout::Transpose>(M1, M2, M3); if (M3[0] != 0 || M3[1] != 0 || M3[2] != 0 || M3[3] != 0 || M3[4] != 0 || M3[5] != 0 || M3[6] != 1 || M3[7] != 2 || M3[8] != 3 || M3[9] != 4 || M3[10] != 0 || M3[11] != 2 || M3[12] != 4 || M3[13] != 6 || M3[14] != 8 || M3[15] != 0 || M3[16] != 3 || M3[17] != 6 || M3[18] != 9 || M3[19] != 12 || M3[20] != 0 || M3[21] != 4 || M3[22] != 8 || M3[23] != 12 || M3[24] != 16) { status = 1; } // 0 1 2 3 4 0 0 1 4 9 16 // 5 6 7 8 9 1 0 6 14 24 36 // 10 11 12 13 14 x 2 = 0 11 24 39 56 // 15 16 17 18 19 3 0 16 34 54 76 // 20 21 22 23 24 4 0 21 44 69 96 vtkMath::MultiplyMatrix<5, 5, 5, vtkMatrixUtilities::Layout::Identity, vtkMatrixUtilities::Layout::Diag>(M1, M2, M3); if (M3[0] != 0 || M3[1] != 1 || M3[2] != 4 || M3[3] != 9 || M3[4] != 16 || M3[5] != 0 || M3[6] != 6 || M3[7] != 14 || M3[8] != 24 || M3[9] != 36 || M3[10] != 0 || M3[11] != 11 || M3[12] != 24 || M3[13] != 39 || M3[14] != 56 || M3[15] != 0 || M3[16] != 16 || M3[17] != 34 || M3[18] != 54 || M3[19] != 76 || M3[20] != 0 || M3[21] != 21 || M3[22] != 44 || M3[23] != 69 || M3[24] != 96) { status = 1; } // 0 0 5 10 15 20 0 0 0 0 0 // 1 1 6 11 16 21 1 6 11 16 21 // 2 x 2 7 12 17 22 = 4 14 24 34 56 // 3 3 8 13 18 23 9 24 39 54 76 // 4 4 9 14 19 24 16 36 56 76 96 vtkMath::MultiplyMatrix<5, 5, 5, vtkMatrixUtilities::Layout::Diag, vtkMatrixUtilities::Layout::Transpose>(M2, M1, M3); if (M3[0] != 0 || M3[1] != 0 || M3[2] != 0 || M3[3] != 0 || M3[4] != 0 || M3[5] != 1 || M3[6] != 6 || M3[7] != 11 || M3[8] != 16 || M3[9] != 21 || M3[10] != 4 || M3[11] != 14 || M3[12] != 24 || M3[13] != 34 || M3[14] != 44 || M3[15] != 9 || M3[16] != 24 || M3[17] != 39 || M3[18] != 54 || M3[19] != 69 || M3[20] != 16 || M3[21] != 36 || M3[22] != 56 || M3[23] != 76 || M3[24] != 96) { status = 1; } // 0 0 0 // 1 1 1 // 2 x 2 = 4 // 3 3 9 // 4 4 16 vtkMath::MultiplyMatrix<5, 5, 5, vtkMatrixUtilities::Layout::Diag, vtkMatrixUtilities::Layout::Diag>(M1, M2, M3); if (M3[0] != 0 || M3[1] != 1 || M3[2] != 4 || M3[3] != 9 || M3[4] != 16) { status = 1; } // 0 0 0 1 2 0 0 0 // 0 1 x 3 4 5 = 3 4 5 vtkMath::MultiplyMatrix<2, 2, 3, vtkMatrixUtilities::Layout::Diag>(M1, M2, M3); if (M3[0] != 0 || M3[1] != 0 || M3[2] != 0 || M3[3] != 3 || M3[4] != 4 || M3[5] != 5) { status = 1; } // 0 0 0 1 0 0 // 0 1 x 2 3 = 2 3 // 0 0 0 0 vtkMath::MultiplyMatrix<3, 2, 2, vtkMatrixUtilities::Layout::Diag>(M1, M2, M3); if (M3[0] != 0 || M3[1] != 0 || M3[2] != 2 || M3[3] != 3 || M3[4] != 0 || M3[5] != 0) { status = 1; } // 0 1 2 0 0 0 0 0 1 4 0 // 3 4 5 x 0 1 0 0 = 0 4 10 0 // 6 7 8 0 0 2 0 0 7 16 0 vtkMath::MultiplyMatrix<3, 3, 4, vtkMatrixUtilities::Layout::Identity, vtkMatrixUtilities::Layout::Diag>(M1, M2, M3); if (M3[0] != 0 || M3[1] != 1 || M3[2] != 4 || M3[3] != 0 || M3[4] != 0 || M3[5] != 4 || M3[6] != 10 || M3[7] != 0 || M3[8] != 0 || M3[9] != 7 || M3[10] != 16 || M3[11] != 0) { status = 1; } if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } // Validate with known solutions int TestMetaMultiplyMatrixWithVector() { int status = 0; std::cout << "MetaMuliplyMatrixWithVector.."; std::array M = { 0, 1, 2, 3, 4, 5, 6, 7, 8 }; int x[3] = { 10, 100, 1000 }, y[3]; // Testing with regular array output vtkMath::MultiplyMatrixWithVector<3, 3>(M, x, y); if (y[0] != 2100 || y[1] != 5430 || y[2] != 8760) { status = 1; } // Testing with the transpose vtkMath::MultiplyMatrixWithVector<3, 3, vtkMatrixUtilities::Layout::Transpose>(M, x, y); if (y[0] != 6300 || y[1] != 7410 || y[2] != 8520) { status = 1; } int* tmp = &(y[0]); // Testing with pointer output, only for compiling purpose. vtkMath::MultiplyMatrixWithVector<3, 3>(M, x, tmp); if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } // Validate with known solutions int TestMetaDot() { int status = 0; std::cout << "MetaDot.."; std::array x = { 0, 1, 2, 3, 4 }; std::array y = { 0, 1, 2, 3, 4 }; int M[5] = { 2, 4, 6, 8, 9 }; if (vtkMath::Dot(x, y) != 30) { status = 1; } if (vtkMath::Dot(x, M, y) != 244) { status = 1; } if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } // Validate with known solutions int TestMetaDeterminant() { int status = 0; std::cout << "MetaDeterminant.."; int M[9] = { 1, 2, 3, 3, 2, 1, 2, 3, 1 }; // | 1 2 3 | // | 3 2 1 | = 12 // | 2 3 1 | if (vtkMath::Determinant<3>(M) != 12) { status = 1; } // | 1 0 0 | // | 0 2 0 | = 6 // | 0 0 3 | if (vtkMath::Determinant<3, vtkMatrixUtilities::Layout::Diag>(M) != 6) { status = 1; } // | 1 2 | // | 3 3 | = -3 if (vtkMath::Determinant<2>(M) != -3) { status = 1; } // | 1 0 | // | 0 2 | = 2 if (vtkMath::Determinant<2, vtkMatrixUtilities::Layout::Diag>(M) != 2) { status = 1; } // | 1 | = 1 if (vtkMath::Determinant<1>(M) != 1) { status = 1; } if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } // Validate with known solutions int TestMetaInvertMatrix() { int status = 0; std::cout << "MetaInvertMatrix.."; int M[9] = { 1, 1, 0, 0, 0, 1, 1, 0, 1 }; int invM[9]; double diag[3] = { 1.0, 2.0, 3.0 }; double invDiag[3]; int N[4] = { 1, -1, 0, 1 }; int invN[4]; // 1 1 0 0 -1 1 // inv 0 0 1 = 1 1 -1 // 1 0 1 0 1 0 vtkMath::InvertMatrix<3>(M, invM); if (invM[0] != 0 || invM[1] != -1 || invM[2] != 1 || invM[3] != 1 || invM[4] != 1 || invM[5] != -1 || invM[6] != 0 || invM[7] != 1 || invM[8] != 0) { std::cout << "a" << std::endl; status = 1; } // 1 0 1 0 1 0 // inv 1 0 0 = -1 1 1 // 0 1 1 1 -1 0 vtkMath::InvertMatrix<3, vtkMatrixUtilities::Layout::Transpose>(M, invM); if (invM[0] != 0 || invM[1] != 1 || invM[2] != 0 || invM[3] != -1 || invM[4] != 1 || invM[5] != 1 || invM[6] != 1 || invM[7] != -1 || invM[8] != 0) { std::cout << "b" << std::endl; status = 1; } // 1 1 // inv 2 = 1/2 // 3 1/3 vtkMath::InvertMatrix<3, vtkMatrixUtilities::Layout::Diag>(diag, invDiag); if (invDiag[0] != 1.0 || invDiag[1] != 1.0 / 2.0 || invDiag[2] != 1.0 / 3.0) { std::cout << "c" << std::endl; status = 1; } // 1 -1 1 1 // inv 0 1 = 0 1 vtkMath::InvertMatrix<2>(N, invN); if (invN[0] != 1 || invN[1] != 1 || invN[2] != 0 || invN[3] != 1) { std::cout << "d" << std::endl; status = 1; } // 1 0 1 0 // inv -1 1 = 1 1 vtkMath::InvertMatrix<2, vtkMatrixUtilities::Layout::Transpose>(N, invN); if (invN[0] != 1 || invN[1] != 0 || invN[2] != 1 || invN[3] != 1) { std::cout << "e" << std::endl; status = 1; } // 1 1 // inv -1 = -1 vtkMath::InvertMatrix<2, vtkMatrixUtilities::Layout::Diag>(N, invN); if (invN[0] != 1 || invN[1] != -1) { std::cout << "f" << std::endl; status = 1; } // inv 1 = 1 vtkMath::InvertMatrix<1>(N, invN); if (invN[0] != 1) { std::cout << "g" << std::endl; status = 1; } if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } // Validate with known solutions int TestMetaLinearSolve() { int status = 0; std::cout << "MetaLinearSolve.."; int M[9] = { 1, 1, 0, 1, 0, 1, 0, 0, 1 }; int X[3] = { 1, 2, 3 }; int Y[3]; // 1 1 0 -1 1 // 0 1 0 x 2 = 2 // 0 0 1 3 3 vtkMath::LinearSolve<3, 3>(M, X, Y); if (Y[0] != -1 || Y[1] != 2 || Y[2] != 3) { status = 1; } // 1 0 0 2 1 // 1 1 0 x -1 = 2 // 0 0 1 4 3 vtkMath::LinearSolve<3, 3, vtkMatrixUtilities::Layout::Transpose>(M, X, Y); if (Y[0] != 2 || Y[1] != -1 || Y[2] != 4) { status = 1; } // 1 1 1 // 2 x 1 = 2 // 3 1 3 vtkMath::LinearSolve<3, 3, vtkMatrixUtilities::Layout::Diag>(X, X, Y); if (Y[0] != 1 || Y[1] != 1 || Y[2] != 1) { status = 1; } int N[4] = { -1, 1, 0, 1 }; // -1 1 1 1 // 0 1 x 2 = 2 vtkMath::LinearSolve<2, 2>(N, X, Y); if (Y[0] != 1 || Y[1] != 2) { status = 1; } // -1 0 -1 1 // 1 1 x 3 = 2 vtkMath::LinearSolve<2, 2, vtkMatrixUtilities::Layout::Transpose>(N, X, Y); if (Y[0] != -1 || Y[1] != 3) { std::cout << Y[0] << ", " << Y[1] << std::endl; status = 1; } // -1 -1 1 // 1 x 2 = 2 vtkMath::LinearSolve<2, 2, vtkMatrixUtilities::Layout::Diag>(N, X, Y); if (Y[0] != -1 || Y[1] != 2) { status = 1; } if (status) { std::cout << "..FAILED" << std::endl; } else { std::cout << ".PASSED" << std::endl; } return status; } static_assert(vtkMatrixUtilities::MatrixIs2DArray(), "Failed"); static_assert(vtkMatrixUtilities::MatrixIs2DArray(), "Failed"); static_assert(vtkMatrixUtilities::MatrixIs2DArray(), "Failed"); static_assert(vtkMatrixUtilities::MatrixIs2DArray(), "Failed"); static_assert(!vtkMatrixUtilities::MatrixIs2DArray(), "Failed"); static_assert(!vtkMatrixUtilities::MatrixIs2DArray(), "Failed"); static_assert(!vtkMatrixUtilities::MatrixIs2DArray(), "Failed"); static_assert(!vtkMatrixUtilities::MatrixIs2DArray(), "Failed");