cgv
Loading...
Searching...
No Matches
interpolate.h
1#pragma once
2
3#include "interval.h"
4
5namespace cgv {
6namespace math {
7
8namespace detail {
9
26template<typename PointT, typename InterpolationOp, typename ParamT = float>
27PointT interpolate_piece(const std::vector<PointT>& points, ParamT t, InterpolationOp operation) {
28 if(t <= ParamT(0))
29 return points.front();
30
31 if(t >= ParamT(1))
32 return points.back();
33
34 size_t num_pairs = points.size() - 1;
35 size_t index = static_cast<size_t>(t * static_cast<ParamT>(num_pairs));
36 ParamT step = ParamT(1) / static_cast<ParamT>(num_pairs);
37 ParamT prev = static_cast<ParamT>(index) * step;
38 ParamT curr = static_cast<ParamT>(index + 1) * step;
39 t = (t - prev) / (curr - prev);
40 return operation(points[index], points[index + 1], t);
41}
42
61template<typename PointT, typename InterpolationOp, typename ParamT = float>
62PointT interpolate_piece(const std::vector<std::pair<ParamT, PointT>>& points, ParamT t, InterpolationOp operation) {
63 using pair_type = std::pair<ParamT, PointT>;
64
65 if(t <= 0)
66 return points.front().second;
67
68 auto it = std::lower_bound(points.begin(), points.end(), t, [](const pair_type& point, float value) { return point.first < value; });
69 if(it == points.end())
70 return points.back().second;
71
72 // "it" points to the first point whose parameter position is larger than t
73 const pair_type& left = *(it == points.begin() ? it : it - 1);
74 const pair_type& right = *it;
75 t = (t - left.first) / (right.first - left.first);
76 return operation(left.second, right.second, t);
77}
78
94template<typename PointT, typename InterpolationOp, typename ParamT = float>
95std::vector<PointT> interpolate_n(const std::vector<std::pair<ParamT, PointT>>& points, InterpolationOp operation, size_t n) {
96 using pair_type = std::pair<ParamT, PointT>;
97
98 if(n == 0 || points.size() == 0)
99 return {};
100
101 if(points.size() == 1)
102 return std::vector<PointT>(n, points.front().second);
103
104 size_t l = 0;
105 size_t r = 1;
106
107 if(points.front().first > ParamT(0))
108 r = 0;
109
110 std::vector<PointT> res;
111 res.reserve(n);
112
113 ParamT step = ParamT(1) / static_cast<ParamT>(n - 1);
114
115 for(size_t i = 0; i < n; ++i) {
116 ParamT x = static_cast<ParamT>(i) * step;
117
118 while(x > points[r].first && l < points.size() - 1) {
119 l = r;
120 r = std::min(l + 1, points.size() - 1);
121 }
122
123 if(l == r) {
124 res.push_back(points[r].second);
125 } else {
126 const pair_type& p0 = points[l];
127 const pair_type& p1 = points[r];
128 ParamT t = (x - p0.first) / (p1.first - p0.first);
129 res.push_back(operation(p0.second, p1.second, t));
130 }
131 }
132 return res;
133}
134
135} // namespace detail
136
145template<typename ParamT = float, typename OutputIt, typename UnaryOp>
146static void sequence_transform(OutputIt output_first, UnaryOp operation, size_t n) {
147 if(n == 1) {
148 *output_first = operation(ParamT(0.5));
149 ++output_first;
150 } else if(n > 1) {
151 ParamT step = ParamT(1) / static_cast<ParamT>(n - 1);
152 for(size_t i = 0; i < n; ++i) {
153 ParamT t = step * static_cast<ParamT>(i);
154 *output_first = operation(t);
155 ++output_first;
156 }
157 }
158}
159
168template<typename PointT, typename ParamT = float>
169PointT interpolate_nearest(const PointT& p0, const PointT& p1, ParamT t) {
170 return t < ParamT(0.5) ? p0 : p1;
171};
172
181template<typename PointT, typename ParamT = float>
182PointT interpolate_nearest(const std::vector<PointT>& points, ParamT t, const interval<ParamT>& domain = { 0.0f, 1.0f }) {
183 return detail::interpolate_piece(points, t, static_cast<PointT(*)(const PointT&, const PointT&, ParamT)>(&interpolate_nearest<PointT, ParamT>));
184};
185
197template<typename PointT, typename ParamT = float>
198PointT interpolate_nearest(const std::vector<std::pair<ParamT, PointT>>& points, ParamT t) {
199 return detail::interpolate_piece(points, t, static_cast<PointT(*)(const PointT&, const PointT&, ParamT)>(&interpolate_nearest<PointT, ParamT>));
200}
201
209template<typename PointT, typename ParamT = float>
210std::vector<PointT> interpolate_nearest_n(const std::vector<PointT>& points, size_t n) {
211 std::vector<PointT> res;
212 res.reserve(n);
213 sequence_transform(std::back_inserter(res), [&points](float t) { return cgv::math::interpolate_nearest(points, t); }, n);
214 return res;
215};
216
227template<typename PointT, typename ParamT = float>
228std::vector<PointT> interpolate_nearest_n(const std::vector<std::pair<ParamT, PointT>>& points, size_t n) {
229 return detail::interpolate_n(points, static_cast<PointT(*)(const PointT&, const PointT&, ParamT)>(&interpolate_nearest<PointT, ParamT>), n);
230}
231
240template<typename PointT, typename ParamT = float>
241static PointT interpolate_linear(const PointT& p0, const PointT& p1, ParamT t) {
242 PointT v0 = (ParamT(1) - t) * p0;
243 PointT v1 = t * p1;
244 return v0 + v1;
245}
246
255template<typename PointT, typename ParamT = float>
256PointT interpolate_linear(const std::vector<PointT>& points, ParamT t, const interval<ParamT>& domain = { 0.0f, 1.0f }) {
257 t = (t - domain.lower_bound) / domain.size();
258 return detail::interpolate_piece(points, t, static_cast<PointT(*)(const PointT&, const PointT&, ParamT)>(&interpolate_linear<PointT, ParamT>));
259};
260
272template<typename PointT, typename ParamT = float>
273PointT interpolate_linear(const std::vector<std::pair<ParamT, PointT>>& points, ParamT t) {
274 return detail::interpolate_piece(points, t, static_cast<PointT(*)(const PointT&, const PointT&, ParamT)>(&interpolate_linear<PointT, ParamT>));
275}
276
284template<typename PointT, typename ParamT = float>
285std::vector<PointT> interpolate_linear_n(const std::vector<PointT>& points, size_t n) {
286 std::vector<PointT> res;
287 res.reserve(n);
288 sequence_transform(std::back_inserter(res), [&points](float t) { return cgv::math::interpolate_linear(points, t); }, n);
289 return res;
290};
291
302template<typename PointT, typename ParamT = float>
303std::vector<PointT> interpolate_linear_n(const std::vector<std::pair<ParamT, PointT>>& points, size_t n) {
304 return detail::interpolate_n(points, static_cast<PointT(*)(const PointT&, const PointT&, ParamT)>(&interpolate_linear<PointT, ParamT>), n);
305}
306
316template<typename PointT, typename ParamT = float>
317static PointT interpolate_quadratic_bezier(const PointT& p0, const PointT& p1, const PointT& p2, ParamT t) {
318 ParamT mt = ParamT(1) - t;
319 PointT v0 = mt * mt * p0;
320 PointT v1 = ParamT(2) * mt * t * p1;
321 PointT v2 = t * t * p2;
322 return v0 + v1 + v2;
323}
324
335template<typename PointT, typename ParamT = float>
336static PointT interpolate_cubic_bezier(const PointT& p0, const PointT& p1, const PointT& p2, const PointT& p3, ParamT t) {
337 ParamT mt = ParamT(1) - t;
338 PointT v0 = mt * mt * mt * p0;
339 PointT v1 = ParamT(3) * mt * mt * t * p1;
340 PointT v2 = ParamT(3) * mt * t * t * p2;
341 PointT v3 = t * t * t * p3;
342 return v0 + v1 + v2 + v3;
343}
344
355template<typename PointT, typename ParamT = float>
356static PointT interpolate_cubic_hermite(const PointT& p0, const PointT& m0, const PointT& p1, const PointT& m1, ParamT t) {
357 ParamT t2 = t * t;
358 ParamT t3 = t * t * t;
359 PointT w0 = ParamT(2) * t3 - ParamT(3) * t2 + ParamT(1);
360 PointT w1 = t3 - ParamT(2) * t2 + t;
361 PointT w2 = ParamT(-2) * t3 + ParamT(3) * t2;
362 PointT w3 = t3 - t2;
363 return w0 * p0 + w1 * m0 + w2 * p1 + w3 * m1;
364}
365
376template<typename PointT, typename ParamT = float>
377static PointT interpolate_cubic_basis(const PointT& b0, const PointT& b1, const PointT& b2, const PointT& b3, ParamT t) {
378 ParamT t2 = t * t;
379 ParamT t3 = t * t * t;
380 PointT v0 = (ParamT(1) - ParamT(3) * t + ParamT(3) * t2 - t3) * b0;
381 PointT v1 = (ParamT(4) - ParamT(6) * t2 + ParamT(3) * t3) * b1;
382 PointT v2 = (ParamT(1) + ParamT(3) * t + ParamT(3) * t2 - ParamT(3) * t3) * b2;
383 PointT v3 = t3 * b3;
384 return (ParamT(1) / ParamT(6)) * (v0 + v1 + v2 + v3);
385}
386
399template<typename PointT, typename ParamT = float>
400PointT interpolate_smooth_cubic(const std::vector<PointT>& points, ParamT t, const interval<ParamT>& domain = { 0.0f, 1.0f }) {
401 t = (t - domain.lower_bound) / domain.size();
402
403 size_t num_pairs = points.size() - 1;
404
405 size_t i = 0;
406 if(t <= ParamT(0)) {
407 t = ParamT(0);
408 } else if(t >= ParamT(1)) {
409 t = ParamT(1);
410 i = num_pairs - 1;
411 } else {
412 i = static_cast<size_t>(std::floor(t * static_cast<float>(num_pairs)));
413 }
414
415 PointT v1 = points[i];
416 PointT v2 = points[i + 1];
417 PointT v0 = i > 0 ? points[i - 1] : PointT(2) * v1 - v2;
418 PointT v3 = i < num_pairs - 1 ? points[i + 2] : PointT(2) * v2 - v1;
419 t = (t - static_cast<float>(i) / static_cast<float>(num_pairs)) * static_cast<float>(num_pairs);
420 return interpolate_cubic_basis(v0, v1, v2, v3, t);
421};
422
424template<typename X, typename Y>
427 interval<X> domain = { X(0), X(1) };
429 std::vector<Y> breakpoints;
430
432 Y evaluate(X x) const {
433 x = (x - domain.lower_bound) / domain.size();
434
435 if(x <= X(0))
436 return breakpoints.front();
437
438 if(x >= X(1))
439 return breakpoints.back();
440
441 size_t num_pieces = breakpoints.size() - 1;
442 size_t index = static_cast<size_t>(x * static_cast<X>(num_pieces));
443
444 X step = X(1) / static_cast<X>(num_pieces);
445 X prev = static_cast<X>(index) * step;
446 X curr = static_cast<X>(index + 1) * step;
447 X t = (x - prev) / (curr - prev);
448 return interpolate_linear(breakpoints[index], breakpoints[index + 1], t);
449 }
450};
451
452} // namespace math
453} // namespace cgv
The interval template represents a closed interval of two numbers, i.e.
Definition interval.h:27
T size() const
return the size of the interval
Definition interval.h:57
the cgv namespace
Definition print.h:11
Template class representing a piecewise linear function with uniformly spaced breakpoints that maps f...
std::vector< Y > breakpoints
The points that define the piecewise intervals and are assumed to be spaced uniformly over the domain...
interval< X > domain
The input parameter domain.
Y evaluate(X x) const
Return the piecewise linear interpolated value at position x.