An extension of the midpoint circle algorithm for arbitrary integer diameters.
TODO: Add touch support.
Every pixel drawn exactly once. For odd diameters, the origin of the circle at a pixel defined by cx and cy is the center of that pixel; for even diameters it's the top-left corner of that pixel instead. Assumes non-negative diameters. The parameters for p were revealed to me in a dream.
1. Circle
function pixel(x, y);
function oddcircle(cx, cy, r) {
if (r == 0) {
pixel(cx, cy);
return;
}
let x = 1;
let y = -r;
let p = -r + 4;
pixel(cx, cy - r);
pixel(cx, cy + r);
pixel(cx - r, cy);
pixel(cx + r, cy);
while (x <= -y) {
pixel(cx + x, cy + y);
pixel(cx - y, cy + x);
pixel(cx + y, cy - x);
pixel(cx - x, cy - y);
if (x <= -y - 1) {
pixel(cx + y, cy + x);
pixel(cx - x, cy + y);
pixel(cx + x, cy - y);
pixel(cx - y, cy - x);
}
if (p > 0) {
y += 1;
p += 2*y - 1;
}
x += 1;
p += 2*x + 1;
}
}
function evencircle(cx, cy, r) {
if (r == 0) return;
let x = 0;
let y = -r;
let p = -2*r + 5;
while (x < -y) {
pixel(cx + x, cy + y);
pixel(cx - y - 1, cy + x);
pixel(cx + y, cy - x - 1);
pixel(cx - x - 1, cy - y - 1);
if (x < -y - 1) {
pixel(cx + y, cy + x);
pixel(cx - x - 1, cy + y);
pixel(cx + x, cy - y - 1);
pixel(cx - y - 1, cy - x - 1);
}
if (p > 0) {
y += 1;
p += 4*y;
}
x += 1;
p += 4*x + 4;
}
}
function circle(cx, cy, d) {
(d&1 ? oddcircle : evencircle)(cx, cy, d>>1);
}
2. Disk (filled circle)
The algorithm for drawing a circle can be adjusted to fill the circle instead:
function horizline(x1, x2, y) {
for (let x = x1; x <= x2; x++) pixel(x, y);
}
function oddcircle(cx, cy, r) {
// ...
horizline(cx - r, cx + r, cy);
while (x <= -y) {
horizline(cx + y, cx - y, cy - x);
horizline(cx + y, cx - y, cy + x);
if (p > 0) {
if (x <= -y - 1) {
horizline(cx - x, cx + x, cy - y);
horizline(cx - x, cx + x, cy + y);
}
// ...
function evencircle(cx, cy, r) {
// ...
while (x < -y) {
horizline(cx + y, cx - y - 1, cy - x - 1);
horizline(cx + y, cx - y - 1, cy + x);
if (p > 0) {
if (x < -y - 1) {
horizline(cx - x - 1, cx + x, cy - y - 1);
horizline(cx - x - 1, cx + x, cy + y);
}
// ...