8#include "compare_float.h"
21template<
typename ParamT =
float>
22ParamT map_to_domain(ParamT t,
const interval<ParamT>& domain = { 0.0f, 1.0f }) {
23 ParamT domain_size = domain.size();
24 if(!is_zero(domain_size))
25 return (t - domain.lower_bound) / domain_size;
26 return domain.lower_bound;
45template<
typename Po
intT,
typename InterpolationOp,
typename ParamT =
float>
46PointT interpolate_piece(
const std::vector<PointT>& points, ParamT t, InterpolationOp operation) {
48 return points.front();
53 size_t num_pairs = points.size() - 1;
54 size_t index =
static_cast<size_t>(t *
static_cast<ParamT
>(num_pairs));
55 ParamT step = ParamT(1) /
static_cast<ParamT
>(num_pairs);
56 ParamT prev =
static_cast<ParamT
>(index) * step;
57 ParamT curr =
static_cast<ParamT
>(index + 1) * step;
58 t = (t - prev) / (curr - prev);
59 return operation(points[index], points[index + 1], t);
80template<
typename Po
intT,
typename InterpolationOp,
typename ParamT =
float>
81PointT interpolate_piece(
const std::vector<std::pair<ParamT, PointT>>& points, ParamT t, InterpolationOp operation) {
82 using pair_type = std::pair<ParamT, PointT>;
84 if(t <= points.front().first)
85 return points.front().second;
87 auto it = std::lower_bound(points.begin(), points.end(), t, [](
const pair_type& point,
float value) { return point.first < value; });
88 if(it == points.end())
89 return points.back().second;
92 const pair_type& left = *(it == points.begin() ? it : it - 1);
93 const pair_type& right = *it;
94 t = (t - left.first) / (right.first - left.first);
95 return operation(left.second, right.second, t);
113template<
typename Po
intT,
typename InterpolationOp,
typename ParamT =
float>
114std::vector<PointT> interpolate_n(
const std::vector<std::pair<ParamT, PointT>>& points, InterpolationOp operation,
size_t n) {
115 using pair_type = std::pair<ParamT, PointT>;
117 if(n == 0 || points.size() == 0)
120 if(points.size() == 1)
121 return std::vector<PointT>(n, points.front().second);
123 std::vector<PointT> res;
128 ParamT size = points.back().first - points.front().first;
129 ParamT step = size /
static_cast<ParamT
>(n - 1);
130 for(
size_t i = 0; i < n; ++i) {
131 ParamT x = points.front().first + step *
static_cast<ParamT
>(i);
133 while(x > points[r].first && l < points.size() - 1) {
135 r = std::min(l + 1, points.size() - 1);
139 res.push_back(points[r].second);
141 const pair_type& p0 = points[l];
142 const pair_type& p1 = points[r];
143 ParamT t = (x - p0.first) / (p1.first - p0.first);
144 res.push_back(operation(p0.second, p1.second, t));
162template<
typename ParamT =
float,
typename OutputIt,
typename UnaryOp>
163static void sequence_transform(OutputIt output_first, UnaryOp operation,
size_t n, ParamT a = ParamT(0), ParamT b = ParamT(1)) {
165 *output_first = operation(ParamT(0.5) * (a + b));
169 ParamT step = size /
static_cast<ParamT
>(n - 1);
170 for(
size_t i = 0; i < n; ++i) {
171 ParamT t = a + step *
static_cast<ParamT
>(i);
172 *output_first = operation(t);
186template<
typename Po
intT,
typename ParamT =
float>
187PointT interpolate_nearest(
const PointT& p0,
const PointT& p1, ParamT t) {
188 return t < ParamT(0.5) ? p0 : p1;
199template<
typename Po
intT,
typename ParamT =
float>
200PointT interpolate_nearest(
const std::vector<PointT>& points, ParamT t,
const interval<ParamT>& domain = { 0.0f, 1.0f }) {
201 return detail::interpolate_piece(points, t,
static_cast<PointT(*)(
const PointT&,
const PointT&, ParamT)
>(&interpolate_nearest<PointT, ParamT>));
215template<
typename Po
intT,
typename ParamT =
float>
216PointT interpolate_nearest(
const std::vector<std::pair<ParamT, PointT>>& points, ParamT t) {
217 return detail::interpolate_piece(points, t,
static_cast<PointT(*)(
const PointT&,
const PointT&, ParamT)
>(&interpolate_nearest<PointT, ParamT>));
227template<
typename Po
intT,
typename ParamT =
float>
228std::vector<PointT> interpolate_nearest_n(
const std::vector<PointT>& points,
size_t n) {
229 std::vector<PointT> res;
231 sequence_transform(std::back_inserter(res), [&points](
float t) {
return interpolate_nearest(points, t); }, n);
245template<
typename Po
intT,
typename ParamT =
float>
246std::vector<PointT> interpolate_nearest_n(
const std::vector<std::pair<ParamT, PointT>>& points,
size_t n) {
247 return detail::interpolate_n(points,
static_cast<PointT(*)(
const PointT&,
const PointT&, ParamT)
>(&interpolate_nearest<PointT, ParamT>), n);
258template<
typename Po
intT,
typename ParamT =
float>
259static PointT interpolate_linear(
const PointT& p0,
const PointT& p1, ParamT t) {
260 PointT v0 = (ParamT(1) - t) * p0;
273template<
typename Po
intT,
typename ParamT =
float>
274PointT interpolate_linear(
const std::vector<PointT>& points, ParamT t,
const interval<ParamT>& domain = { 0.0f, 1.0f }) {
275 t = detail::map_to_domain(t, domain);
276 return detail::interpolate_piece(points, t,
static_cast<PointT(*)(
const PointT&,
const PointT&, ParamT)
>(&interpolate_linear<PointT, ParamT>));
290template<
typename Po
intT,
typename ParamT =
float>
291PointT interpolate_linear(
const std::vector<std::pair<ParamT, PointT>>& points, ParamT t) {
292 return detail::interpolate_piece(points, t,
static_cast<PointT(*)(
const PointT&,
const PointT&, ParamT)
>(&interpolate_linear<PointT, ParamT>));
302template<
typename Po
intT,
typename ParamT =
float>
303std::vector<PointT> interpolate_linear_n(
const std::vector<PointT>& points,
size_t n) {
304 std::vector<PointT> res;
306 sequence_transform(std::back_inserter(res), [&points](
float t) {
return interpolate_linear(points, t); }, n);
320template<
typename Po
intT,
typename ParamT =
float>
321std::vector<PointT> interpolate_linear_n(
const std::vector<std::pair<ParamT, PointT>>& points,
size_t n) {
322 return detail::interpolate_n(points,
static_cast<PointT(*)(
const PointT&,
const PointT&, ParamT)
>(&interpolate_linear<PointT, ParamT>), n);
334template<
typename Po
intT,
typename ParamT =
float>
335static PointT interpolate_quadratic_bezier(
const PointT& p0,
const PointT& p1,
const PointT& p2, ParamT t) {
336 ParamT mt = ParamT(1) - t;
337 PointT v0 = mt * mt * p0;
338 PointT v1 = ParamT(2) * mt * t * p1;
339 PointT v2 = t * t * p2;
353template<
typename Po
intT,
typename ParamT =
float>
354static PointT interpolate_cubic_bezier(
const PointT& p0,
const PointT& p1,
const PointT& p2,
const PointT& p3, ParamT t) {
355 ParamT mt = ParamT(1) - t;
356 PointT v0 = mt * mt * mt * p0;
357 PointT v1 = ParamT(3) * mt * mt * t * p1;
358 PointT v2 = ParamT(3) * mt * t * t * p2;
359 PointT v3 = t * t * t * p3;
360 return v0 + v1 + v2 + v3;
373template<
typename Po
intT,
typename ParamT =
float>
374static PointT interpolate_cubic_hermite(
const PointT& p0,
const PointT& m0,
const PointT& p1,
const PointT& m1, ParamT t) {
376 ParamT t3 = t * t * t;
377 PointT w0 = ParamT(2) * t3 - ParamT(3) * t2 + ParamT(1);
378 PointT w1 = t3 - ParamT(2) * t2 + t;
379 PointT w2 = ParamT(-2) * t3 + ParamT(3) * t2;
381 return w0 * p0 + w1 * m0 + w2 * p1 + w3 * m1;
394template<
typename Po
intT,
typename ParamT =
float>
395static PointT interpolate_cubic_basis(
const PointT& b0,
const PointT& b1,
const PointT& b2,
const PointT& b3, ParamT t) {
397 ParamT t3 = t * t * t;
398 PointT v0 = (ParamT(1) - ParamT(3) * t + ParamT(3) * t2 - t3) * b0;
399 PointT v1 = (ParamT(4) - ParamT(6) * t2 + ParamT(3) * t3) * b1;
400 PointT v2 = (ParamT(1) + ParamT(3) * t + ParamT(3) * t2 - ParamT(3) * t3) * b2;
402 return (ParamT(1) / ParamT(6)) * (v0 + v1 + v2 + v3);
417template<
typename Po
intT,
typename ParamT =
float>
418PointT interpolate_smooth_cubic(
const std::vector<PointT>& points, ParamT t,
const interval<ParamT>& domain = { 0.0f, 1.0f }) {
419 t = detail::map_to_domain(t, domain);
421 size_t num_pairs = points.size() - 1;
426 }
else if(t >= ParamT(1)) {
430 i =
static_cast<size_t>(t *
static_cast<float>(num_pairs));
433 PointT v1 = points[i];
434 PointT v2 = points[i + 1];
435 PointT v0 = i > 0 ? points[i - 1] : PointT(2) * v1 - v2;
436 PointT v3 = i < num_pairs - 1 ? points[i + 2] : PointT(2) * v2 - v1;
437 t = (t -
static_cast<float>(i) /
static_cast<float>(num_pairs)) *
static_cast<float>(num_pairs);
438 return interpolate_cubic_basis(v0, v1, v2, v3, t);
454template<
typename Po
intT,
typename ParamT =
float>
455PointT interpolate_smooth_cubic(
const std::vector<std::pair<ParamT, PointT>>& points, ParamT t) {
456 using pair_type = std::pair<ParamT, PointT>;
458 size_t num_pairs = points.size() - 1;
461 return points.front().second;
463 auto it = std::lower_bound(points.begin(), points.end(), t, [](
const pair_type& point,
float value) { return point.first < value; });
464 if(it == points.end())
465 return points.back().second;
467 if(it != points.begin())
470 size_t i = std::distance(points.begin(), it);
472 pair_type v1 = points[i];
473 pair_type v2 = points[i + 1];
474 PointT v0 = i > 0 ? points[i - 1].second : PointT(2) * v1.second - v2.second;
475 PointT v3 = i < num_pairs - 1 ? points[i + 2].second : PointT(2) * v2.second - v1.second;
476 t = (t - v1.first) / (v2.first - v1.first);
477 return interpolate_cubic_basis(v0, v1.second, v2.second, v3, t);
489template<
typename Po
intT,
typename ParamT =
float>
490std::vector<PointT> interpolate_smooth_cubic_n(
const std::vector<PointT>& points,
size_t n) {
491 std::vector<PointT> res;
493 sequence_transform(std::back_inserter(res), [&points](
float t) {
return interpolate_smooth_cubic(points, t); }, n);
506template<
typename Po
intT,
typename ParamT =
float>
507std::vector<PointT> interpolate_smooth_cubic_n(
const std::vector<std::pair<ParamT, PointT>>& points,
size_t n) {
508 std::vector<PointT> res;
510 sequence_transform(std::back_inserter(res), [&points](
float t) {
return interpolate_smooth_cubic(points, t); }, n);
515template<
typename X,
typename Y>
524 x = detail::map_to_domain(x,
domain);
533 size_t index =
static_cast<size_t>(x *
static_cast<X
>(num_pieces));
535 X step = X(1) /
static_cast<X
>(num_pieces);
536 X prev =
static_cast<X
>(index) * step;
537 X curr =
static_cast<X
>(index + 1) * step;
538 X t = (x - prev) / (curr - prev);
544template<
typename ValueT,
typename ParamT =
float>
549 virtual std::unique_ptr<interpolator> clone()
const = 0;
554 virtual ValueT
at(ParamT t)
const = 0;
563 virtual std::vector<ValueT>
quantize(
size_t n)
const {
564 std::vector<ValueT> samples;
566 sequence_transform<ParamT>(std::back_inserter(samples), [
this](ParamT t) {
return at(t); }, n);
571template<
typename Po
intT,
typename ValueT,
typename ParamT =
float>
574 using point_type = PointT;
582 template<
class IteratorT>
584 points.assign(first, last);
587 std::vector<point_type> points;
590template<
typename ValueT,
typename ParamT =
float>
595 std::unique_ptr<interpolator<ValueT, ParamT>> clone()
const override {
599 ValueT
at(ParamT t)
const override {
604template<
typename ValueT,
typename ParamT =
float>
612template<
typename ValueT,
typename ParamT =
float>
620template<
typename ValueT,
typename ParamT =
float>
627 std::unique_ptr<interpolator<ValueT, ParamT>> clone()
const override {
631 ValueT
at(ParamT t)
const override {
632 size_t num_points = this->points.size();
635 return this->points.front();
636 else if(t >= ParamT(1))
637 return this->points.back();
639 return this->points[std::min(
static_cast<size_t>(t *
static_cast<ParamT
>(num_points)), num_points - 1)];
643template<
typename ValueT,
typename ParamT =
float>
650 std::unique_ptr<interpolator<ValueT, ParamT>> clone()
const override {
654 ValueT
at(ParamT t)
const override {
655 return interpolate_linear(this->points, t);
658 std::vector<ValueT>
quantize(
size_t n)
const override {
659 return interpolate_linear_n(this->points, n);
663template<
typename ValueT,
typename ParamT =
float>
670 std::unique_ptr<interpolator<ValueT, ParamT>> clone()
const override {
674 ValueT
at(ParamT t)
const override {
675 return interpolate_linear(this->points, t);
678 std::vector<ValueT>
quantize(
size_t n)
const override {
679 return interpolate_linear_n(this->points, n);
683template<
typename ValueT,
typename ParamT =
float>
690 std::unique_ptr<interpolator<ValueT, ParamT>> clone()
const override {
694 ValueT
at(ParamT t)
const override {
695 return interpolate_smooth_cubic(this->points, t);
699template<
typename ValueT,
typename ParamT =
float>
706 std::unique_ptr<interpolator<ValueT, ParamT>> clone()
const override {
710 ValueT
at(ParamT t)
const override {
711 return interpolate_smooth_cubic(this->points, t);
715template<
typename ValueT,
typename ParamT =
float>
720 std::unique_ptr<interpolator<ValueT, ParamT>> clone()
const override {
724 ValueT
at(ParamT t)
const override {
730 std::function<ValueT(ParamT)> function;
base class for all classes that can be registered with support for dynamic properties (see also secti...
ValueT at(ParamT t) const override
Return the interpolated value at position t.
ValueT at(ParamT t) const override
Return the interpolated value at position t.
ValueT at(ParamT t) const override
Return the interpolated value at position t.
Template of an abstract interface for interpolators that can be evaluated at a position t and return ...
virtual ValueT at(ParamT t) const =0
Return the interpolated value at position t.
virtual std::vector< ValueT > quantize(size_t n) const
Return a sequence of n uniformly-spaced samples from the interpolator within the parameter range [0,...
The interval template represents a closed interval of two numbers, i.e.
std::vector< ValueT > quantize(size_t n) const override
Return a sequence of n uniformly-spaced samples from the interpolator within the parameter range [0,...
ValueT at(ParamT t) const override
Return the interpolated value at position t.
ValueT at(ParamT t) const override
Return the interpolated value at position t.
this header is dependency free