## Biarc geometry done easy

Wednesday, January 20th, 2016 at 4:57 pm

This is about C-shaped biarcs. I’m not interested in the S-shaped ones, so I’ve not looked at them.

A Biarc is a smooth curve composed of two consecutive tangential circular arcs that can be drawn between a given pair of points with a given tangency at those points.

In many ways a biarc fulfills the job of a cubic spline commonly used in CAD to interpolate a curve between two points with given tangencies. They can be chained to form a continuous curve that appears smooth to the eye (continuous first derivative) all along its length.

Given end points and tangent vectors, there are two extra degrees of freedom for the cubic spline. These are usually called the weight factors.

A biarc has only one extra degree of freedom, which determines the point where the two arcs join tangentially.

Biarcs have a larger application in CAM than CAD for the following reasons:

1) CNC mechanisms whose motions are controlled by G-code (most of them) have G1 for linear motion as well as G2 and G3 for circular arc clockwise and circular arc counter-clockwise. They do not have codes to do arcs (although Siemens tried to market a controller in the 1990s that had NURBS), so if you want to produce a perfectly smooth path then you need to provide a sequence of tangential arcs. Biarcs can effectively act as a drop-in replacement for cubic splines.

2) Physical machines in motion are limited by their maximum acceleration which is determined by the power. A cubic spline has a maximum acceleration (minimum curvature) at only one point along its length, and this means all the other points have to be run below this value. On the other hand, a circular arc has a constant and easy to calculate acceleration for a given velocity. This means it is more likely to be programmed to attain the maximum power over a longer distance than is the case for cubic splines which are too hard to optimize.

Let’s get to the point. After days of messy algebra, similar to what’s been done by this guy and in other papers I have read, I spotted a pattern, which I have reduced to a nice theorem in plane geometry. Theorem: Given points A and B and tangent vectors at them that intersect at E, we consider any biarc that is consistent with these endpoints and tangents. (This is defined as two circular arcs that are tangent at these points and to each other)

This biarc is drawn as the arc AC (with centre a) and the arc CB (with centre b)

If we extend the line EB to the point D so that the length of ED equals the length of EA then the point C where the two arcs meet will always lie on the circle through the points A, B and D (whose centre is c) proof:
The points A, B, E, D are given by the initial conditions. Points C, a, b are given by the choice of biarc.

By the definition of the biarc, the line aA (which is a radius of the left hand big arc) is perpendicular to the line AE, the line bB (which is a radius of the right hand small arc) is perpendicular to BE, and the points a, b and C must be collinear for the two arcs to be tangential at C.

Let f be the midpoint of the arc AC and g be the midpoint of the arc BC and draw in the lines af and bg to form bisectors of their respective arc angles.

Extend the line bg back to the point c where it intersects the line af.

By symmetry (of af being a bisection line), the lengths of cA and cC have the same length. Similarly the lines cC and cB have the same length. Therefore the three points A, B and C all lie on the orange circle whose centre is at c which we just constructed by intersecting these two bisector lines.

By bisector symmetry the angle aAc specified by d is equal to the angle aCc, and the angle cCb is equal to the angle cBb specified by d’. In other words d equals d’.

The tangent line to the orange circle at A is perpendicular to the radius line cA; if we rotate it anticlockwise about the point A through the angle d then it will be aligned with AE. Similarly, the tangent line to the orange circle at B is perpendicular to the radius line bB, and if we rotate it anticlockwise about the point B through the angle d’ then it will be aligned with EB.

Because the construction of both these lines are the equivalent (due to the sizes of the angles d and d’ being the same), the chord lengths of Ah and Bk are the same (where A, h and E are collinear and E, B and k are collinear).

We need to equate the angles chE and chE to prove symmetry. The perpendicular bisector of the chord Ah will pass through the centre of the circle c, and therefore by symmetry around this line the angle chE is equal to 90 degrees plus the angle d. But we also know that the angle cBE is also 90 degrees plus the same angle d’ (since the lines bB and BE are perpendicular).

This proves that the triangles chE and cBE are equal. Therefore the line length Eh equals EB. Since the chord lengths Ah and Bk are equal, the length of Bk is the length of AE minus the length of Eh, which puts k at exactly the point where we originally constructed D in the statement of the theorem.

The orange circle about c passes through the points A, B and D, which is a statement that crucially does not depend on the choice of the biarc.

I’m not saying that any of the above is easy. The consequence, however, is a remarkably easy method to find biarcs.

Using my namedtuple P2 class with a few basic functions, like so:

```class P2(namedtuple('P2', ['u', 'v'])): ...
def Dot(a, b):  return a.u*b.u + a.v*b.v
def CPerp(v):  return P2(v.v, -v.u)
def APerp(v):  return P2(-v.v, v.u)
```

Start with the points A and B with unit normal vectors nA and nB.

To find the intersection of the tangents we need to solve:

`E = A + CPerp(nA)*sA = B + APerp(nB)*sB`

Compute the values of sA and sB by dotting this equation with nA and nB and dividing out:

```sA = Dot(B-A, nB)/Dot(CPerp(nA), nB)
sB = Dot(A-B, nA)/Dot(APerp(nB), nA)
E = A + CPerp(nA)*sA
E = B + APerp(nB)*sB  # same value
```

The centre point c of the orange circle lies on the perpendicular bisector of BD at an unknown distance of h along this perpendicular where it interesects the angle bisector line from E (which is parallel to nA+nB).

```sH = ((sA+sB)*0.5)
c = E + CPerp(nB)*sH + nB*h

solve: Dot(c - E, CPerp(nA + nB)) = 0
0 = Dot(CPerp(nB)*sH + nB*h, CPerp(nA) + CPerp(nB))
= Dot(nA, nB)*sH + h*Dot(nB, CPerp(nA)) + sH
h = -(Dot(nB, nA)+1)*sH / Dot(nB, CPerp(nA))
```

This means we’re almost done as we know where the c lies. All that remains is to choose the point C on this circle.

```Project a point from the chord between hB to the circle
centred on c with radius rC.

Let 0<lam<1 refer to a point position along this chord.

rC = (CPerp(nA)*(s1-s0)/2 + nA*h).Len()
= sqrt((s1-s0)**2/4 + h**2)
sM = min(sA, sB)
pC = E + (APerp(n0)*(1-lam) + CPerp(n1)*lam)*min(sA, sB)
cpC = pC - c
C = c + cpC*(rC/cpC.Len())
```

Now all that remains is to find the radii of the two arcs in the biarc.

```Left hand arc has radius rA and centre cA:

cA = A + nA*rA

Distance to C should also be rA:

rA = (cA - C).Len() = (A + nA*rA - C).Len()
rA**2 = (A - C).Len()**2 + 2*Dot(A - C, nA)*nA + rA**2

rA = -(A - C).Len()**2 / (2*Dot(A - C, nA))

Similarly:

rB = -(B - C).Len()**2 / (2*Dot(B - C, nB))
```

Basically, the entire operation is done with with a few dot products and around 2 square roots. No quadratic equations needed to be solved, so we’ve not had to mess around with choosing the right polynomial root or any guesswork which this entails.

This should be able to extend into a reliable arc fitting algorithm to a point sequence which I’ll get to at some point later.