Curves.Spline.Type.NaturalCubic (curves v1.0.1)

Copy Markdown View Source

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")

Natural cubic spline

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.