Allolib  1.0
C++ Components For Interactive Multimedia
al_Interpolation.hpp
1 #ifndef INCLUDE_AL_MATH_INTERPOLATION_HPP
2 #define INCLUDE_AL_MATH_INTERPOLATION_HPP
3 
4 /* Allocore --
5  Multimedia / virtual environment application class library
6 
7  Copyright (C) 2009. AlloSphere Research Group, Media Arts & Technology, UCSB.
8  Copyright (C) 2012. The Regents of the University of California.
9  All rights reserved.
10 
11  Redistribution and use in source and binary forms, with or without
12  modification, are permitted provided that the following conditions are met:
13 
14  Redistributions of source code must retain the above copyright notice,
15  this list of conditions and the following disclaimer.
16 
17  Redistributions in binary form must reproduce the above copyright
18  notice, this list of conditions and the following disclaimer in the
19  documentation and/or other materials provided with the distribution.
20 
21  Neither the name of the University of California nor the names of its
22  contributors may be used to endorse or promote products derived from
23  this software without specific prior written permission.
24 
25  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
29  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35  POSSIBILITY OF SUCH DAMAGE.
36 
37 
38  File description:
39  A collection of generic interpolation functions
40 
41  File author(s):
42  Lance Putnam, 2006, putnam.lance@gmail.com
43 */
44 
45 namespace al {
46 
48 namespace ipl {
49 
51 
56 template <class Tf, class Tv>
57 Tv bezier(Tf frac, const Tv& x2, const Tv& x1, const Tv& x0);
58 
60 
65 template <class Tf, class Tv>
66 Tv bezier(Tf frac, const Tv& x3, const Tv& x2, const Tv& x1, const Tv& x0);
67 
69 
77 template <class Tf, class Tv>
78 Tv casteljau(const Tf& frac, const Tv& a, const Tv& b, const Tv& c,
79  const Tv& d);
80 
84 template <class Tp, class Tv>
85 Tv hermite(Tp f, const Tv& w, const Tv& x, const Tv& y, const Tv& z, Tp tension,
86  Tp bias);
87 
89 
95 template <class T>
96 void lagrange(T* h, T delay, int order);
97 
101 template <class T>
102 void lagrange1(T* h, T delay);
103 
107 template <class T>
108 void lagrange2(T* h, T delay);
109 
113 template <class T>
114 void lagrange3(T* h, T delay);
115 
116 // Various functions to perform Waring-Lagrange interpolation.
117 // These are much faster than using a general purpose FIR filter since
118 // the coefs are computed directly and nested multiplication is used
119 // rather than directly evaluating the polynomial (FIR).
120 
122 
129 template <class Tf, class Tv>
130 void cardinalSpline(Tv* w, const Tv* x, const Tf& f, double b);
131 
133 
137 template <class Tf, class Tv>
138 Tv cubic(Tf frac, const Tv& w, const Tv& x, const Tv& y, const Tv& z);
139 
141 
145 template <class Tf, class Tv>
146 Tv cubic2(Tf frac, const Tv& w, const Tv& x, const Tv& y, const Tv& z);
147 
151 template <class Tf, class Tv>
152 Tv linear(Tf frac, const Tv& x, const Tv& y);
153 
157 template <class Tf, class Tv>
158 Tv linear(Tf frac, const Tv& x, const Tv& y, const Tv& z);
159 
163 template <class Tf, class Tv>
164 Tv linearCyclic(Tf frac, const Tv& x, const Tv& y, const Tv& z);
165 
169 template <class Tf, class Tv>
170 void linear(Tv* dst, const Tv* xs, const Tv* xp1s, int len, const Tf& frac);
171 
175 template <class Tf, class Tv>
176 Tv nearest(Tf frac, const Tv& x, const Tv& y);
177 
181 template <class Tf, class Tv>
182 inline Tv bilinear(const Tf& fracX, const Tf& fracY, const Tv& xy, const Tv& Xy,
183  const Tv& xY, const Tv& XY) {
184  return linear(fracY, linear(fracX, xy, Xy), linear(fracX, xY, XY));
185 }
186 
190 template <class Tf2, class Tv>
191 inline Tv bilinear(const Tf2& f, const Tv& xy, const Tv& Xy, const Tv& xY,
192  const Tv& XY) {
193  return bilinear(f[0], f[1], xy, Xy, xY, XY);
194 }
195 
199 template <class Tf, class Tv>
200 inline Tv trilinear(const Tf& fracX, const Tf& fracY, const Tf& fracZ,
201  const Tv& xyz, const Tv& Xyz, const Tv& xYz, const Tv& XYz,
202  const Tv& xyZ, const Tv& XyZ, const Tv& xYZ,
203  const Tv& XYZ) {
204  return linear(fracZ, bilinear(fracX, fracY, xyz, Xyz, xYz, XYz),
205  bilinear(fracX, fracY, xyZ, XyZ, xYZ, XYZ));
206 }
207 
209 
213 template <class Tf3, class Tv>
214 inline Tv trilinear(const Tf3& f, const Tv& xyz, const Tv& Xyz, const Tv& xYz,
215  const Tv& XYz, const Tv& xyZ, const Tv& XyZ, const Tv& xYZ,
216  const Tv& XYZ) {
217  return trilinear(f[0], f[1], f[2], xyz, Xyz, xYz, XYz, xyZ, XyZ, xYZ, XYZ);
218 }
219 
220 //------------------------------------------------------------------------------
221 // Implementation
222 //------------------------------------------------------------------------------
223 
224 template <class Tf, class Tv>
225 inline Tv bezier(Tf d, const Tv& x2, const Tv& x1, const Tv& x0) {
226  Tf d2 = d * d;
227  Tf dm1 = Tf(1) - d;
228  Tf dm12 = dm1 * dm1;
229  return dm12 * x2 + Tf(2) * dm1 * d * x1 + d2 * x0;
230 
231  // x2 (1-d)(1-d) + 2 x1 (1-d) d + x0 d d
232  // x2 - d 2 x2 + d d x2 + d 2 x1 - d d 2 x1 + d d x0
233  // x2 - d (2 x2 + d x2 + 2 x1 - d 2 x1 + d x0)
234  // x2 - d (2 (x2 + x1) + d (x2 - 2 x1 + x0))
235 
236  // float c2 = x2 - 2.f * x1 + x0;
237  // float c1 = 2.f * (x2 + x1);
238  // return x2 - (d * c2 + c1) * d;
239 }
240 
241 template <class Tf, class Tv>
242 inline Tv bezier(Tf d, const Tv& x3, const Tv& x2, const Tv& x1, const Tv& x0) {
243  Tv c1 = Tf(3) * (x2 - x3);
244  Tv c2 = Tf(3) * (x1 - x2) - c1;
245  Tv c3 = x0 - x3 - c1 - c2;
246  return ((c3 * d + c2) * d + c1) * d + x3;
247 }
248 
249 template <class Tf, class Tv>
250 Tv casteljau(const Tf& f, const Tv& a, const Tv& b, const Tv& c, const Tv& d) {
251  Tv ab = linear(f, a, b);
252  Tv bc = linear(f, b, c);
253  Tv cd = linear(f, c, d);
254  return linear(f, linear(f, ab, bc), linear(f, bc, cd));
255 }
256 
257 template <class Tf, class Tv>
258 inline void cardinalSpline(Tv* w, const Tv* x, const Tf& f, double b) {
259  // c = (1-b); // tension
260  b *= (x[2] - x[1]); // make domain [t[1], t[2]]
261 
262  // evaluate the Hermite basis functions
263  Tf h00 = (1 + 2 * f) * (f - 1) * (f - 1);
264  Tf h10 = f * (f - 1) * (f - 1);
265  Tf h01 = f * f * (3 - 2 * f);
266  Tf h11 = f * f * (f - 1);
267 
268  /*
269  The general cubic Hermite spline is
270  p(f) = h00 * p0 + h10 * m0 + h01 * p1 + h11 * m1
271 
272  For a cardinal spline, the tangent at point k is
273  m[k] = (1-c) * (p[k+1] - p[k-1]) / (x[k+1] - x[k-1])
274 
275  To get the weights for each point, we plug the tangents into the general
276  spline equation and factor out the p[k].
277  */
278 
279  w[0] = (-b * h10 / (x[2] - x[0]));
280  w[1] = (h00 - b * h11 / (x[3] - x[1]));
281  w[2] = (h01 + b * h10 / (x[2] - x[0]));
282  w[3] = (+b * h11 / (x[3] - x[1]));
283 }
284 
285 template <class Tf, class Tv>
286 inline Tv cubic(Tf f, const Tv& w, const Tv& x, const Tv& y, const Tv& z) {
287  // Tv c3 = (x - y)*(Tf)1.5 + (z - w)*(Tf)0.5;
288  // Tv c2 = w - x*(Tf)2.5 + y*(Tf)2. - z*(Tf)0.5;
289  // Tv c1 = (y - w)*(Tf)0.5;
290  // return ((c3 * f + c2) * f + c1) * f + x;
291 
292  // -w + 3x - 3y + z
293  // 2w - 5x + 4y - z
294  // c2 = w - 2x + y - c3
295 
296  // Tv c3 = (x - y)*(Tf)3 + z - w;
297  // Tv c2 = w - x*(Tf)2 + y - c3;
298  // Tv c1 = y - w;
299  // return (((c3 * f + c2) * f + c1)) * f * (Tf)0.5 + x;
300 
301  // Tv c3 = (x - y)*(Tf)1.5 + (z - w)*(Tf)0.5;
302  // Tv c2 = (y + w)*(Tf)0.5 - x - c3;
303  // Tv c1 = (y - w)*(Tf)0.5;
304  // return ((c3 * f + c2) * f + c1) * f + x;
305 
306  Tv c1 = (y - w) * Tf(0.5);
307  Tv c3 = (x - y) * Tf(1.5) + (z - w) * Tf(0.5);
308  Tv c2 = c1 + w - x - c3;
309  return ((c3 * f + c2) * f + c1) * f + x;
310 }
311 
312 template <class T>
313 void cubic(T* dst, const T* xm1s, const T* xs, const T* xp1s, const T* xp2s,
314  int len, T f) {
315  for (int i = 0; i < len; ++i)
316  dst[i] = cubic(f, xm1s[i], xs[i], xp1s[i], xp2s[i]);
317 }
318 
319 // From http://astronomy.swin.edu.au/~pbourke/other/interpolation/ (Paul Bourke)
320 template <class Tf, class Tv>
321 inline Tv cubic2(Tf f, const Tv& w, const Tv& x, const Tv& y, const Tv& z) {
322  Tv c3 = z - y - w + x;
323  Tv c2 = w - x - c3;
324  Tv c1 = y - w;
325  return ((c3 * f + c2) * f + c1) * f + x;
326 }
327 
328 // From http://astronomy.swin.edu.au/~pbourke/other/interpolation/ (Paul Bourke)
329 /*
330  Tension: 1 is high, 0 normal, -1 is low
331  Bias: 0 is even,
332  positive is towards first segment,
333  negative towards the other
334 */
335 template <class Tp, class Tv>
336 inline Tv hermite(Tp f, const Tv& w, const Tv& x, const Tv& y, const Tv& z,
337  Tp tension, Tp bias) {
338  tension = (Tp(1) - tension) * Tp(0.5);
339 
340  // compute endpoint tangents
341  // Tv m0 = ((x-w)*(1+bias) + (y-x)*(1-bias))*tension;
342  // Tv m1 = ((y-x)*(1+bias) + (z-y)*(1-bias))*tension;
343  Tv m0 = ((x * Tv(2) - w - y) * bias + y - w) * tension;
344  Tv m1 = ((y * Tv(2) - x - z) * bias + z - x) * tension;
345 
346  // x - w + x b - w b + y - x - y b + x b
347  // -w + 2x b - w b + y - y b
348  // b(2x - w - y) + y - w
349  //
350  // y - x + y b - x b + z - y - z b + y b
351  // -x + 2y b - x b + z - z b
352  // b(2y - x - z) + z - x
353 
354  Tp f2 = f * f;
355  Tp f3 = f2 * f;
356 
357  // compute hermite basis functions
358  Tp a3 = Tp(-2) * f3 + Tp(3) * f2;
359  Tp a0 = Tp(1) - a3;
360  Tp a2 = f3 - f2;
361  Tp a1 = f3 - Tp(2) * f2 + f;
362 
363  return x * a0 + m0 * a1 + m1 * a2 + y * a3;
364 }
365 
366 template <class T>
367 void lagrange(T* a, T delay, int order) {
368  for (int i = 0; i <= order; ++i) {
369  T coef = T(1);
370  T i_f = T(i);
371  for (int j = 0; j <= order; ++j) {
372  if (j != i) {
373  T j_f = (T)j;
374  coef *= (delay - j_f) / (i_f - j_f);
375  }
376  }
377  *a++ = coef;
378  }
379 }
380 
381 template <class T>
382 inline void lagrange1(T* h, T d) {
383  h[0] = T(1) - d;
384  h[1] = d;
385 }
386 
387 template <class T>
388 inline void lagrange2(T* h, T d) {
389  h[0] = (d - T(1)) * (d - T(2)) * T(0.5);
390  h[1] = -d * (d - T(2));
391  h[2] = d * (d - T(1)) * T(0.5);
392 }
393 
394 template <class T>
395 inline void lagrange3(T* h, T d) {
396  T d1 = d - T(1);
397  T d2 = d - T(2);
398  T d3 = d - T(3);
399  h[0] = -d1 * d2 * d3 * T(1. / 6.);
400  h[1] = d * d2 * d3 * T(0.5);
401  h[2] = -d * d1 * d3 * T(0.5);
402  h[3] = d * d1 * d2 * T(1. / 6.);
403 }
404 
405 /*
406 x1 (1 - d) + x0 d
407 x1 - x1 d + x0 d
408 x1 + (x0 - x1) d
409 
410 x2 (d - 1) (d - 2) /2 - x1 d (d - 2) + x0 d (d - 1) /2
411 d d /2 x2 - d 3/2 x2 + x2 - d d x1 + d 2 x1 + d d /2 x0 - d /2 x0
412 d d /2 x2 - d d x1 + d d /2 x0 - d 3/2 x2 + d 2 x1 - d /2 x0 + x2
413 d (d (/2 x2 - x1 + /2 x0) - 3/2 x2 + 2 x1 - /2 x0) + x2
414 */
415 
416 template <class Tf, class Tv>
417 inline Tv linear(Tf f, const Tv& x, const Tv& y) {
418  return (y - x) * f + x;
419 }
420 
421 template <class Tf, class Tv>
422 inline Tv linear(Tf frac, const Tv& x, const Tv& y, const Tv& z) {
423  frac *= Tf(2);
424  if (frac < Tf(1)) return ipl::linear(frac, x, y);
425  return ipl::linear(frac - Tf(1), y, z);
426 }
427 
428 template <class Tf, class Tv>
429 void linear(Tv* dst, const Tv* xs, const Tv* xp1s, int len, const Tf& f) {
430  for (int i = 0; i < len; ++i) dst[i] = linear(f, xs[i], xp1s[i]);
431 }
432 
433 template <class Tf, class Tv>
434 inline Tv linearCyclic(Tf frac, const Tv& x, const Tv& y, const Tv& z) {
435  frac *= Tf(3);
436  if (frac <= Tf(1))
437  return ipl::linear(frac, x, y);
438  else if (frac >= Tf(2))
439  return ipl::linear(frac - Tf(2), z, x);
440  return ipl::linear(frac - Tf(1), y, z);
441 }
442 
443 template <class Tf, class Tv>
444 inline Tv nearest(Tf f, const Tv& x, const Tv& y) {
445  return (f < Tf(0.5)) ? x : y;
446 }
447 
448 } // namespace ipl
449 } // namespace al
450 
451 #endif
Tv cubic(Tf frac, const Tv &w, const Tv &x, const Tv &y, const Tv &z)
Cubic interpolation.
Tv hermite(Tp f, const Tv &w, const Tv &x, const Tv &y, const Tv &z, Tp tension, Tp bias)
Tv casteljau(const Tf &frac, const Tv &a, const Tv &b, const Tv &c, const Tv &d)
de Casteljau algorithm for four point interpolation
Tv nearest(Tf frac, const Tv &x, const Tv &y)
Tv trilinear(const Tf &fracX, const Tf &fracY, const Tf &fracZ, const Tv &xyz, const Tv &Xyz, const Tv &xYz, const Tv &XYz, const Tv &xyZ, const Tv &XyZ, const Tv &xYZ, const Tv &XYZ)
void lagrange2(T *h, T delay)
Tv linearCyclic(Tf frac, const Tv &x, const Tv &y, const Tv &z)
void lagrange1(T *h, T delay)
void lagrange3(T *h, T delay)
void cardinalSpline(Tv *w, const Tv *x, const Tf &f, double b)
Compute weights for cubic cardinal spline.
void lagrange(T *h, T delay, int order)
Computes FIR coefficients for Waring-Lagrange interpolation.
Tv linear(Tf frac, const Tv &x, const Tv &y)
Tv bezier(Tf frac, const Tv &x2, const Tv &x1, const Tv &x0)
Bezier curve, 3-point quadratic.
Tv bilinear(const Tf &fracX, const Tf &fracY, const Tv &xy, const Tv &Xy, const Tv &xY, const Tv &XY)
Tv cubic2(Tf frac, const Tv &w, const Tv &x, const Tv &y, const Tv &z)
Cubic interpolation.
Definition: al_App.hpp:23