Approximating a Circle with Bezier Curves.

Introduction.

This is not something I've wanted to do before just recently. I'm working with GTK+3 via gdk2. and the Cairo graphics faciliities draw arcs just fine. However, I've been investigating tensor-product patch meshes, recently provided by Cairo 1.12, and they require me to do everything in terms of straight lines or Bezier curves.

A search on the web turns up loads of results, but most of them didn't help me. I only need to have a superficial overview of the math - which I already had for Bezier curves, and I certainly don't need a proof. What I was looking for was a bit of code in some comprehensible language that I could lift - I'm always in a hurry. I did not find that, so here it is, with the minimum preamble. In this case, the language is D, but if you can read C or C++, or Java ... you should be OK. First my attempt at a pictorial explanation:

There's a magic number involved, that the mathematical treatments derive - here m which equals 0.55191502449.

You'll need four curves to get a decent approximation to a circle of radius r. If you're drawing a circle around the origin (0,0), you need four points to define each quadrant, as shown above. If you are drawing it around a point (x,y), you'll have to add the offsets of the center to each of these coordinates. Assuming the direction of increasing Y is downward, the first curve around the origin using Cairo Context c, is:


c.moveTo(0, -r);
c.curveTo(m*r,-r, r,-m*r, r,0);
Around an arbitrary center(x,y), that becomes:

c.moveTo(x, y-r);
c.curveTo(x+m*r,y-r, x+r,y-m*r, x+r,y);
For the next quadrant and so on, if you can't work out that sort of thing immediately in your head, print out the image, then you can turn if round 90° at a time and fill in the blanks

c.curveTo(x+r,y+m*r, x+m*r,y+r, x,y+r);
c.curveTo(x-m*r,y+r, x-r,y+m*r, x-r,y);
c.curveTo(x-r,y-m*r, x-m*r,y-r, x,y-r);
Adding the other essentials, that gives us

double x = 100, y = 100, r = 80;
double m = 0.55191502449;
c.setLineWidth(1);
c.setSourceRgb(0,0,0);
c.moveTo(x, y-r);
c.curveTo(x+m*r,y-r, x+r,y-m*r, x+r,y);
c.curveTo(x+r,y+m*r, x+m*r,y+r, x,y+r);
c.curveTo(x-m*r,y+r, x-r,y+m*r, x-r,y);
c.curveTo(x-r,y-m*r, x-m*r,y-r, x,y-r);
c.closePath();
c.stroke();
I paste that into my little 'what-happens' drawing program, and the result is:

Can you tell the difference? It's not a question I can answer, since I'm wearing progressive specs whose prescription is about seven years old. The math articles will tell you about the maximum deviation from a true circle and at what angles it occurs.