#pragma region CPL License /* Nuclex Native Framework Copyright (C) 2002-2015 Nuclex Development Labs This library is free software; you can redistribute it and/or modify it under the terms of the IBM Common Public License as published by the IBM Corporation; either version 1.0 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the IBM Common Public License for more details. You should have received a copy of the IBM Common Public License along with this library */ #pragma endregion // CPL License // If the library is compiled as a DLL, this ensures symbols are exported #define NUCLEX_GEOMETRY_SOURCE 1 #include "Nuclex/Geometry/Lines/Interpolators/LinearInterpolator.h" #include "Nuclex/Geometry/Point2.h" #include namespace { // ------------------------------------------------------------------------------------------- // /// Vertex traits for Point2 types when used in interpolators struct Point2VertexTraits { /// Type that is used to measure distance between vertices public: typedef float TDistance; /// Type that is used to specify the interpolation interval public: typedef float TScalar; /// A vertex with a value of zero public: static const Nuclex::Geometry::Point2 ZeroVertex; /// Measures the distance between two vertices /// First vertex for the distance calculation /// Second vertex for the distance calculation /// The distance between the two vertices public: static TDistance DistanceBetween( const Nuclex::Geometry::Point2 &first, const Nuclex::Geometry::Point2 &second ) { return Nuclex::Geometry::Point2::DistanceBetween(first, second); } /// Rounds a scalar / interval value to the closest integer /// Scalar / interval value that will be rounded /// The closest integer to the specified scalar / interval value public: static std::size_t RoundScalarToInteger(float t) { return static_cast(t + 0.5f); } /// Truncates a scalar / interval value to the next lower integer /// Scalar / interval value that will be truncated /// The next lower integer to the specified scalar / interval value public: static std::size_t TruncateScalarToInteger(float t) { return static_cast(t); } }; // ------------------------------------------------------------------------------------------- // const Nuclex::Geometry::Point2 Point2VertexTraits::ZeroVertex(0.0f, 0.0f); // ------------------------------------------------------------------------------------------- // /// Verifies that a point lies near to another point /// First point that will be compared /// Second point that will be compared /// True if the first point is near the void ExpectIsNear( const Nuclex::Geometry::Point2 &first, const Nuclex::Geometry::Point2 &second ) { const float Tolerance = 1.e-006f; EXPECT_NEAR(first.X, second.X, Tolerance); EXPECT_NEAR(first.Y, second.Y, Tolerance); } // ------------------------------------------------------------------------------------------- // /// Interpolator we use for testing typedef Nuclex::Geometry::Lines::Interpolators::LinearInterpolator< Nuclex::Geometry::Point2, Point2VertexTraits > InterpolatorType; // ------------------------------------------------------------------------------------------- // } // anonymous namespace namespace Nuclex { namespace Geometry { namespace Lines { namespace Interpolators { // ------------------------------------------------------------------------------------------- // TEST(LinearInterpolatorTest, InterpolateByTimeHandlesEmptyPath) { std::vector> vertices; EXPECT_EQ( Point2::Zero, InterpolatorType::InterpolateByTime(vertices.begin(), vertices.end(), 0.5f) ); } // ------------------------------------------------------------------------------------------- // TEST(LinearInterpolatorTest, InterpolateByTimeHandlesSingleVertex) { std::vector> vertices; vertices.push_back(Point2(5.0f, 5.0f)); EXPECT_EQ( vertices[0], InterpolatorType::InterpolateByTime(vertices.begin(), vertices.end(), -1.1f) ); EXPECT_EQ( vertices[0], InterpolatorType::InterpolateByTime(vertices.begin(), vertices.end(), 0.0f) ); EXPECT_EQ( vertices[0], InterpolatorType::InterpolateByTime(vertices.begin(), vertices.end(), 1.1f) ); } // ------------------------------------------------------------------------------------------- // TEST(LinearInterpolatorTest, VertexCanBeInterpolatedByTime) { std::vector> vertices; vertices.push_back(Point2(1.0f, 5.0f)); vertices.push_back(Point2(10.0f, 6.0f)); vertices.push_back(Point2(9.0f, 10.0f)); vertices.push_back(Point2(5.0f, 1.0f)); EXPECT_EQ( vertices[0], InterpolatorType::InterpolateByTime(vertices.begin(), vertices.end(), 0.0f) ); EXPECT_EQ( Point2(5.41f, 5.49f), InterpolatorType::InterpolateByTime(vertices.begin(), vertices.end(), 0.49f) ); EXPECT_EQ( Point2(5.59f, 5.51f), InterpolatorType::InterpolateByTime(vertices.begin(), vertices.end(), 0.51f) ); EXPECT_EQ( Point2(7.08f, 5.68f), InterpolatorType::InterpolateByTime(vertices.begin(), vertices.end(), 2.48f) ); EXPECT_EQ( Point2(6.92f, 5.32f), InterpolatorType::InterpolateByTime(vertices.begin(), vertices.end(), 2.52f) ); } // ------------------------------------------------------------------------------------------- // TEST(LinearInterpolatorTest, InterpolateByTimeClamps) { std::vector> vertices; vertices.push_back(Point2(1.0f, 5.0f)); vertices.push_back(Point2(10.0f, 1.0f)); vertices.push_back(Point2(5.0f, 10.0f)); EXPECT_EQ( vertices[0], InterpolatorType::InterpolateByTime(vertices.begin(), vertices.end(), -0.1f) ); EXPECT_EQ( vertices[0], InterpolatorType::InterpolateByTime(vertices.begin(), vertices.end(), -2.5f) ); EXPECT_EQ( vertices[2], InterpolatorType::InterpolateByTime(vertices.begin(), vertices.end(), 2.1f) ); EXPECT_EQ( vertices[2], InterpolatorType::InterpolateByTime(vertices.begin(), vertices.end(), 4.5f) ); } // ------------------------------------------------------------------------------------------- // TEST(LinearInterpolatorTest, InterpolateByDistanceHandlesEmptyPath) { std::vector> vertices; EXPECT_EQ( Point2::Zero, InterpolatorType::InterpolateByDistance(vertices.begin(), vertices.end(), 0.5f) ); } // ------------------------------------------------------------------------------------------- // TEST(LinearInterpolatorTest, InterpolateByDistanceHandlesSingleVertex) { std::vector> vertices; vertices.push_back(Point2(5.0f, 5.0f)); EXPECT_EQ( vertices[0], InterpolatorType::InterpolateByDistance(vertices.begin(), vertices.end(), -1.1f) ); EXPECT_EQ( vertices[0], InterpolatorType::InterpolateByDistance(vertices.begin(), vertices.end(), 0.0f) ); EXPECT_EQ( vertices[0], InterpolatorType::InterpolateByDistance(vertices.begin(), vertices.end(), 1.1f) ); } // ------------------------------------------------------------------------------------------- // TEST(LinearInterpolatorTest, VertexCanBeInterpolatedByDistance) { std::vector> vertices; vertices.push_back(Point2(1.0f, 5.0f)); vertices.push_back(Point2(10.0f, 6.0f)); vertices.push_back(Point2(9.0f, 10.0f)); vertices.push_back(Point2(5.0f, 1.0f)); EXPECT_EQ( vertices[0], InterpolatorType::InterpolateByDistance(vertices.begin(), vertices.end(), 0.0f) ); ExpectIsNear( Point2(5.4724768060312850411736491557f, 5.4969418673368094490192943506f), InterpolatorType::InterpolateByDistance(vertices.begin(), vertices.end(), 4.5f) ); ExpectIsNear( Point2(5.5718651794986469309775080258f, 5.5079850199442941034419453362f), InterpolatorType::InterpolateByDistance(vertices.begin(), vertices.end(), 4.6f) ); ExpectIsNear( Point2(7.0417996347289572632238987003f, 5.5940491781401538422537720758f), InterpolatorType::InterpolateByDistance(vertices.begin(), vertices.end(), 18.0f) ); ExpectIsNear( Point2(6.9605719415182677397455794309f, 5.4112868684161024144275537196f), InterpolatorType::InterpolateByDistance(vertices.begin(), vertices.end(), 18.2f) ); } // ------------------------------------------------------------------------------------------- // TEST(LinearInterpolatorTest, InterpolateByDistanceClamps) { std::vector> vertices; vertices.push_back(Point2(1.0f, 5.0f)); vertices.push_back(Point2(10.0f, 1.0f)); vertices.push_back(Point2(5.0f, 10.0f)); EXPECT_EQ( vertices[0], InterpolatorType::InterpolateByDistance(vertices.begin(), vertices.end(), -0.1f) ); EXPECT_EQ( vertices[0], InterpolatorType::InterpolateByDistance(vertices.begin(), vertices.end(), -15.0f) ); EXPECT_EQ( vertices[2], InterpolatorType::InterpolateByDistance(vertices.begin(), vertices.end(), 23.1f) ); EXPECT_EQ( vertices[2], InterpolatorType::InterpolateByDistance(vertices.begin(), vertices.end(), 35.0f) ); } // ------------------------------------------------------------------------------------------- // TEST(LinearInterpolatorTest, LengthHandlesEmptyPath) { std::vector> vertices; EXPECT_EQ( 0.0f, InterpolatorType::EstimateLength(vertices.begin(), vertices.end()) ); } // ------------------------------------------------------------------------------------------- // TEST(LinearInterpolatorTest, LengthHandlesSingleVertex) { std::vector> vertices; vertices.push_back(Point2(5.0f, 5.0f)); EXPECT_EQ( 0.0f, InterpolatorType::EstimateLength(vertices.begin(), vertices.end()) ); } // ------------------------------------------------------------------------------------------- // TEST(LinearInterpolatorTest, LengthCanBeEstimated) { std::vector> vertices; vertices.push_back(Point2(1.0f, 5.0f)); vertices.push_back(Point2(10.0f, 6.0f)); vertices.push_back(Point2(9.0f, 10.0f)); vertices.push_back(Point2(5.0f, 1.0f)); EXPECT_EQ( 23.027348565551183f, InterpolatorType::EstimateLength(vertices.begin(), vertices.end()) ); } // ------------------------------------------------------------------------------------------- // }}}} // namespace Nuclex::Geometry::Lines::Interpolators