vtk-m2/vtkm/testing/UnitTestVectorAnalysis.cxx

243 lines
8.4 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
//to do have to implement a norm and normalized call to verify the math ones
//against
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
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
{
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
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.");
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)
{
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
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
{
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);
// The cross product result should be perpendicular to input vectors.
VTKM_TEST_ASSERT(vtkm::Abs(vtkm::Dot(cross, x)) <
std::numeric_limits<T>::epsilon() * vtkm::MagnitudeSquared(x),
"Cross product not perpendicular.");
VTKM_TEST_ASSERT(vtkm::Abs(vtkm::Dot(cross, y)) <
std::numeric_limits<T>::epsilon() * vtkm::MagnitudeSquared(y),
"Cross product not perpendicular.");
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.");
// Test finding the normal to a triangle (similar to cross product).
Vec3 normal = vtkm::TriangleNormal(x, y, Vec3(0, 0, 0));
VTKM_TEST_ASSERT(vtkm::Abs(vtkm::Dot(normal, x - y)) <
std::numeric_limits<T>::epsilon() * vtkm::MagnitudeSquared(x),
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);
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));
// Example from: https://pharr.org/matt/blog/2019/11/03/difference-of-floats.html
TestCross(VectorType(33962.035f, 41563.4f, 7706.415f),
VectorType(-24871.969f, -30438.8f, -5643.727f));
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
}