How to Draw an Offset Curve

I was prototyping something and I needed to draw a curve with some thickness. It wasn’t just the case of increasing the thickness of the stroke, I wanted to find the contour of a curve, to draw two new curves around one in the center. After some research, I learnt that the correct term for that is parallel curve or offset curve.

The task turned out to be not as simple as I thought. After some failed attempts I found the solution in a paper by Gabriel Suchowolski entitled ‘Quadratic bezier offsetting with selective subdivision‘. The recipe is there, but I was missing an open source implementation so I decided to write one.
In this post I present a step by step process and at the end an interactive version written in Javascript.

How to draw an offset curve:

Start with 3 points.
wide-01

Draw a quadratic curve using p1 and p2 as anchors and c as the control point.
wide-02

Get the vectors between these points.
v1 = c - p1
v2 = p2 - c

Find the vector perpendicular to v1 and scale it to the width (or thickness) of the new curve.
Add the new temporary vector to p1 to find p1a, then subtract from p1 it to find p1b.
Do the same with c to find c1a and c1b.
wide-03 width=

Repeat the same process with v2 to find the points on the other side.
wide-04

Find vectors between the new points. These are parallel to v1 and v2 and offset by the given thickness.
wide-05

The intersection points of these vectors are the new control points ca and cb.
wide-06

Draw a curve from p1a to p2a with control point at ca.
Draw another curve from p1b to p2b with control point at cb.
wide-07

This method works only when the angle between v1 and v2 is wide (bigger than 90 degrees), it doesn’t work for sharp angles.
wide-08

For angles smaller than 90 degrees it is necessary to split the curve. In fact the curve could be split several times, the more the better the precision of the offset curve. To do it only at 90 degrees is fast and the result is not too bad.

The curve needs to be split at t, which is the closest point to c in the curve. The technique to find t has been described in the paper I mentioned before. It requires solving a third degree polynomial like this ax3+bx2+cx+d=0
third-degree-polynomial

The equation returns a number between 0 and 1 that can be plotted in the curve to find t.
curve-07

Find the tangent of t and the points t1 and t2 where it intersects v1 and v2.
Create a new vector perpendicular to the tangent of t, scale it to the given thickness and find qa and qb. This vector splits the original curve at t.
curve-08

Add the tangent of t to qa and qb and find the points where it intersects the offset vectors.
curve-09

These are all the points needed to draw an offset curve. All the others that were created in the process can be removed for clarity.
Draw a curve with anchors at p1a and qa with the control point at q1a.
curve-10

Repeat the process for all the new points to get the offset curve.
curve-11

Here is an interactive version. Drag the gray dots to change the curve.

See the Pen VYEWgY by Bruno Imbrizi (@brunoimbrizi) on CodePen.

Thanks to:
– Gabriel Suchowolski (aka @microbians) for his paper
toxiclibs for the really handy Vec2D and Line2D classes
– Professor Eric Schechter for The Cubic Formula

Leave a Reply

Your email address will not be published. Required fields are marked *