// Interp.h - Interpolation methods
//
// This is free and unencumbered software released into the public domain.
//
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
//
// In jurisdictions that recognize copyright laws, the author or authors
// of this software dedicate any and all copyright interest in the
// software to the public domain.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
// For more information, please refer to
//-----------------------------------------------------------------------------------------------------------
// History
// - v1.02 - 10/12/11 - Renamed some functions to be more consistent.
// - v1.01 - 9/29/11 - Added cubic and quintic s-curves. Removed references from InterpCosine.
// - v1.00 - 9/23/11 - Initial release by achild
//-----------------------------------------------------------------------------------------------------------
// Notes
// - Most of these can be optimized or simplified a great deal. They have never been a bottleneck
// so I never really got around to it.
//-----------------------------------------------------------------------------------------------------------
// Todo
// -
//-----------------------------------------------------------------------------------------------------------
// Sources
// - http://local.wasp.uwa.edu.au/~pbourke/miscellaneous/interpolation/
// - http://www.gamedev.net/reference/articles/article1808.asp
// - http://en.wikipedia.org/wiki/Bezier_curve
// - http://paulbourke.net/miscellaneous/interpolation/
// - http://libnoise.sourceforge.net/noisegen/index.html (also very good perlin noise tutorial)
// - http://www.cs.helsinki.fi/group/goa/mallinnus/curves/curves.html
// - http://willperone.net/Code/spline.php
#pragma once
namespace glory {
//------------------------------
// USES MAIN INPUTS ONLY
//------------------------------
// 1st derivative undefined at integer boundaries
template inline T InterpLinear(T v1, T v2, float pos) {
//return (v1 * (1.0f - pos) + v2 * pos);
return v1 + (v2 - v1) * pos;
}
// 2nd derivative undefined at integer boundaries
template inline T InterpSCurve3(T v1, T v2, float pos) {
float pos2 = pos * pos;
return v1 + (v2 - v1) * (3 * pos2 - 2 * pos2 * pos);
}
// 4th derivative undefined at integer boundaries ??
template inline T InterpSCurve5(T v1, T v2, float pos) {
float pos2 = pos * pos;
float pos3 = pos * pos2;
return v1 + (v2 - v1) * (6 * pos3 * pos2 - 15 * pos3 * pos + 10 * pos3);
}
template inline T InterpCosine(T v1, T v2, float pos) {
float pos2 = (1 - cos(pos * M_PI)) / 2;
return v1 + (v2 - v1) * pos2;
}
template inline T InterpBilinear(T v00, T v01, T v10, T v11, float unitX, float unitY) {
float X0 = v00 + (v01 - v00) * unitY;
float X1 = v10 + (v11 - v10) * unitY;
return X0 + (X1 - X0) * unitX;
}
template inline T InterpTrilinear(T v000, T v001, T v010, T v011, T v100, T v101, T v110, T v111,
float unitX, float unitY, float unitZ)
{
float Z00 = v000 + (v001 - v000) * unitZ;
float Z01 = v010 + (v011 - v010) * unitZ;
float Z10 = v100 + (v101 - v100) * unitZ;
float Z11 = v110 + (v111 - v110) * unitZ;
float X0 = Z00 + (Z01 - Z00) * unitY;
float X1 = Z10 + (Z11 - Z10) * unitY;
return X0 + (X1 - X0) * unitX;
}
//------------------------------
// USES EXTERNAL CONTROL POINTS
//------------------------------
// When pos is 0, it is on v1, when it is 1, it is on v2, and between 0 and 1 interpolates between, while
// outside of 0 or 1 extrapolates past the points to v0 or v3.
// Note that this means if we have, say, 5 control points, we only get 2 segments interpolated, since
// there is nothing outside of the 2 endpoints. We always get n - 3 segments.
template inline T InterpCubic(T v0, T v1, T v2, T v3, float pos) {
T a0, a1, a2;
float mu2 = pos * pos;
a0 = v3 - v2 - v0 + v1;
a1 = v0 - v1 - a0;
a2 = v2 - v0;
return (a0 * pos * mu2 + a1 * mu2 + a2 * pos + v1);
}
// Catmull-Rom spline.
// When pos is 0, it is on v1, when it is 1, it is on v2, and between 0 and 1 interpolates between, while
// outside of 0 or 1 extrapolates past the points to v0 or v3.
// Note that this means if we have, say, 5 control points, we only get 2 segments interpolated, since
// there is nothing outside of the 2 endpoints. We always get n - 3 segments.
template inline T InterpCatmullRom(T v0, T v1, T v2, T v3, float pos) {
T a0, a1, a2;
float mu2 = pos * pos;
a0 = .5f * v3 - 1.5f * v2 - .5f * v0 + 1.5f * v1;
a1 = v0 - 2.5f * v1 + 2.0f * v2 - .5f * v3;
a2 = .5f * v2 - .5f * v0;
return (a0 * pos * mu2 + a1 * mu2 + a2 * pos + v1);
}
//------------------------------
// USES INTERNAL CONTROL POINTS
//------------------------------
// Quadratic bezier curve
// Interpolates between v0 and v2 with v1 as a control point
// v0*a^2 + 2*v1*a*b + v2*b^2
template inline T InterpBezQuadratic(T v0, T v1, T v2, float pos) {
float b = 1.0f - pos;
return (v0 * b * b) + (2 * v1 * pos * b) + (v2 * pos * pos);
}
// Cubic bezier curve
// Interpolates between v0 and v3. v1 is control point for v0, and v2 is control point for v3.
// v0*a^3 + 3*v1*a^2*b + 3*v2*a*b^2 + v3*b^3
template inline T InterpBezCubic(T v0, T v1, T v2, T v3, float pos) {
float p2 = pos * pos;
float b = (1.0f - pos);
float b2 = b * b;
return (v0 * b2 * b) + (v1 * 3.0f * b2 * pos) + (v2 * 3.0f * b * p2) + (v3 * p2 * pos);
}
// B-Spline
/*template inline T InterpBSpline(T v0, T v1, T v2, T v3, float pos) {
T a0, a1, a2;
float mu2 = pos * pos;
a0 = (1.0f / 6.0f) * v3 - .5f * v2 - (1.0f / 6.0f) * v0 + .5f * v1;
a1 = .5f * v0 - v1 + .5f * v2;
a2 = .5f * v2 - .5f * v0;
//return (a0 * pos * mu2 + a1 * mu2 + a2 * pos + v1);
}*/
// Interpolates between v0 and v3. v1 is tangent for v0, and v2 is tangent for v3.
// Tension can be used to tighten up the curve towards the points
// Bias can twist the curve about the points
// pos, tension, and bias are all 0 - 1
template inline T InterpHermite(T v0, T v1, T v2, T v3, float pos,
float tension, float bias)
{
T m0, m1;
float mu2, mu3;
float a0, a1, a2, a3;
m0 = (v1 - v0) * (1 + bias) * (1 - tension) / 2;
m0 += (v2 - v1) * (1 - bias) * (1 - tension) / 2;
m1 = (v2 - v1) * (1 + bias) * (1 - tension) / 2;
m1 += (v3 - v2) * (1 - bias) * (1 - tension) / 2;
mu2 = pos * pos;
mu3 = mu2 * pos;
a0 = 2 * mu3 - 3 * mu2 + 1;
a1 = mu3 - 2 * mu2 + pos;
a2 = mu3 - mu2;
a3 = -2 * mu3 + 3 * mu2;
return a0 * v1 + a1 * m0 + a2 * m1 + a3 * v2;
}
} // namespace glory