

How to Draw a Circle - hendi_
https://banu.com/blog/7/drawing-circles/

======
drallison
How to draw a circle (HAKMEM 149 through HAKMEM 152) reproduced below.

ITEM 149 (Minsky): CIRCLE ALGORITHM Here is an elegant way to draw almost
circles on a point-plotting display:

NEW X = OLD X - epsilon * OLD Y NEW Y = OLD Y + epsilon * NEW(!) X

This makes a very round ellipse centered at the origin with its size
determined by the initial point. epsilon determines the angular velocity of
the circulating point, and slightly affects the eccentricity. If epsilon is a
power of 2, then we don't even need multiplication, let alone square roots,
sines, and cosines! The "circle" will be perfectly stable because the points
soon become periodic.

The circle algorithm was invented by mistake when I tried to save one register
in a display hack! Ben Gurley had an amazing display hack using only about six
or seven instructions, and it was a great wonder. But it was basically line-
oriented. It occurred to me that it would be exciting to have curves, and I
was trying to get a curve display hack with minimal instructions.

ITEM 150 (Schroeppel): PROBLEM: Although the reason for the circle algorithm's
stability is unclear, what is the number of distinct sets of radii? (Note:
algorithm is invertible, so all points have predecessors.)

ITEM 151 (Gosper): Separating X from Y in the above recurrence,

X(N+1) = (2 - epsilon^2) * X(N) - X(N-1) Y(N+1) = (2 - epsilon) * Y(N) -
Y(N-1).

These are just the Chebychev recurrence with cos theta (the angular increment)
= 1-epsilon^2/2. Thus X(N) and Y(N) are expressible in the form R cos(N theta
+ phi). The phi's and R for X(N) and Y(N) can be found from N=0,1. The phi's
will differ by less than pi/2 so that the curve is not really a circle. The
algorithm is useful nevertheless, because it needs no sine or square root
function, even to get started.

X(N) and Y(N) are also expressible in closed form in the algebra of ordered
pairs described under linear recurrences, but they lack the remarkable
numerical stability of the "simultaneous" form of the recurrence.

ITEM 152 (Salamin): With exact arithmetic, the circle algorithm is stable iff
|epsilon| < 2\. In this case, all points lie on the ellipse

X^2 - epsilon X Y + Y^2 = constant,

where the constant is determined by the initial point. This ellipse has its
major axis at 45 degrees (if epsilon > 0) or 135 degrees (if epsilon < 0) and
has eccentricity

sqrt(epsilon/(1 + epsilon/2)).

For the full MIT HAKMEM (a report everyone who programs should read at some
point) <http://www.inwap.com/pdp10/hbaker/hakmem/hacks.html>

~~~
binarymax
Looks like this would be awesome but I can't seem to get it to work (ITEM
149)...I tried for lots of different values of epsilon. Maybe I'm
misunderstanding what a point-plotting display is?

<http://jsbin.com/umurar/edit#source>

EDIT: err - nevermind, I had a silly bug that didnt update the old values.
Kinda working now!

<http://jsbin.com/umurar/6/edit#source>

~~~
daeken
I just took your 6th revision and started playing around with the parameters,
and it's interesting how much variation you can get with simple manipulation:
<http://jsbin.com/umurar/11/edit>

------
kragen
In the blog post, he links to this Slashdot comment about circle-drawing at
Apple on the Macintosh project here:
[http://apple.slashdot.org/comments.pl?sid=2462124&cid=37...](http://apple.slashdot.org/comments.pl?sid=2462124&cid=37619800)

Which links to
[http://www.folklore.org/StoryView.py?project=Macintosh&s...](http://www.folklore.org/StoryView.py?project=Macintosh&story=Round_Rects_Are_Everywhere.txt),
which talks a little bit about algorithms for drawing circles, ellipses, and
RoundRects, and in particular what was used in QuickDraw.

QuickDraw source code is available at
<http://www.computerhistory.org/highlights/macpaint/> and I've posted what I
think is the relevant file at <https://gist.github.com/1287861>. I think the
relevant routine is BumpOval, starting around line 1000. But I don't
understand it at all, partly because it's been 18 years since I looked at
68000 assembly. Can anyone help explain what's going on in there? I'd like to
know if the algorithm being used there is the same one in Mukund's awesome
blog post.

One bug: Mukund, if you're going to call malloc() without checking its return
value, use xmalloc()! It's like five lines of code.

~~~
tptacek
I don't know what the deal is on Linux, but in professional code, I disagree:
don't both checking malloc, just rig malloc to blow up when it fails.

You'll do more harm trying to use something like xmalloc and failing to use it
consistently (obviously you need to "x" more than just "malloc") than you will
by taking steps to guarantee a swift failure to make sure _any_ malloc failure
ends the program.

Obviously, in any code where "malloc(3)" is the way you get more memory, I
think it's pretty silly to check malloc's return value. You aren't going to
get recovery right.

~~~
kragen
Maybe you're thinking of a different xmalloc than I am? I'm talking about the
one from libiberty, which is _exactly_ a way to "rig malloc to blow up when it
fails". (edited:) Or do you mean that xmalloc isn't a reliable way to do that
because some piece of your code might call malloc instead? Is it better to
depend on some nonstandard behavior from the standard library?

I think there are only very rare cases in production code where it makes sense
to check malloc's return value and try to recover, but they do occasionally
exist.

~~~
tptacek
No, I'm thinking of the exact same thing you're thinking of, and I'm saying
the "xmalloc" solution looks like it does the same thing as simply rigging
malloc to blow up, but does not do so consistently (because "x" malloc isn't
going to be used consistently).

I think we agree about explicit malloc return value checks.

~~~
kragen
It's good to agree with you about something.

I don't think I understand what you mean by 'obviously you need to "x" more
than just "malloc"'. If you use xmalloc() instead of malloc(), and either
abjure realloc() or use xrealloc(), haven't you covered all your bases?

It's true that a bug could creep in somewhere, but that hardly seems like a
particularly damning criticism. Every place you use xmalloc() instead of
malloc() is one less bug, one less potential Mark Dowd Flash exploit. And you
can use nm(1) or the Visual Studio equivalent to find out if your program
still has any calls to malloc() or realloc(), and then you can remove them.

From my perspective, the problem with rigging malloc() itself to blow up is
that there's no portable, standard way to do that. And, if someone fails to do
it when they're porting your code to a new platform, everything will appear to
work perfectly, but the port will have introduced a subtle bug that may result
in remote-root vulnerabilities. That would be really bad.

~~~
tptacek
Try to list all the other functions that need "x" equivalents. Here's a free
one: xcalloc.

~~~
kragen
True! It's already in xmalloc.c, but xstrdup isn't. And if you're using third-
party libraries that call malloc(), you're probably screwed unless you have a
way to change malloc()'s behavior. So you've basically convinced me.

~~~
tptacek
Yay! Another convert! We're gradually taking over the world.

It is seriously soooo much easier to write C code when you don't have to
explicitly check allocation returns. I shaved FOUR THOUSAND LINES out of not-
particularly- huge- to- begin- with- server in a previous job simply by
getting rid of ridiculous chains of "functions that returned errors that
ultimately boiled down to malloc failures", and "call sites to those functions
that checked their errors and propagated them". I'll never explicitly check
malloc() again.

(There are allocators you do need to check; they just tend not to be called
"malloc").

~~~
dr_rezzy
So you are saying that adhering to memory bounds and limits (and possibly
SLAs) should be ignored in favor of having your software crash because its
easier? Sure, I can see it as a possible strategy in some cases. But to go
ahead and cite this as a rule is kind of short sighted and a disservice to
people who put thought into their memory allocation strategies.

~~~
tptacek
No. I favor not kidding yourself.

Almost no software of any significant size has been written in the last 10
years that can honestly claim to gracefully _and reliably_ handle out-of-
memory conditions.

Programming regimes that ostensibly cover out-of-memory cases are usually
delusive; they provide for some superficial handling of out-of-memory issues
(which usually just devolves to exiting the program anyways), but do nothing
to address the myriad instances of malloc calls happening behind their backs
in libraries or temporary allocations.

Fuck that. These people are going through extra work which (a) provides no
greater user experience and (b) actually harms their program by creating
opportunities for missed checks that propagate NULL pointers (which, when
offset against, are actually exploitable!) through the rest of their code.

Just have malloc terminate your program for you when it fails and be done with
it. You seriously aren't going to get anything else right, and it's silly to
waste your time trying anyways.

~~~
kragen
The exceptions, I think, require that you aren't using tons of buggy third-
party libraries. In AAA games and in bare-metal programming, for example,
exiting the program is not an option, so you don't use libraries that might do
that.

------
heyrhett
I thought this was going to be about the World Freehand Circle Drawing
Champion: <http://www.youtube.com/watch?v=eAhfZUZiwSE>

------
michaelfeathers
> Circles are invisible. When we say we want to draw a circle on the screen,
> we want to set pixels (light up equally sized rectangular bits of the
> screen) at integer coordinates to represent an approximation of the circle.

Priceless.

~~~
skeptical
I don't think that paragraph is of much value, and I think all the replies you
got kind of address a non existent discussion.

I don't think it makes sense to discuss if a mathematical concept is 'visible'
just because it happens to be something that is often represented on a 2d
plot.

This discussion is not visible, what's visible is the group of pixels that
form the text on the display device you're using to read this webpage.

Honestly, is this kind of observation of any value?

~~~
skermes
When I spend all day hopping up and down through different levels of
abstraction in the service of building some particular program, it's all too
easy to start confusing the map with the territory. If I'm writing some code
to draw a circle, I might also have the circle stored on disk in a file that
lists a (center, radius) pair, and I might be passing it around in memory as
an IDrawable object for someone else's code to consume and I'm putting it on
the screen wit pixels and so on and so on and at a certain point it does
become useful to have someone remind me that none of those things are really
the same circle, or really circles at all, but all representations of some
Platonic circle that doesn't actually exist in my code. This problem gets
worse when more than one programmer is involved. How many arguments have we
seen between two people who agree with each other, but can't tell because
they're stuck arguing over whether (center, radius) or a pixel group is "the
real circle"?

So no, it's not of much value in that it doesn't tell us anything that we
don't already know. But it can be of value to frame our understanding or
discussion of the problem.

------
jbum
CG pioneer Jim Blinn wrote an excellent article which provides a myriad of
ways to do it.

<http://dl.acm.org/citation.cfm?id=1435623.1436274>

It was republished in his excellent collection of essays "A Trip down the
Graphics Pipeline"

------
rhizome31
Thanks, as a programmer (re)learning math and trig this will be a good
exercise.

~~~
kragen
For me, at least, graphics was the way to learn trig in the first place. I
wanted to make a thingy on the screen go at a specified angle at a specified
speed, so that I could change its angle without changing the speed, and I
vaguely knew that this had something to do with sine and cosine, so I took a
trig textbook off the shelf and puzzled it out. Didn't need things like the
double-angle formulas, though, so I didn't learn those until I took a class
that covered them.

------
joejohnson
I couldn't tell in the third example, wouldn't it be rather efficient to make
a filled-in large black circle with radius r and then make a concentric
filled-in white circle with radius r - epsilon? Epsilon would be the thickness
of the circle (not exactly one pixel, but could be close).

I couldn't tell if he thought of this method, but it is a quick way to draw a
circle.

~~~
muks
What's discussed in the article depends on the capabilities of hardware you
are targeting. :) Filling is typically a bottleneck as you are writing to a
lot of memory. Square roots can also be rather slow, esp. when there's no
hardware implementation of it. Square roots, divisions, multiplications,
additions and subtractions, and shifts perform in order of slowest to fastest.
Some processors have no floating point hardware. Some processors do shifts,
additions and subtractions much faster than multiplications and divisions.

Think of the article as a bunch of ways to draw circles, and you can make up
something based on what device you write your code for. :)

Drawing the circle as points using the last function in the article, rather
than 2 concentric fills would be faster unless you have some unique hardware
for it. :) Disk filling can be implemented in a fragment shader by testing
each point against the implicit equation. Such testing is easily parallelized.

You are a clever thinker nevertheless. :)

------
zokier
All the talk about optimizing but not a single performance measurement or even
estimate.

------
JeffL
Fun article, but what about anti-aliased circles and thick circles?

------
veyron
reminds me of: [http://stackoverflow.com/questions/7618374/bresenhams-
circle...](http://stackoverflow.com/questions/7618374/bresenhams-circle-
algorithm)

------
jrockway
In image_new, doesn't he want to allocate enough memory for an Image rather
than for whatever the sizeof an image* is?

~~~
kragen
No, image is an Image _, so_ image is an Image, so sizeof _image is the amount
of memory you need to allocate for an Image. Saying sizeof_ image rather than
sizeof Image allows you to change the type of image in one fewer place, should
you want to do that.

~~~
kragen
Fucking piece of shit Arc. I'm very sorry that this comment I wrote above is
completely fucking wrong because of the deletion of asterisks.

~~~
jrockway
I knew what you meant. I tend to use ∗ when I can't get * to work.

------
ObnoxiousJul
Well, yet another CS (under)graduated used to reason in term of optimisation
in the code based on false misconceptions : \- a circle is drawed differently
if you change the _geometrical_ context (what if we asked to draw a circle on
a sphere or any others non euclidian/cartesian geometry ?).
Cartesian/euclidian definition of a problem can be the problem. \- a circle is
a stupid singular case, it can be seen either as a peculiar case of rectangle
with rounded corner, or an ellipse. Will he make distinct algorithm for
rectangle, circle, rounded cornered rectangle, ellipse ? \- Its algorithm
lacks the _divide and conquer_ aspect : for instance, he could create the
bondaries, and then fill in the form. Thus mutualizing much more code than
what is shown, thus respecting the DRY imperative. \- his explications does
not suits godel _stick up your nose from a problem to solve it_ I was
expecting a model oriented problem solving. \- I am astonished at the level of
computer illeteracy : GGI, gimp, SDL and a lot of open source code have circle
drawing algorithm implemented wich worth man * years of effort, I guess they
already have smart algorithm. CS is about standing on the giant's shoulder,
and learning to learn. He clearly fails on both this points which are
important in our craft.

Well, I was clearly disappointed this lousy article got so much points. What
is important for me in CS is not the algorithm and the code, but how the code
elegantly express the general understanding of a real problem into code. How
one can fluently translate from a natural language problem into code, and
swicth from reformulation of the problem to coding.

These kind of developpers should not be hired at any costs at my opinion.

