Points on Circumference
geometryfunctionjavascriptarchivedCircle boundary points
Given a circle with a centre point at cx, cy, with a radius cr, this function returns a list of coordinates that make the pixel positions, or integer positions, of the edge of the circle (the circles circumference).
This is known as Bresenhams Circle Algorithm, and is a form of midpoint-circle algorithm that is particularly efficient as it only calculates an 8th of the circles circumference and simply mirrors and flips the generated coordinates 8 times, massively reducing computational costs.
function pointsOnCircumference(cx, cy, cr)
{
var list = new Array();
var x = cr;
var y = 0;
var o2 = Math.floor(1 - x);
while(y <= x)
{
list.push([ x + cx, y + cy]);
list.push([ y + cx, x + cy]);
list.push([-x + cx, y + cy]);
list.push([-y + cx, x + cy]);
list.push([-x + cx, -y + cy]);
list.push([-y + cx, -x + cy]);
list.push([ x + cx, -y + cy]);
list.push([ y + cx, -x + cy]);
y+= 1;
if(o2 <= 0) { o2+= (2 * y) + 1; }
else
{
x-= 1;
o2+= (2 * (y - x)) + 1;
}
}
return list;
}
Example source code
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
var ctx = null, game = null;
var mouseX = 30, mouseY = 20, radius = 5;
var pointList = null;
window.onload = function() {
game = document.getElementById('game');
ctx = game.getContext('2d');
ctx.font = "bold 10pt sans-serif";
pointList = pointsOnCircumference(mouseX, mouseY, radius);
game.addEventListener('mouseup', function(e) {
// Store the position of the last mouse click for reference
var prevX = mouseX;
var prevY = mouseY;
// Get the position of the mouse click on the page
mouseX = e.pageX;
mouseY = e.pageY;
// Find the offset of the Canvas relative to the document top, left,
// and modify the mouse position to account for this
var p = game;
do
{
mouseX-= p.offsetLeft;
mouseY-= p.offsetTop;
p = p.offsetParent;
} while(p!=null);
// fit the real mouse position to our 10x10 grid
mouseX = Math.floor(mouseX / 10);
mouseY = Math.floor(mouseY / 10);
// If the previous grid click was the same tile as this one, change the radius
if(prevX == mouseX && prevY == mouseY) { radius = (radius < 12 ? radius+1 : 3); }
// Update the list of points on the circles circumference
pointList = pointsOnCircumference(mouseX, mouseY, radius);
// Show a list of points for information
var htm = '';
for(p in pointList)
{
htm+= '<li>' + pointList[p][0] + ', ' + pointList[p][1] + '</li>';
}
document.getElementById('pointList').innerHTML = htm;
});
requestAnimationFrame(drawGame);
};
function pointsOnCircumference(cx, cy, cr)
{
var list = new Array();
var x = cr;
var y = 0;
var o2 = Math.floor(1 - x);
while(y <= x)
{
list.push([ x + cx, y + cy]);
list.push([ y + cx, x + cy]);
list.push([-x + cx, y + cy]);
list.push([-y + cx, x + cy]);
list.push([-x + cx, -y + cy]);
list.push([-y + cx, -x + cy]);
list.push([ x + cx, -y + cy]);
list.push([ y + cx, -x + cy]);
y+= 1;
if(o2 <= 0) { o2+= (2 * y) + 1; }
else
{
x-= 1;
o2+= (2 * (y - x)) + 1;
}
}
return list;
}
function drawGame()
{
if(ctx==null) { return; }
// Clear the Canvas
ctx.fillStyle = "#ffffff";
ctx.fillRect(0, 0, 600, 400);
// Draw the grid
ctx.strokeStyle = "#999999";
ctx.beginPath();
for(y = 0; y < (400/10); ++y)
{
for(x = 0; x < (600/10); ++x)
{
ctx.rect((x*10), (y*10), 10, 10);
}
}
ctx.closePath();
ctx.stroke();
// Draw the points on the circles edge
ctx.fillStyle = "#ff9999";
ctx.strokeStyle = "#ff3333";
ctx.beginPath();
for(p in pointList)
{
ctx.rect(pointList[p][0] * 10, pointList[p][1] * 10, 10, 10);
}
ctx.closePath();
ctx.fill();
ctx.stroke();
// Show some information...
ctx.fillStyle = "#ff0000";
ctx.fillText("Circle at " + mouseX + "," + mouseY + " radius " + radius, 10, 20);
// Ask for the next animation frame
requestAnimationFrame(drawGame);
}
</script>
</head>
<body>
<p>Click on the grid to draw a circle there. Click repeatedly on the same point to resize the circle.</p>
<canvas id="game" width="600" height="400"></canvas>
<ul id="pointList" style="font-family:monospace;"></ul>
</body>
</html>