raw Math
RAW Math Computer Graphics Curves and Splines

Approximating Bézier Curves with Circular Arcs

Robert Eisele

Circular arcs are often a better manufacturing primitive than line segments. They preserve a constant curvature, produce smoother CNC motion, and can replace a polynomial toolpath with far fewer primitives than a polyline at the same geometric tolerance. A general cubic Bézier curve, however, is not itself circular. Converting it into arcs is therefore an approximation problem with three separate obligations: preserve endpoints, preserve endpoint tangents, and verify a geometric error bound.

The construction below follows Walton and Meek's arc-spline approximation for cubic Bézier spirals. Its elementary unit is a biarc, two circular arcs joined with a common tangent. Move the tolerance below. The blue curve is the cubic spiral from their numerical example; alternating red and green strokes are circular arcs, and black points mark the joins inside each biarc.

1e-3

Why Two Arcs Instead of One?

Let a curve segment begin at \(\mathbf A_0\) with unit tangent \(\mathbf T_0\) and end at \(\mathbf A_1\) with unit tangent \(\mathbf T_1\). One circle has only three independent geometric parameters. Requiring it to pass through both endpoints and match both tangent directions generally imposes too many conditions.

A biarc introduces a join \(\mathbf G\). The first arc interpolates \(\mathbf A_0\) and \(\mathbf G\), the second interpolates \(\mathbf G\) and \(\mathbf A_1\), and both possess the same oriented tangent at \(\mathbf G\). The composite is therefore \(G^1\): position and unit tangent are continuous, although curvature usually jumps at the join.

There is a one-parameter family of such biarcs. Walton and Meek use Sabin's symmetric and inexpensive choice: the join is the incenter of the endpoint tangent triangle.

The Tangent Triangle

Intersect the endpoint tangent lines,

\[ \mathbf A_0+s\mathbf T_0=\mathbf A_1+r\mathbf T_1, \]

and call the intersection \(\mathbf V\). For a forward-facing convex segment, \(\mathbf V\) lies along the forward ray from \(\mathbf A_0\) and the backward ray from \(\mathbf A_1\). The three points \(\mathbf A_0,\mathbf V,\mathbf A_1\) form the tangent triangle.

If \(a_0=\|\mathbf V-\mathbf A_1\|\), \(a_V=\|\mathbf A_1-\mathbf A_0\|\), and \(a_1=\|\mathbf A_0-\mathbf V\|\) are the side lengths opposite the corresponding vertices, its incenter is

\[ \boxed{ \mathbf G= \frac{a_0\mathbf A_0+a_V\mathbf V+a_1\mathbf A_1} {a_0+a_V+a_1}. } \]

The incenter lies inside every nondegenerate triangle. Sabin's result shows that it lies on the locus of admissible biarc joins and produces two noninflecting arcs contained in the tangent triangle. The common tangent at \(\mathbf G\) is parallel to the chord \(\mathbf A_1-\mathbf A_0\).

Recovering Each Circle

The circle through an endpoint \(\mathbf A\) and the join \(\mathbf G\), tangent to unit direction \(\mathbf T\) at \(\mathbf A\), can be obtained without a three-point circle solver. Let \(\mathbf N=R_{90}\mathbf T=(-T_y,T_x)\). Its center must lie on the endpoint normal,

\[ \mathbf C=\mathbf A+\lambda\mathbf N. \]

Equating the distances from \(\mathbf C\) to \(\mathbf A\) and \(\mathbf G\) gives

\[ \|\mathbf G-\mathbf A-\lambda\mathbf N\|^2=\lambda^2. \]

Since \(\|\mathbf N\|=1\), the quadratic terms cancel and leave the explicit signed radius

\[ \boxed{ \lambda= rac{\|\mathbf G-\mathbf A\|^2} {2(\mathbf G-\mathbf A)\cdot\mathbf N}, \qquad \mathbf C=\mathbf A+\lambda\mathbf N. } \]

The radius is \(|\lambda|\); its sign selects clockwise or counterclockwise traversal. Apply the formula at \(\mathbf A_0\) for the first circle and at \(\mathbf A_1\) for the second. Choosing the directed sweeps that follow \(\mathbf T_0\) and arrive along \(\mathbf T_1\) completes the biarc.

The Cubic Bézier Spiral

The strongest error theorem requires more than an arbitrary cubic. Walton and Meek consider a planar cubic Bézier spiral whose signed curvature is positive and increases monotonically. Given a start point \(\mathbf B_0\), start and end unit tangents \(\mathbf T_0,\mathbf T_1\), their counterclockwise angle \(0<\theta<\pi/2\), and terminal curvature \(c>0\), define

\[ a=\frac{25\tan\theta}{54c\cos\theta}, \qquad b=\frac{5\tan\theta}{9c}, \]

\[ \mathbf B_1=\mathbf B_0+a\mathbf T_0, \qquad \mathbf B_2=\mathbf B_1+a\mathbf T_0, \qquad \mathbf B_3=\mathbf B_2+b\mathbf T_1. \]

Its cubic Bernstein form simplifies because the quadratic power-basis coefficient vanishes:

\[ \boxed{ \mathbf Q(u)=\mathbf B_0+3a\mathbf T_0u +(b\mathbf T_1-a\mathbf T_0)u^3, } \]

\[ \mathbf Q'(u)=3a\mathbf T_0 +3(b\mathbf T_1-a\mathbf T_0)u^2. \]

This special curve has no cusp, loop, or inflection, and its curvature has no interior extremum. Those facts are not cosmetic: they make the radial deviation equations monotone enough to isolate all relevant extrema.

Locating the Curve Point Opposite the Biarc Join

Approximate the subcurve \(u_0\leq u\leq u_1\). Set \(\mathbf A_i=\mathbf Q(u_i)\), construct its incenter biarc, and let \(\mathbf H\) be the common unit tangent at \(\mathbf G\). Let \(\mathbf M=R_{90}\mathbf H\). The curve point lying on the radial line of the biarc through \(\mathbf G\) satisfies

\[ f(t)=(\mathbf Q(t)-\mathbf G)\cdot\mathbf H=0. \]

The endpoint signs are opposite because \(\mathbf H\) has the direction of the chord:

\[ f(u_0)<0,\qquad f(u_1)>0. \]

More importantly,

\[ f'(t)=\mathbf Q'(t)\cdot\mathbf H =3a(\mathbf T_0\cdot\mathbf H)(1-t^2) +3b(\mathbf T_1\cdot\mathbf H)t^2>0. \]

Hence the root is unique. Safeguarded Newton iteration is efficient, while bisection supplies guaranteed progress. Once \(t\) is known, the signed deviation at the join normal is

\[ d_G=(\mathbf Q(t)-\mathbf G)\cdot\mathbf M. \]

This is one important deviation, but it is not automatically the maximum over either arc. The remaining extrema must still be found.

All Radial Error Extrema

Let \(\mathbf C_i,r_i\) be the center and radius of the arc touching \(\mathbf Q(u_i)\), where \(i=0,1\). Its radial deviation from the cubic is

\[ e_i(u)=\|\mathbf Q(u)-\mathbf C_i\|-r_i. \]

Away from the circle center, a stationary radial deviation satisfies

\[ (\mathbf Q(u)-\mathbf C_i)\cdot\mathbf Q'(u)=0. \]

Put \(\mathbf D=b\mathbf T_1-a\mathbf T_0\). Dividing the left side by three and inserting the monomial form yields a fifth-degree polynomial with no fourth-degree term,

\[ g_i(u)=\alpha_{i,0}+\alpha_1u+\alpha_{i,2}u^2+\alpha_3u^3+\alpha_4u^5, \]

\[ \begin{aligned} \alpha_{i,0}&=a\mathbf T_0\cdot(\mathbf B_0-\mathbf C_i),\\ \alpha_1&=3a^2,\\ \alpha_{i,2}&=\mathbf D\cdot(\mathbf B_0-\mathbf C_i),\\ \alpha_3&=4a(b\mathbf T_0\cdot\mathbf T_1-a),\\ \alpha_4&=\|\mathbf D\|^2 =a^2-2ab\mathbf T_0\cdot\mathbf T_1+b^2. \end{aligned} \]

The endpoint \(u_i\) is already a tangential contact, so \(g_i(u_i)=0\). Factoring that known root avoids solving a general quintic:

\[ g_i(u)=(u-u_i)q_i(u), \]

\[ \boxed{ \begin{aligned} q_i(u)={}&\alpha_1+\alpha_{i,2}(u+u_i) +\alpha_3(u^2+uu_i+u_i^2)\\ &+\alpha_4(u^4+u^3u_i+u^2u_i^2+uu_i^3+u_i^4). \end{aligned} } \]

This quartic contains every nontrivial stationary radial distance to the corresponding circle. For a convex spiral, the circle-contact theorem used by Walton and Meek implies at most one relevant interior maximum on each side of the biarc join: search \((u_0,t]\) for \(q_0=0\) and \([t,u_1)\) for \(q_1=0\). Evaluate the absolute radial deviation at these roots, the join, and the interval boundaries. The largest value is the segment error \(\delta\), attained at parameter \(u_\delta\).

Adaptive Arc-Spline Algorithm

The approximation now becomes a short recursive procedure:

  1. Evaluate the subcurve endpoints and unit tangents.
  2. Construct the incenter biarc from their tangent triangle.
  3. Find the unique join-normal parameter \(t\).
  4. Find every relevant radial-error extremum from the two quartics.
  5. Accept both arcs when \(\delta\leq\varepsilon\).
  6. Otherwise split the Bézier curve at \(u_\delta\) and recurse on both pieces.
function approximateSpiral(curve, u0, u1, tolerance) {
  const biarc = incenterBiarc(
    curve.point(u0), curve.tangent(u0),
    curve.point(u1), curve.tangent(u1)
  );

  const maximum = exactSpiralDeviation(curve, biarc, u0, u1);
  if (maximum.distance <= tolerance) return biarc.arcs;

  return [
    ...approximateSpiral(curve, u0, maximum.parameter, tolerance),
    ...approximateSpiral(curve, maximum.parameter, u1, tolerance)
  ];
}

Splitting at the largest error attacks the failing region directly. De Casteljau subdivision gives exact child cubics, so no additional approximation is introduced before the arcs are constructed. Every accepted biarc reproduces its child endpoints and endpoint tangents; neighboring accepted pieces therefore meet with the tangent inherited from the original cubic.

General Cubics Need Preprocessing

The uniqueness and one-extremum arguments above rely on monotone signed curvature. A general cubic may contain up to two inflections, a loop, a cusp, or several curvature regimes. Applying the spiral proof unchanged to such a curve can miss radial-error extrema or produce a backward-facing tangent triangle.

A robust general converter should therefore:

  1. Reject singular derivatives and isolate cusps or loops.
  2. Split exactly at every inflection, where signed curvature changes sign.
  3. Split again at curvature extrema so each candidate piece has monotone curvature.
  4. Verify that endpoint tangent rays define a forward-facing triangle.
  5. Use the analytic spiral bound only when its hypotheses are established.
  6. Otherwise use a conservative certified distance bound, or label dense sampling honestly as numerical verification.

The shared JavaScript implementation exposes both levels. Bezier.biarc performs the exact endpoint and tangent construction. curve.toArcSpline(tolerance) recursively fits biarcs and measures point-to-arc distance at a configurable number of samples. The latter is useful for visualization and practical candidate generation, but its reported tolerance is sampled verification, not the Walton–Meek theorem for every arbitrary cubic.

Where Should a Failing Piece Be Split?

Riškus compared five practical choices for general cubics: the parameter midpoint, an intersection between the curve and its current approximation, the measured maximum-error parameter, the first parameter at which tolerance is exceeded, and a cutting line through the biarc center and incenter join. Midpoint and intersection-based cuts used fewer arcs than maximum-error splitting in his two reported examples; splitting at the first tolerance violation was markedly less efficient.

These are experimental results on particular curves, not a global optimality theorem. Maximum-error splitting remains a principled default because it attacks the currently worst measured region. Midpoint splitting is useful when deterministic balanced parameter intervals matter, and the shared API exposes it without changing the acceptance test:

const balanced = cubic.toArcSpline(1e-3, {
  samples: 64,
  splitStrategy: 'midpoint'
});
const biarc = Bezier.biarc(start, startTangent, end, endTangent);

const pieces = cubic.toArcSpline(1e-3, {
  samples: 64,
  maxDepth: 20
});

for (const piece of pieces) {
  for (const arc of piece.arcs) {
    emitCircularArc(arc.center, arc.radius, arc.startAngle, arc.endAngle);
  }
}

Error Metrics and Machine Output

Walton and Meek measure deviation along radial directions of the approximating arcs. For an admissible convex spiral this is geometrically natural and supports their extremum proof. It should not be silently renamed Hausdorff distance for an arbitrary curve: nearest Euclidean distance, radial distance, chordal error, and controller interpolation error are different quantities.

An arc spline is \(G^1\), not \(G^2\). Each individual arc has constant curvature, and that constant generally changes abruptly at every join. A sufficiently small positional tolerance can make the jump visually and mechanically acceptable, but it does not turn the composite into a curvature-continuous curve. Feed rate, acceleration limits, controller precision, tool radius compensation, and transformed output coordinates still need independent engineering tolerances.

Degenerate Cases

The method succeeds because it keeps construction and verification separate. The tangent triangle supplies an exact \(G^1\) biarc; the spiral analysis finds every relevant radial deviation; recursive subdivision supplies as many local degrees of freedom as the requested tolerance demands. Without the verification step, a visually plausible biarc is only a guess.

References