#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 #ifndef NUCLEX_GEOMETRY_LINES_INTERPOLATORS_NEARESTINTERPOLATOR_H #define NUCLEX_GEOMETRY_LINES_INTERPOLATORS_NEARESTINTERPOLATOR_H #include "Nuclex/Geometry/Config.h" #include "Nuclex/Geometry/Lines/CurveInterpolationMethod.h" #include namespace Nuclex { namespace Geometry { namespace Lines { namespace Interpolators { // ------------------------------------------------------------------------------------------- // #if 0 /// Example implementation of the TVertexTraits type struct ExampleVertexTraits { /// 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 float ZeroVertex = 0.0f; /// 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(float first, float second) { return std::abs(second - first), } /// 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); } }; #endif // ------------------------------------------------------------------------------------------- // /// Interpolator that clamps to the nearest vertex in a sequence /// Type of the interpolated values /// Additional information about the vertex type template struct NearestInterpolator { /// Returns the closest vertex to the specified time index /// Type of the iterator used to find vertices /// Iterator pointing to the first vertex /// Iterator pointing one past the last vertex /// Interpolation time index, equivalent to vertex index /// The closest vertex to the specified time index public: template static TVertex InterpolateByTime( TVertexIterator first, TVertexIterator onePastLast, typename TVertexTraits::TScalar t ) { // Empty vertex list? Return default value if(onePastLast == first) { return TVertexTraits::ZeroVertex; } // Asking for a time before the first vertex? Clamp to first vertex if(t < 0) { return *first; } // Round to closest vertex index std::size_t nearestVertexIndex = TVertexTraits::RoundScalarToInteger(t); // Asking for a time past the last vertex? Clamp to last vertex std::size_t count = onePastLast - first; if(nearestVertexIndex >= count - 1) { return *(onePastLast - 1); } // Regular query, return closest vertex return *(first + nearestVertexIndex); } /// Returns the closest vertex to the specified distance /// Type of the iterator used to find vertices /// Iterator pointing to the first vertex /// Iterator pointing one past the last vertex /// Distance along the path to interpolate /// The closest vertex to the specified distance public: template static TVertex InterpolateByDistance( TVertexIterator first, TVertexIterator onePastLast, typename TVertexTraits::TDistance distance ) { // Empty vertex list? Return the default value if(onePastLast == first) { return TVertexTraits::ZeroVertex; } // If the distance is zero or less, return the starting point TVertex previous = *first; if(distance < 0) { return previous; } // Go through all segments and if the distance falls into the current segment, // return the closer of the to vertices ++first; while(first != onePastLast) { TVertex current = *first; typename TVertexTraits::TDistance segmentLength = TVertexTraits::DistanceBetween( previous, current ); // Does the user-specified distance fall into this segment? if(segmentLength >= distance) { if(segmentLength - distance > distance) { // Closer to left vertex? return previous; } else { // Closer to right vertex return current; } } distance -= segmentLength; previous = current; ++first; } // Specified distance was beyond the end of the path, return the lastmost // vertex we processed (thereby clamping to the end of the path) return previous; } /// Estimates the length of the curve /// Type of the iterator used to find vertices /// Iterator pointing to the first vertex /// Iterator pointing one past the last vertex /// The length of the curve public: template static typename TVertexTraits::TDistance EstimateLength( TVertexIterator first, TVertexIterator onePastLast ) { // Empty vertex list? The path has a length of 0 if(onePastLast == first) { return TVertexTraits::ZeroVertex; } TVertex previous = *first; typename TVertexTraits::TDistance distance = 0; // Advance through all points, accumulating the total distance ++first; while(first != onePastLast) { TVertex current = *first; distance += TVertexTraits::DistanceBetween(previous, current); previous = current; ++first; } return distance; } }; // ------------------------------------------------------------------------------------------- // }}}} // namespace Nuclex::Geometry::Lines::Interpolators #endif // NUCLEX_GEOMETRY_LINES_INTERPOLATORS_NEARESTINTERPOLATOR_H