A natural cubic spline: the smoothest curve that passes through every knot.
Catmull-Rom and its relatives only keep the curve's direction smooth at each knot. A natural
cubic spline also keeps its bend (its curvature) smooth, like a Curves.Spline.Type.BSpline,
but unlike a B-spline it still goes through every knot. It is what you get if you bend a thin,
flexible strip of wood or metal through pins at the knots, which is where the name "spline" comes
from. At the first and last knots it straightens out, as a free strip would.
The catch is that every knot affects the whole curve: moving one knot changes every segment a little, not just the nearby ones.
A spline with n knots has n - 1 segments, like Catmull-Rom.
curve = Curves.define_natural_cubic([{0, 0}, {2, 3}, {4, 1}, {6, 4}, {8, 2}])
# Find any point along the curve (u goes from 0.0 to Curves.max_u(curve))...
Curves.solve!(curve, 1.5)
# ...or draw the whole curve as an SVG image
Curves.Svg.save!(curve, "natural_cubic.svg")How it is built
The tangents D0 .. Dn-1 at the knots P0 .. Pn-1 are the ones that make the curve's bend
continuous at every knot and zero at both ends. They come from solving these equations together
(each is one row of a tridiagonal system, solved in one pass each way):
2 * D0 + D1 = 3 * (P1 - P0)
D(i - 1) + 4 * Di + D(i + 1) = 3 * (P(i + 1) - P(i - 1)) for every middle knot
D(n - 2) + 2 * D(n - 1) = 3 * (P(n - 1) - P(n - 2))Each segment is then the Hermite segment between two knots, stored as a cubic Bezier curve.