Theoretica
A C++ numerical and automatic mathematical library
Loading...
Searching...
No Matches
splines.h
Go to the documentation of this file.
1
5
6#ifndef THEORETICA_SPLINES_H
7#define THEORETICA_SPLINES_H
8
9#include "../core/constants.h"
10#include "../algebra/algebra_types.h"
11
12
13namespace theoretica {
14
15
18 return (x1 + interp * (x2 - x1));
19 }
20
21
23 template<unsigned int N>
25 const vec<real, N>& P1, const vec<real, N>& P2, real interp) {
26
27 return (P1 + (P2 - P1) * interp);
28 }
29
30
33 return (value - x1) / (x2 - x1);
34 }
35
36
38 template<unsigned int N>
40 const vec<real, N>& P1, const vec<real, N>& P2, real value) {
41
42 real t = invlerp(P1.get(0), P2.get(0), value);
43
44 // Check that all computed t_i are the same
45 for (int i = 1; i < N; ++i) {
46
47 real t_new = invlerp(P1.get(i), P2.get(i), value);
48
49 if(t != t_new) {
50 TH_MATH_ERROR("invlerp", t_new, OUT_OF_DOMAIN);
51 return nan();
52 }
53 }
54
55 return t;
56 }
57
58
63
64
66 template<unsigned int N>
68 const vec<real, N>& iFrom, const vec<real, N>& iTo,
69 const vec<real, N>& oFrom, const vec<real, N>& oTo, real value) {
70 return lerp(oFrom, oTo, invlerp(iFrom, iTo, value));
71 }
72
73
75 template<unsigned int N>
77 const vec<real, N>& P1, const vec<real, N>& P2, real interp) {
78
79 return (P1 + (P2 - P1) * interp).normalized();
80 }
81
82
84 template<unsigned int N>
86 const vec<real, N>& P1, const vec<real, N>& P2, real t) {
87
88 // Compute (only once) the length
89 // of the input vectors
90 const real P1_l = P1.norm();
91 const real P2_l = P2.norm();
92
93 // Check whether one of the vectors is null,
94 // which would make the computation impossible
95 if(P1_l == 0 || P2_l == 0) {
96 TH_MATH_ERROR("slerp", P1_l ? P2_l : P1_l, IMPOSSIBLE_OPERATION);
97 return vec<real, N>(nan());
98 }
99
100 // Angle between P1 and P2 (from the dot product)
101 real omega = acos((P1 * P2) / (P1_l * P2_l));
102 real s = sin(omega);
103
104 // Check that the sine of the angle is not zero
105 if(s == 0) {
106 TH_MATH_ERROR("slerp", s, DIV_BY_ZERO);
107 return vec<real, N>(nan());
108 }
109
110 return (P1 * sin((1 - t) * omega) + P2 * sin(t * omega)) / s;
111 }
112
113
114 // Sigmoid-like interpolation
115
116
119
120 if(x1 == x2) {
121 TH_MATH_ERROR("smoothstep", x1, DIV_BY_ZERO);
122 return nan();
123 }
124
125 // Clamp x between 0 and 1
126 const real x = clamp((interp - x1) / (x2 - x1), 0.0, 1.0);
127
128 // 3x^2 - 2x^3
129 return x * x * (3 - 2 * x);
130 }
131
132
135
136 if(x1 == x2) {
137 TH_MATH_ERROR("smootherstep", x1, DIV_BY_ZERO);
138 return nan();
139 }
140
141 // Clamp x between 0 and 1
142 const real x = clamp((interp - x1) / (x2 - x1), 0.0, 1.0);
143
144 // 6x^5 - 15x^4 + 10x^3
145 return x * x * x * (x * (x * 6 - 15) + 10);
146 }
147
148
149 // Bezier curves
150
151
153 template<unsigned int N>
155 const vec<real, N>& P0, const vec<real, N>& P1,
156 const vec<real, N>& P2, real t) {
157
158 return lerp(lerp(P0, P1, t), lerp(P1, P2, t), t);
159 }
160
161
163 template<unsigned int N>
165 const vec<real, N>& P0, const vec<real, N>& P1,
166 const vec<real, N>& P2, vec<real, N> P3, real t) {
167
168 const vec<real, N> A = lerp(P0, P1, t);
169 const vec<real, N> B = lerp(P1, P2, t);
170 const vec<real, N> C = lerp(P2, P3, t);
171
172 const vec<real, N> D = lerp(A, B, t);
173 const vec<real, N> E = lerp(B, C, t);
174
175 return lerp(D, E, t);
176 }
177
178
189 template<unsigned int N>
190 inline vec<real, N> bezier(const std::vector<vec<real, N>>& points, real t) {
191
192 if(points.size() < 2) {
193 TH_MATH_ERROR("bezier", points.size(), INVALID_ARGUMENT);
194 return vec<real, N>(nan());
195 }
196
197 if(t < 0 || t > 1) {
198 TH_MATH_ERROR("bezier", t, INVALID_ARGUMENT);
199 return vec<real, N>(nan());
200 }
201
202 for (int index = points.size(); index > 1; --index) {
203
204 for (int i = 0; i < index - 1; ++i)
205 points[i] = lerp(points[i], points[i + 1], t);
206 }
207
208 return points[0];
209 }
210
211
213 struct spline_node {
214
217
220 real a, b, c, d;
221
223 spline_node() : x(0), a(0), b(0), c(0), d(0) {}
224
227 : x(x), a(a), b(b), c(c), d(d) {}
228
229
232 inline real operator()(real X) const {
233 const real h = X - x;
234 return a + h * (b + h * (c + h * d));
235 }
236
237
240 inline real deriv(real X) const {
241 const real h = X - x;
242 return b + h * (c * 2 + h * d * 3);
243 }
244 };
245
246
250 template<typename DataPoints = std::vector<vec2>>
251 inline std::vector<spline_node> cubic_splines(DataPoints p) {
252
253 if(p.size() < 2) {
254 TH_MATH_ERROR("cubic_splines", p.size(), INVALID_ARGUMENT);
255 return {spline_node(nan(), nan(), nan(), nan(), nan())};
256 }
257
258 const unsigned int n = p.size() - 1;
259
260 std::vector<real> dx(n);
261 std::vector<real> delta(n);
262
263 delta[0] = 0;
264
265 std::vector<real> alpha(n + 1);
266 std::vector<real> beta(n + 1);
267 std::vector<real> gamma(n + 1);
268
269 alpha[0] = 1;
270 beta[0] = 0;
271 gamma[0] = 0;
272
273 std::vector<real> b(n);
274 std::vector<real> c(n);
275 std::vector<real> d(n);
276
277 for (unsigned int i = 0; i < n; ++i)
278 dx[i] = p[i + 1][0] - p[i][0];
279
280 for (unsigned int i = 1; i < n; ++i)
281 delta[i] = 3 * (
282 ((p[i + 1][1] - p[i][1]) / dx[i])
283 - (p[i][1] - p[i - 1][1]) / dx[i - 1]);
284
285 for (unsigned int i = 1; i < n; ++i) {
286 alpha[i] = 2 * (p[i + 1][0] - p[i - 1][0]) - dx[i - 1] * beta[i - 1];
287 beta[i] = dx[i] / alpha[i];
288 gamma[i] = (delta[i] - dx[i] * gamma[i - 1]) / alpha[i];
289 }
290
291 // Apply boundary conditions
292 alpha[n] = 1;
293 gamma[n] = 0;
294 c[n] = 0;
295
296 // Solve the associated tridiagonal system
297 // using back-substitution
298 for (int i = n - 1; i >= 0; --i) {
299
300 c[i] = gamma[i] - beta[i] * c[i + 1];
301 b[i] = (p[i + 1][1] - p[i][1]) / dx[i]
302 - dx[i] * (c[i + 1] + 2 * c[i]) / 3.0;
303 d[i] = (c[i + 1] - c[i]) / (3.0 * dx[i]);
304 }
305
306 std::vector<spline_node> nodes(n);
307
308 for (unsigned int i = 0; i < n; ++i)
309 nodes[i] = spline_node(p[i][0], p[i][1], b[i], c[i], d[i]);
310
311 return nodes;
312 }
313
314
318 template<typename Dataset1, typename Dataset2>
319 inline std::vector<spline_node> cubic_splines(
320 const Dataset1& x, const Dataset2& y) {
321
322 if(x.size() < 2) {
323 TH_MATH_ERROR("cubic_splines", x.size(), INVALID_ARGUMENT);
324 return {spline_node(nan(), nan(), nan(), nan(), nan())};
325 }
326
327 if(x.size() != y.size()) {
328 TH_MATH_ERROR("cubic_splines", x.size(), INVALID_ARGUMENT);
329 return {spline_node(nan(), nan(), nan(), nan(), nan())};
330 }
331
332 const unsigned int n = x.size() - 1;
333
334 std::vector<real> dx(n);
335 std::vector<real> delta(n);
336
337 delta[0] = 0;
338
339 std::vector<real> alpha(n + 1);
340 std::vector<real> beta(n + 1);
341 std::vector<real> gamma(n + 1);
342
343 alpha[0] = 1;
344 beta[0] = 0;
345 gamma[0] = 0;
346
347 std::vector<real> b(n);
348 std::vector<real> c(n);
349 std::vector<real> d(n);
350
351 for (unsigned int i = 0; i < n; ++i)
352 dx[i] = x[i + 1] - x[i];
353
354 for (unsigned int i = 1; i < n; ++i)
355 delta[i] = 3 * (
356 ((y[i + 1] - y[i]) / dx[i])
357 - (y[i] - y[i - 1]) / dx[i - 1]);
358
359 for (unsigned int i = 1; i < n; ++i) {
360 alpha[i] = 2 * (x[i + 1] - x[i - 1]) - dx[i - 1] * beta[i - 1];
361 beta[i] = dx[i] / alpha[i];
362 gamma[i] = (delta[i] - dx[i] * gamma[i - 1]) / alpha[i];
363 }
364
365 // Apply boundary conditions
366 alpha[n] = 1;
367 gamma[n] = 0;
368 c[n] = 0;
369
370 // Solve the associated tridiagonal system
371 // using back-substitution
372 for (int i = n - 1; i >= 0; --i) {
373
374 c[i] = gamma[i] - beta[i] * c[i + 1];
375 b[i] = (y[i + 1] - y[i]) / dx[i]
376 - dx[i] * (c[i + 1] + 2 * c[i]) / 3.0;
377 d[i] = (c[i + 1] - c[i]) / (3.0 * dx[i]);
378 }
379
380 std::vector<spline_node> nodes(n);
381
382 for (unsigned int i = 0; i < n; ++i)
383 nodes[i] = spline_node(x[i], y[i], b[i], c[i], d[i]);
384
385 return nodes;
386 }
387
388
391 class spline {
392 public:
393
396 std::vector<spline_node> nodes;
397
398
401 template<typename DataPoints = std::vector<vec2>>
404 }
405
406
409 template<typename Dataset1, typename Dataset2>
410 spline(const Dataset1& X, const Dataset2& Y) {
412 }
413
414
416 inline spline& operator=(const spline& other) {
417 nodes = other.nodes;
418 return *this;
419 }
420
421
424 inline real operator()(real x) const {
425
426 for (int i = int(nodes.size()) - 1; i > 0; --i)
427 if(x >= nodes[i].x)
428 return nodes[i](x);
429
430 // Extrapolation for x < x_0
431 return nodes[0](x);
432 }
433
434
437 inline real deriv(real x) const {
438
439 for (unsigned int i = nodes.size() - 1; i > 0; --i)
440 if(x >= nodes[i].x)
441 return nodes[i].deriv(x);
442
443 // Extrapolation for x < x_0
444 return nodes[0].deriv(x);
445 }
446
447
449 inline auto begin() {
450 return nodes.begin();
451 }
452
453
455 inline auto end() {
456 return nodes.end();
457 }
458 };
459
460
461}
462
463#endif
A natural cubic spline interpolation class.
Definition splines.h:391
spline(const Dataset1 &X, const Dataset2 &Y)
Construct the natural cubic spline interpolation from the sets of X and Y data points.
Definition splines.h:410
real operator()(real x) const
Evaluate the natural cubic spline interpolation at a given point.
Definition splines.h:424
real deriv(real x) const
Evaluate the derivative of the natural cubic spline interpolation at a given point.
Definition splines.h:437
auto end()
Get an iterator to one plus the last spline element.
Definition splines.h:455
auto begin()
Get an iterator to the first spline element.
Definition splines.h:449
spline(const DataPoints &p)
Construct the natural cubic spline interpolation from a vector of coordinate pairs.
Definition splines.h:402
spline & operator=(const spline &other)
Copy from another spline.
Definition splines.h:416
std::vector< spline_node > nodes
The computed nodes of the natural cubic spline interpolation over the points.
Definition splines.h:396
#define TH_MATH_ERROR(F_NAME, VALUE, EXCEPTION)
TH_MATH_ERROR is a macro which throws exceptions or modifies errno (depending on which compiling opti...
Definition error.h:219
Main namespace of the library which contains all functions and objects.
Definition algebra.h:27
double real
A real number, defined as a floating point type.
Definition constants.h:198
std::remove_reference_t< decltype(std::declval< Structure >()[0])> vector_element_t
Extract the type of a vector (or any indexable container) from its operator[].
Definition core_traits.h:134
real smootherstep(real x1, real x2, real interp)
Smootherstep interpolation.
Definition splines.h:134
vec< real, N > nlerp(const vec< real, N > &P1, const vec< real, N > &P2, real interp)
Normalized linear interpolation.
Definition splines.h:76
real remap(real iFrom, real iTo, real oFrom, real oTo, real value)
Remap a value from one range to another.
Definition splines.h:60
real smoothstep(real x1, real x2, real interp)
Smoothstep interpolation.
Definition splines.h:118
real invlerp(real x1, real x2, real value)
Inverse linear interpolation.
Definition splines.h:32
std::vector< spline_node > cubic_splines(DataPoints p)
Compute the cubic splines interpolation of a set of data points.
Definition splines.h:251
real lerp(real x1, real x2, real interp)
Linear interpolation.
Definition splines.h:17
constexpr real E
The Euler mathematical constant (e)
Definition constants.h:237
vec< real, N > bezier(const std::vector< vec< real, N > > &points, real t)
Generic Bezier curve in N dimensions.
Definition splines.h:190
vec< real, N > cubic_bezier(const vec< real, N > &P0, const vec< real, N > &P1, const vec< real, N > &P2, vec< real, N > P3, real t)
Cubic Bezier curve.
Definition splines.h:164
dual2 acos(dual2 x)
Compute the arcosine of a second order dual number.
Definition dual2_functions.h:223
vec< real, N > slerp(const vec< real, N > &P1, const vec< real, N > &P2, real t)
Spherical interpolation.
Definition splines.h:85
dual2 sin(dual2 x)
Compute the sine of a second order dual number.
Definition dual2_functions.h:72
real nan()
Return a quiet NaN number in floating point representation.
Definition error.h:54
real clamp(real x, real a, real b)
Clamp x between a and b.
Definition real_analysis.h:355
vec< real, N > quadratic_bezier(const vec< real, N > &P0, const vec< real, N > &P1, const vec< real, N > &P2, real t)
Quadratic Bezier curve.
Definition splines.h:154
A cubic splines node for a given x interval.
Definition splines.h:213
spline_node()
Default constructor.
Definition splines.h:223
real operator()(real X) const
Evaluate the interpolating cubic spline (no check on the input value is performed!...
Definition splines.h:232
real deriv(real X) const
Evaluate the derivative of the interpolating cubic spline (no check on the input value is performed)
Definition splines.h:240
real x
Upper extreme of the interpolation interval .
Definition splines.h:216
real a
Coefficients of the interpolating cubic spline .
Definition splines.h:220
spline_node(real x, real a, real b, real c, real d)
Construct from and polynomial coefficients.
Definition splines.h:226