vtk-m/vtkm/testing/UnitTestVectorAnalysis.cxx

259 lines
8.8 KiB
C++
Raw Normal View History

2019-04-15 23:24:21 +00:00
//============================================================================
2015-07-07 20:25:58 +00:00
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
2019-04-15 23:24:21 +00:00
//============================================================================
2015-07-07 20:25:58 +00:00
#include <vtkm/VectorAnalysis.h>
#include <vtkm/Types.h>
#include <vtkm/VecTraits.h>
#include <vtkm/testing/Testing.h>
#include <math.h>
2017-05-18 14:29:41 +00:00
namespace
{
2015-07-07 20:25:58 +00:00
2017-05-18 14:29:41 +00:00
namespace internal
{
2015-07-07 20:25:58 +00:00
2017-05-18 14:29:41 +00:00
template <typename VectorType>
typename vtkm::VecTraits<VectorType>::ComponentType MyMag(const VectorType& vt)
2015-07-07 20:25:58 +00:00
{
2018-02-22 13:29:13 +00:00
using Traits = vtkm::VecTraits<VectorType>;
2015-07-07 20:25:58 +00:00
double total = 0.0;
for (vtkm::IdComponent index = 0; index < Traits::NUM_COMPONENTS; ++index)
{
2017-05-18 14:29:41 +00:00
total += Traits::GetComponent(vt, index) * Traits::GetComponent(vt, index);
2015-07-07 20:25:58 +00:00
}
return static_cast<typename Traits::ComponentType>(sqrt(total));
}
2017-05-18 14:29:41 +00:00
template <typename VectorType>
2015-07-07 20:25:58 +00:00
VectorType MyNormal(const VectorType& vt)
{
2018-02-22 13:29:13 +00:00
using Traits = vtkm::VecTraits<VectorType>;
2015-07-07 20:25:58 +00:00
typename Traits::ComponentType mag = internal::MyMag(vt);
VectorType temp = vt;
for (vtkm::IdComponent index = 0; index < Traits::NUM_COMPONENTS; ++index)
{
2017-05-18 14:29:41 +00:00
Traits::SetComponent(temp, index, Traits::GetComponent(vt, index) / mag);
2015-07-07 20:25:58 +00:00
}
return temp;
}
2017-05-18 14:29:41 +00:00
template <typename T, typename W>
T MyLerp(const T& a, const T& b, const W& w)
2015-07-07 20:25:58 +00:00
{
2017-05-18 14:29:41 +00:00
return (W(1) - w) * a + w * b;
2015-07-07 20:25:58 +00:00
}
}
2017-05-18 14:29:41 +00:00
template <typename VectorType>
2015-07-07 20:25:58 +00:00
void TestVector(const VectorType& vector)
{
2018-02-22 13:29:13 +00:00
using ComponentType = typename vtkm::VecTraits<VectorType>::ComponentType;
2015-07-07 20:25:58 +00:00
std::cout << "Testing " << vector << std::endl;
//to do have to implement a norm and normalized call to verify the math ones
//against
std::cout << " Magnitude" << std::endl;
2015-07-07 20:25:58 +00:00
ComponentType magnitude = vtkm::Magnitude(vector);
ComponentType magnitudeCompare = internal::MyMag(vector);
2017-05-18 14:29:41 +00:00
VTKM_TEST_ASSERT(test_equal(magnitude, magnitudeCompare), "Magnitude failed test.");
2015-07-07 20:25:58 +00:00
std::cout << " Magnitude squared" << std::endl;
2015-07-07 20:25:58 +00:00
ComponentType magnitudeSquared = vtkm::MagnitudeSquared(vector);
2017-05-18 14:29:41 +00:00
VTKM_TEST_ASSERT(test_equal(magnitude * magnitude, magnitudeSquared),
2015-07-07 20:25:58 +00:00
"Magnitude squared test failed.");
if (magnitudeSquared > 0)
2017-05-18 14:29:41 +00:00
{
std::cout << " Reciprocal magnitude" << std::endl;
2015-07-07 20:25:58 +00:00
ComponentType rmagnitude = vtkm::RMagnitude(vector);
2017-05-18 14:29:41 +00:00
VTKM_TEST_ASSERT(test_equal(1 / magnitude, rmagnitude), "Reciprical magnitude failed.");
2015-07-07 20:25:58 +00:00
std::cout << " Normal" << std::endl;
2017-05-18 14:29:41 +00:00
VTKM_TEST_ASSERT(test_equal(vtkm::Normal(vector), internal::MyNormal(vector)),
2015-07-07 20:25:58 +00:00
"Normalized vector failed test.");
std::cout << " Normalize" << std::endl;
2015-07-07 20:25:58 +00:00
VectorType normalizedVector = vector;
vtkm::Normalize(normalizedVector);
VTKM_TEST_ASSERT(test_equal(normalizedVector, internal::MyNormal(vector)),
"Inplace Normalized vector failed test.");
2017-05-18 14:29:41 +00:00
}
2015-07-07 20:25:58 +00:00
}
template <typename VectorType>
void TestLerp(const VectorType& a,
const VectorType& b,
const VectorType& w,
2015-07-07 20:25:58 +00:00
const typename vtkm::VecTraits<VectorType>::ComponentType& wS)
{
2017-05-18 14:29:41 +00:00
std::cout << "Linear interpolation: " << a << "-" << b << ": " << w << std::endl;
VectorType vtkmLerp = vtkm::Lerp(a, b, w);
VectorType otherLerp = internal::MyLerp(a, b, w);
VTKM_TEST_ASSERT(test_equal(vtkmLerp, otherLerp),
2015-07-07 20:25:58 +00:00
"Vectors with Vector weight do not lerp() correctly");
2017-05-18 14:29:41 +00:00
std::cout << "Linear interpolation: " << a << "-" << b << ": " << wS << std::endl;
VectorType lhsS = internal::MyLerp(a, b, wS);
VectorType rhsS = vtkm::Lerp(a, b, wS);
VTKM_TEST_ASSERT(test_equal(lhsS, rhsS), "Vectors with Scalar weight do not lerp() correctly");
2015-07-07 20:25:58 +00:00
}
2017-05-18 14:29:41 +00:00
template <typename T>
void TestCross(const vtkm::Vec<T, 3>& x, const vtkm::Vec<T, 3>& y)
2015-07-07 20:25:58 +00:00
{
std::cout << "Testing " << x << " x " << y << std::endl;
2018-02-22 13:29:13 +00:00
using Vec3 = vtkm::Vec<T, 3>;
2015-07-07 20:25:58 +00:00
Vec3 cross = vtkm::Cross(x, y);
std::cout << " = " << cross << std::endl;
2015-07-07 20:25:58 +00:00
std::cout << " Orthogonality" << std::endl;
2015-07-07 20:25:58 +00:00
// The cross product result should be perpendicular to input vectors.
VTKM_TEST_ASSERT(test_equal(vtkm::Dot(cross, x), T(0.0)), "Cross product not perpendicular.");
VTKM_TEST_ASSERT(test_equal(vtkm::Dot(cross, y), T(0.0)), "Cross product not perpendicular.");
2015-07-07 20:25:58 +00:00
std::cout << " Length" << std::endl;
2015-07-07 20:25:58 +00:00
// The length of cross product should be the lengths of the input vectors
// times the sin of the angle between them.
2017-05-18 14:29:41 +00:00
T sinAngle = vtkm::Magnitude(cross) * vtkm::RMagnitude(x) * vtkm::RMagnitude(y);
2015-07-07 20:25:58 +00:00
// The dot product is likewise the lengths of the input vectors times the
// cos of the angle between them.
T cosAngle = vtkm::Dot(x, y) * vtkm::RMagnitude(x) * vtkm::RMagnitude(y);
2015-07-07 20:25:58 +00:00
// Test that these are the actual sin and cos of the same angle with a
// basic trigonometric identity.
2017-05-18 14:29:41 +00:00
VTKM_TEST_ASSERT(test_equal(sinAngle * sinAngle + cosAngle * cosAngle, T(1.0)),
2015-07-07 20:25:58 +00:00
"Bad cross product length.");
std::cout << " Triangle normal" << std::endl;
2015-07-07 20:25:58 +00:00
// Test finding the normal to a triangle (similar to cross product).
Vec3 normal = vtkm::TriangleNormal(x, y, Vec3(0, 0, 0));
VTKM_TEST_ASSERT(test_equal(vtkm::Dot(normal, x - y), T(0.0)),
2015-07-07 20:25:58 +00:00
"Triangle normal is not really normal.");
}
template <typename VectorBasisType>
void TestOrthonormalize(const VectorBasisType& inputs, int expectedRank)
{
VectorBasisType outputs;
int actualRank = vtkm::Orthonormalize(inputs, outputs);
std::cout << "Testing orthonormalize\n"
<< " Rank " << actualRank << " expected " << expectedRank << "\n"
<< " Basis vectors:\n";
for (int i = 0; i < actualRank; ++i)
{
std::cout << " " << i << " " << outputs[i] << "\n";
}
VTKM_TEST_ASSERT(test_equal(actualRank, expectedRank), "Orthonormalized rank is unexpected.");
}
2015-07-07 20:25:58 +00:00
struct TestLinearFunctor
{
template <typename T>
void operator()(const T&) const
{
2018-02-22 13:29:13 +00:00
using Traits = vtkm::VecTraits<T>;
2015-07-07 20:25:58 +00:00
const vtkm::IdComponent NUM_COMPONENTS = Traits::NUM_COMPONENTS;
2018-02-22 13:29:13 +00:00
using ComponentType = typename Traits::ComponentType;
2015-07-07 20:25:58 +00:00
T zeroVector = T(ComponentType(0));
T normalizedVector = T(vtkm::RSqrt(ComponentType(NUM_COMPONENTS)));
T posVec = TestValue(1, T());
T negVec = -TestValue(2, T());
TestVector(zeroVector);
TestVector(normalizedVector);
TestVector(posVec);
TestVector(negVec);
T weight(ComponentType(0.5));
ComponentType weightS(0.5);
2017-05-18 14:29:41 +00:00
TestLerp(zeroVector, normalizedVector, weight, weightS);
TestLerp(zeroVector, posVec, weight, weightS);
TestLerp(zeroVector, negVec, weight, weightS);
2015-07-07 20:25:58 +00:00
2017-05-18 14:29:41 +00:00
TestLerp(normalizedVector, zeroVector, weight, weightS);
TestLerp(normalizedVector, posVec, weight, weightS);
TestLerp(normalizedVector, negVec, weight, weightS);
2015-07-07 20:25:58 +00:00
2017-05-18 14:29:41 +00:00
TestLerp(posVec, zeroVector, weight, weightS);
TestLerp(posVec, normalizedVector, weight, weightS);
TestLerp(posVec, negVec, weight, weightS);
2015-07-07 20:25:58 +00:00
2017-05-18 14:29:41 +00:00
TestLerp(negVec, zeroVector, weight, weightS);
TestLerp(negVec, normalizedVector, weight, weightS);
TestLerp(negVec, posVec, weight, weightS);
2015-07-07 20:25:58 +00:00
}
};
struct TestCrossFunctor
{
2017-05-18 14:29:41 +00:00
template <typename VectorType>
void operator()(const VectorType&) const
2015-07-07 20:25:58 +00:00
{
2017-05-18 14:29:41 +00:00
TestCross(VectorType(1.0f, 0.0f, 0.0f), VectorType(0.0f, 1.0f, 0.0f));
TestCross(VectorType(1.0f, 2.0f, 3.0f), VectorType(-3.0f, -1.0f, 1.0f));
TestCross(VectorType(0.0f, 0.0f, 1.0f), VectorType(0.001f, 0.01f, 2.0f));
2015-07-07 20:25:58 +00:00
}
};
struct TestVectorFunctor
{
template <typename VectorType>
void operator()(const VectorType&) const
{
constexpr int NUM_COMPONENTS = VectorType::NUM_COMPONENTS;
using Traits = vtkm::VecTraits<VectorType>;
using ComponentType = typename Traits::ComponentType;
vtkm::Vec<VectorType, NUM_COMPONENTS> basis;
VectorType normalizedVector = VectorType(vtkm::RSqrt(ComponentType(NUM_COMPONENTS)));
VectorType zeroVector = VectorType(ComponentType(0));
// Test with a degenerate set of inputs:
basis[0] = zeroVector;
basis[1] = normalizedVector;
for (int ii = 2; ii < NUM_COMPONENTS; ++ii)
{
basis[ii] = zeroVector;
}
TestOrthonormalize(basis, 1);
// Now test with a valid set of inputs:
for (int ii = 0; ii < NUM_COMPONENTS; ++ii)
{
for (int jj = 0; jj < NUM_COMPONENTS; ++jj)
{
basis[ii][jj] =
ComponentType(jj == ii ? 1.0 : 0.0) + ComponentType(0.05) * ComponentType(jj);
}
}
TestOrthonormalize(basis, NUM_COMPONENTS);
}
};
2015-07-07 20:25:58 +00:00
void TestVectorAnalysis()
{
vtkm::testing::Testing::TryTypes(TestLinearFunctor(), vtkm::TypeListField());
vtkm::testing::Testing::TryTypes(TestCrossFunctor(), vtkm::TypeListFieldVec3());
vtkm::testing::Testing::TryTypes(TestVectorFunctor(), vtkm::TypeListFloatVec());
2015-07-07 20:25:58 +00:00
}
} // anonymous namespace
int UnitTestVectorAnalysis(int argc, char* argv[])
2015-07-07 20:25:58 +00:00
{
return vtkm::testing::Testing::Run(TestVectorAnalysis, argc, argv);
2015-07-07 20:25:58 +00:00
}