Friday, May 23, 2008

Approximating a Semicircle with a Cubic Nonrational Bezier Curve

At times I have had the need to approximate a semicircle with two quadratic Bezier curves.

Recently I wanted to approximate a semicircle with one Bezier curve. I decided to do this with a non-rational cubic Bezier curve.

First I made a cubic Bezier curve with a control polygon whose points correspond to a unit square.

Then I plotted a circle against the Bezier curve to see how close the Bezier curve was to a semicircle. It wasn't very close. So I knew I needed to adjust the Y values of P1 and P2 to bring down the curve. But how much? I evaluated the Bezier curve parametrically at t = 0.5 and determined that the y value at t = 0.5 was 0.75 or 3/4.

The radius of the semicircle is 0.5. I needed to move the Bezier curve down from 0.75 to 0.5. To do this I adjust the Y value of points P1 and P2 by:

yValueOffset = radius * 4.0 / 3.0

The resulting Bezier control polygon and curve is shown in the following image.
That looks more like a semicircle. Following is the same image with the semicircle plotted against it for reference.

For most situations this approximation will suffice. However, I decided to try and get it a bit closer! The next change was done by some calculations which yielded a value that was very close but to tell the truth my math and the complexity of the blending functions where such that I am not sure at this time if my conclusions are correct. (Note: Don't let your math skills get too rusty!)

While I endeavor to get the correct solution to the problem I will at this time share with you an easy value to remember that tightens up the Bezier curve close to the circle. The magic number is 0.05.

By insetting points P1 and P2 in the X value only the resulting Bezier control polygon and curve are shown in the following image.

Notice how nicely this cubic non-rational Bezier curve approximates a semicircle.

Here is an enlarged image so that you can see how nicely the curve fits the semicircle. (Click Image to see larger view.)

So, in summary:

xValueInset = Diameter * 0.05
yValueOffset = radius * 4.0 / 3.0

P0 = (0,0)
P1 = (xValueInset, yValueOffset)
P2 = (Diameter - xValueInset, yValueOffset)
P3 = (Diameter, 0)

This gives a pretty good approximation to a semicircle using only one Bezier curve.


lucie said...

Yes I can tell instantly that it's not a half circle, because the vertical tangent.. is not vertical

Geoff Slinker said...

It has been a long time since I posted this, but if I recall correctly the image with the thick line is a semi-circle.

Adriel said...

Nice post. Thanks!