Points on Arc Circumference

Fri May 02 2025 15:06:07 GMT+0100 (British Summer Time) geometryfunctionjavascriptarchived

Arc edge coordinates

With this method we can find all the points that fall along the circumference of an arc, given the centre point, the radius, and the start and end angles of the arc in radians.

View example

This function works by using Bresenhams circle algorithm to find all points on the circle circumference, and then computes the angle between the centre and each point to see if that point falls within the arcs start and end angles.

The function is called with the following arguments: cx, cy, cr (the circle of which the arc is formed center X and Y coordinate, and its radius), angleStart and angleEnd (the start and end points of the arc in radians).


function pointsInArc(cx, cy, cr, angleStart, angleEnd)
{
    var list    = pointsOnCircumference(cx, cy, cr);
    var arc    = new Array();
    
    for(i in list)
    {
        var a = getAngle(cx, cy, list[i][0], list[i][1]);

        if(angleStart < 0 && (a >= (Math.PI*2 + angleStart))) { arc.push(list[i]); }
        else if(angleEnd > (Math.PI*2) && a <= (angleEnd - (Math.PI*2))) { arc.push(list[i]); }
        else if(a>=angleStart && a<=angleEnd) { arc.push(list[i]); }
    }
    
    return arc;
}

The return value is a list of coordinates in 2D space that form this arcs circumference.

This function makes use of the getAngle function:


function getAngle(x, y, x2, y2)
{
    var a = Math.atan2(y2 - y, x2 - x);
    return a < 0 ? a + (Math.PI * 2) : a;
}

It also makes use of Bresenhams circle algorithm:


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 circleX = 30, circleY = 20, radius = 10;
var pointList = null, fullPointList = null;
var arcRadius = 1;
var arcStart = Math.PI*0.5, arcEnd = Math.PI*0.8;
var mouseX = 0, mouseY = 0;

window.onload = function() {
    game = document.getElementById('game');
    ctx = game.getContext('2d');
    ctx.font = "bold 10pt sans-serif";

    pointList = pointsInArc(circleX, circleY, radius, arcStart, arcEnd);

    game.addEventListener('mousemove', function(e) {
        // Get the position of the mouse click on the page
        x = e.pageX;
        y = 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
        {
            x-= p.offsetLeft;
            y-= p.offsetTop;

            p = p.offsetParent;
        } while(p!=null);

        // fit the real mouse position to our 10x10 grid
        x = Math.floor(x / 10);
        y = Math.floor(y / 10);
        
        mouseX = x;
        mouseY = y;

        // Find the angle between the circle centre and here
        var a = getAngle(circleX, circleY, x, y);
        arcStart     = a - (arcRadius / 2);
        arcEnd        = a + (arcRadius / 2);

        pointList = pointsInArc(circleX, circleY, radius, arcStart, arcEnd);
    });
    window.addEventListener('keypress', function(e) {
        // Increase / decrease the arc radius
        if(e.keyCode==39) { arcRadius+= 0.1; }
        else if(e.keyCode==37) { arcRadius-= 0.1; }

        // Correct for too small / too large
        if(arcRadius<0.1) { arcRadius = 0.1; }
        if(arcRadius>(Math.PI*2)) { arcRadius = (Math.PI*2); }
        
        // Find the angle between the circle centre and the mouse
        var a = getAngle(circleX, circleY, mouseX, mouseY);
        arcStart     = a - (arcRadius / 2);
        arcEnd        = a + (arcRadius / 2);

        // Update the list of points on the circles circumference
        pointList = pointsInArc(circleX, circleY, radius, arcStart, arcEnd);

        // 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 pointsInArc(cx, cy, cr, angleStart, angleEnd)
{
    var list    = pointsOnCircumference(cx, cy, cr);
    var arc        = new Array();
    
    for(i in list)
    {
        var a = getAngle(cx, cy, list[i][0], list[i][1]);

        if(angleStart < 0 && (a >= (Math.PI*2 + angleStart))) { arc.push(list[i]); }
        else if(angleEnd > (Math.PI*2) && a <= (angleEnd - (Math.PI*2))) { arc.push(list[i]); }
        else if(a>=angleStart && a<=angleEnd) { arc.push(list[i]); }
    }
    
    return arc;
}

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 getAngle(x, y, x2, y2)
{
    var a = Math.atan2(y2 - y, x2 - x);
    return a < 0 ? a + (Math.PI * 2) : a;
}

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 centre of the circle
    ctx.fillStyle = "#aaaaff";
    ctx.strokeStyle = "#0000dd";
    ctx.fillRect(circleX*10, circleY*10, 10, 10);
    ctx.strokeRect(circleX*10, circleY*10, 10, 10);
    
    // 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 " + circleX + "," + circleY + " radius " + radius, 10, 20);
    ctx.fillText("Arc radius: " + arcRadius.toFixed(2) + ", start: " + arcStart.toFixed(2) + ", end: " + arcEnd.toFixed(2), 10, 40);

    // Ask for the next animation frame
    requestAnimationFrame(drawGame);
}
</script>
</head>
<body>

<p>Move the mouse around the grid to change the direction of the arc.  Press the ledt arrow key to reduce the arc radius, and the right arrow key to increase it.  If you do not see the grid and arc, please check you have Javascript enabled and that your browser supports the Canvas element.</p>

<canvas id="game" width="600" height="400"></canvas>
<ul id="pointList" style="font-family:monospace;"></ul>

</body>
</html>