26template<
typename Po
intT,
typename InterpolationOp,
typename ParamT =
float>
27PointT interpolate_piece(
const std::vector<PointT>& points, ParamT t, InterpolationOp operation) {
29 return points.front();
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);
61template<
typename Po
intT,
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>;
66 return points.front().second;
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;
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);
94template<
typename Po
intT,
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>;
98 if(n == 0 || points.size() == 0)
101 if(points.size() == 1)
102 return std::vector<PointT>(n, points.front().second);
107 if(points.front().first > ParamT(0))
110 std::vector<PointT> res;
113 ParamT step = ParamT(1) /
static_cast<ParamT
>(n - 1);
115 for(
size_t i = 0; i < n; ++i) {
116 ParamT x =
static_cast<ParamT
>(i) * step;
118 while(x > points[r].first && l < points.size() - 1) {
120 r = std::min(l + 1, points.size() - 1);
124 res.push_back(points[r].second);
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));
145template<
typename ParamT =
float,
typename OutputIt,
typename UnaryOp>
146static void sequence_transform(OutputIt output_first, UnaryOp operation,
size_t n) {
148 *output_first = operation(ParamT(0.5));
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);
168template<
typename Po
intT,
typename ParamT =
float>
169PointT interpolate_nearest(
const PointT& p0,
const PointT& p1, ParamT t) {
170 return t < ParamT(0.5) ? p0 : p1;
181template<
typename Po
intT,
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>));
197template<
typename Po
intT,
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>));
209template<
typename Po
intT,
typename ParamT =
float>
210std::vector<PointT> interpolate_nearest_n(
const std::vector<PointT>& points,
size_t n) {
211 std::vector<PointT> res;
213 sequence_transform(std::back_inserter(res), [&points](
float t) {
return cgv::math::interpolate_nearest(points, t); }, n);
227template<
typename Po
intT,
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);
240template<
typename Po
intT,
typename ParamT =
float>
241static PointT interpolate_linear(
const PointT& p0,
const PointT& p1, ParamT t) {
242 PointT v0 = (ParamT(1) - t) * p0;
255template<
typename Po
intT,
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>));
272template<
typename Po
intT,
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>));
284template<
typename Po
intT,
typename ParamT =
float>
285std::vector<PointT> interpolate_linear_n(
const std::vector<PointT>& points,
size_t n) {
286 std::vector<PointT> res;
288 sequence_transform(std::back_inserter(res), [&points](
float t) {
return cgv::math::interpolate_linear(points, t); }, n);
302template<
typename Po
intT,
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);
316template<
typename Po
intT,
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;
335template<
typename Po
intT,
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;
355template<
typename Po
intT,
typename ParamT =
float>
356static PointT interpolate_cubic_hermite(
const PointT& p0,
const PointT& m0,
const PointT& p1,
const PointT& m1, ParamT 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;
363 return w0 * p0 + w1 * m0 + w2 * p1 + w3 * m1;
376template<
typename Po
intT,
typename ParamT =
float>
377static PointT interpolate_cubic_basis(
const PointT& b0,
const PointT& b1,
const PointT& b2,
const PointT& b3, ParamT 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;
384 return (ParamT(1) / ParamT(6)) * (v0 + v1 + v2 + v3);
399template<
typename Po
intT,
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();
403 size_t num_pairs = points.size() - 1;
408 }
else if(t >= ParamT(1)) {
412 i =
static_cast<size_t>(std::floor(t *
static_cast<float>(num_pairs)));
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);
424template<
typename X,
typename Y>
442 size_t index =
static_cast<size_t>(x *
static_cast<X
>(num_pieces));
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);
The interval template represents a closed interval of two numbers, i.e.
T size() const
return the size of the interval