#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_COSINEINTERPOLATOR_H #define NUCLEX_GEOMETRY_LINES_INTERPOLATORS_COSINEINTERPOLATOR_H #include "Nuclex/Geometry/Config.h" #include "Nuclex/Geometry/Point2.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 eases in and out between vertices /// Type of the interpolated values /// Additional information about the vertex type template struct CosineInterpolator { /// /// Performs cosine interpolation between the vertices at 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 cosine-interpolated position at 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; } // Truncate to obtain left vertex and right vertex index std::size_t leftVertexIndex = TVertexTraits::TruncateScalarToInteger(t); std::size_t rightVertexIndex = leftVertexIndex + 1; // Asking for a time past the last vertex? Clamp to last vertex std::size_t count = onePastLast - first; if(rightVertexIndex > count - 1) { return *(onePastLast - 1); } // At this point we know the leftVertex is at least index 0 and // the rightVertex is at least one before the end. Interpolate. t -= leftVertexIndex; t = 1 - Math::Cosine( t * Math::Pi ); t /= 2; TVertex leftVertex = *(first + leftVertexIndex); TVertex rightVertex = *(first + rightVertexIndex); leftVertex += (rightVertex - leftVertex) * t; return leftVertex; } /// /// Performs cosine interpolation between the vertices at 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 cosine-interpolated position at the specified distance /// /// This is identical to the linear interpolator because the cosine interpolator's /// path differs in time, but not in space (the curve you may know from friendly /// illustrations is a 1D interpolation where the X axis is time). /// public: template static TVertex InterpolateByDistance( TVertexIterator first, TVertexIterator onePastLast, typename TVertexTraits::TDistance distance ) { // Empty vertex list? Return 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 interpolated position on the current segment; ++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) { typename TVertexTraits::TScalar t = distance / segmentLength; previous += (current - previous) * t; return previous; } 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 a path when cosine-interpolated /// 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 path /// /// This is identical to the linear interpolator because the cosine interpolator's /// path differs in time, but not in space (the curve you may know from friendly /// illustrations is a 1D interpolation where the X axis is time). /// 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 0; } 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_COSINEINTERPOLATOR_H