t is not distance along a curve

A Bezier is defined by a parameter t from 0 to 1, and it is enormously tempting to treat that as position along the curve. It is not. The curve moves at different speeds through different parts of its own parameter range, and everything you place by t inherits that.

Thirteen markers on the same curve. Left: evenly spaced t. Right: evenly spaced arc length.

Left, the markers bunch up in the tight hook and stretch out along the lazy opening, even though t was stepped in perfectly equal increments. Right, they are evenly spaced along the curve, which is what "evenly spaced" almost always meant.

Why the parameter is not the distance

The speed along a curve is the magnitude of its derivative, |B'(t)|, and for a cubic that varies with the control polygon. Where control points are far apart the curve covers a lot of ground per unit of t; where they bunch, it crawls. A useful rule of thumb: the speed ratio is roughly the ratio of the longest to shortest control-polygon segment, and that ratio is exactly how unevenly your markers will land.

Which also tells you when you can ignore all of this. A gentle curve with a near-even control polygon has a speed ratio near one, and stepping t is fine. The problem appears with hooks, cusps and anything with a tight end.

The fix is a small table

// build once
float len[N+1]; len[0] = 0;
for (i = 1..N) len[i] = len[i-1] + |B(i/N) - B((i-1)/N)|;

// then invert: given a target LENGTH, find the t
find i where len[i] >= target
f = (target - len[i-1]) / (len[i] - len[i-1])
t = (i-1 + f) / N

There is no closed form for the arc length of a cubic, so a table is not a shortcut, it is the standard answer. Twenty samples is plenty for one curve segment; the remaining error is far below what you can see at drawing sizes.

Everything that lands on a curve needs this

Rules of thumb

  1. t is a parameter, not a distance. They coincide only for a straight line.
  2. Estimate the speed ratio from the control polygon before deciding it does not matter.
  3. Build a cumulative length table and invert it. Twenty samples per segment is enough.
  4. Interpolate inside the table bracket rather than snapping to the nearest sample.
  5. Rebuild the table when the curve changes, not every frame for a static one.

All 61 notes How to use them Credits