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>
572class piecewise_interpolator_storage :
public interpolator<ValueT, ParamT> {
574 using point_type = PointT;
576 piecewise_interpolator_storage() {}
578 piecewise_interpolator_storage(std::initializer_list<point_type> points) : points(points) {}
580 piecewise_interpolator_storage(
const std::vector<point_type>& points) : points(points) {}
582 template<
class IteratorT>
583 piecewise_interpolator_storage(IteratorT first, IteratorT last) {
584 points.assign(first, last);
587 std::vector<point_type> points;
590template<
typename ValueT,
typename ParamT =
float>
593 identity_interpolator() {}
595 std::unique_ptr<interpolator<ValueT, ParamT>> clone()
const override {
596 return std::unique_ptr<interpolator<ValueT, ParamT>>(
new identity_interpolator(*
this));
599 ValueT at(ParamT t)
const override {
604template<
typename ValueT,
typename ParamT =
float>
606 using base = piecewise_interpolator_storage<ValueT, ValueT, ParamT>;
612template<
typename ValueT,
typename ParamT =
float>
614 using base = piecewise_interpolator_storage<std::pair<ParamT, ValueT>, ValueT, ParamT>;
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>
718 function_ref_interpolator(std::function<ValueT(ParamT)> function) : function(function) {}
720 std::unique_ptr<interpolator<ValueT, ParamT>> clone()
const override {
721 return std::unique_ptr<interpolator<ValueT, ParamT>>(
new function_ref_interpolator(*
this));
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...
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,...
this header is dependency free