250

How can the following function be implemented in various languages?

Calculate the (x,y) point on the circumference of a circle, given input values of:

  • Radius
  • Angle
  • Origin (optional parameter, if supported by the language)
Justin Ethier
  • 131,333
  • 52
  • 229
  • 284

6 Answers6

645

The parametric equation for a circle is

x = cx + r * cos(a)
y = cy + r * sin(a)

Where r is the radius, cx,cy the origin, and a the angle.

That's pretty easy to adapt into any language with basic trig functions. Note that most languages will use radians for the angle in trig functions, so rather than cycling through 0..360 degrees, you're cycling through 0..2PI radians.

Paul Dixon
  • 295,876
  • 54
  • 310
  • 348
  • 118
    Note that `a` must be in radians - that was really hard for me as a beginner to understand. – ioan Jun 02 '13 at 20:55
  • 13
    I've been trying to derive this equation for an hour now. Thanks. Who know the trig identities you learned in high school would be so helpful. – Isioma Nnodum May 28 '14 at 22:37
  • 1
    @Dean No need for extra brackets because of the operator precedence. When you have `+` and `*` like in those two equations and without any brackets you always go for the `*` first and then for the `+`. – rbaleksandar Oct 30 '15 at 07:27
  • 13
    @IsiomaNnodum Couldn't have been that helpful if we're all coming back here just to remember what the equation was. – arkon Aug 07 '16 at 22:17
56

My implementation in C#:

public static PointF PointOnCircle(float radius, float angleInDegrees, PointF origin)
{
    // Convert from degrees to radians via multiplication by PI/180        
    float x = (float)(radius * Math.Cos(angleInDegrees * Math.PI / 180F)) + origin.X;
    float y = (float)(radius * Math.Sin(angleInDegrees * Math.PI / 180F)) + origin.Y;

    return new PointF(x, y);
}
Pang
  • 9,564
  • 146
  • 81
  • 122
Justin Ethier
  • 131,333
  • 52
  • 229
  • 284
  • 6
    Pre-compute the conversion factor so there's less chance you type the conversion wrong using hard-coded numbers. – Scottie T May 08 '09 at 14:15
18

Who needs trig when you have complex numbers:

#include <complex.h>
#include <math.h>

#define PI      3.14159265358979323846

typedef complex double Point;

Point point_on_circle ( double radius, double angle_in_degrees, Point centre )
{
    return centre + radius * cexp ( PI * I * ( angle_in_degrees  / 180.0 ) );
}
Pete Kirkham
  • 48,893
  • 5
  • 92
  • 171
  • How does this work? How does it compare speed wise? Why isn't this more commonly used? – Mark A. Ropper Feb 16 '18 at 17:42
  • @MarkA.Ropper how do complex numbers work? - look up a maths tutorial or go from https://en.wikipedia.org/wiki/Euler%27s_identity if you already know what a complex number is. It's probably not as efficient in speed compared to say implementing sin as a look-up table, but sometimes you are using complex numbers to represent points throughout to exploit other properties of them. Similar to using quaternions for 3D rotations, it's not really the speed but the capabilities they give you. – Pete Kirkham Feb 19 '18 at 09:44
9

Implemented in JavaScript (ES6):

/**
    * Calculate x and y in circle's circumference
    * @param {Object} input - The input parameters
    * @param {number} input.radius - The circle's radius
    * @param {number} input.angle - The angle in degrees
    * @param {number} input.cx - The circle's origin x
    * @param {number} input.cy - The circle's origin y
    * @returns {Array[number,number]} The calculated x and y
*/
function pointsOnCircle({ radius, angle, cx, cy }){

    angle = angle * ( Math.PI / 180 ); // Convert from Degrees to Radians
    const x = cx + radius * Math.sin(angle);
    const y = cy + radius * Math.cos(angle);
    return [ x, y ];

}

Usage:

const [ x, y ] = pointsOnCircle({ radius: 100, angle: 180, cx: 150, cy: 150 });
console.log( x, y );

Codepen

/**
 * Calculate x and y in circle's circumference
 * @param {Object} input - The input parameters
 * @param {number} input.radius - The circle's radius
 * @param {number} input.angle - The angle in degrees
 * @param {number} input.cx - The circle's origin x
 * @param {number} input.cy - The circle's origin y
 * @returns {Array[number,number]} The calculated x and y
 */
function pointsOnCircle({ radius, angle, cx, cy }){
  angle = angle * ( Math.PI / 180 ); // Convert from Degrees to Radians
  const x = cx + radius * Math.sin(angle);
  const y = cy + radius * Math.cos(angle);
  return [ x, y ];
}

const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");

function draw( x, y ){

  ctx.clearRect( 0, 0, canvas.width, canvas.height );
  ctx.beginPath();
  ctx.strokeStyle = "orange";
  ctx.arc( 100, 100, 80, 0, 2 * Math.PI);
  ctx.lineWidth = 3;
  ctx.stroke();
  ctx.closePath();

  ctx.beginPath();
  ctx.fillStyle = "indigo";
  ctx.arc( x, y, 6, 0, 2 * Math.PI);
  ctx.fill();
  ctx.closePath();
  
}

let angle = 0;  // In degrees
setInterval(function(){

  const [ x, y ] = pointsOnCircle({ radius: 80, angle: angle++, cx: 100, cy: 100 });
  console.log( x, y );
  draw( x, y );
  document.querySelector("#degrees").innerHTML = angle + "&deg;";
  document.querySelector("#points").textContent = x.toFixed() + "," + y.toFixed();

}, 100 );
<p>Degrees: <span id="degrees">0</span></p>
<p>Points on Circle (x,y): <span id="points">0,0</span></p>
<canvas width="200" height="200" style="border: 1px solid"></canvas>
tommyc38
  • 703
  • 1
  • 8
  • 21
Kostas Minaidis
  • 4,681
  • 3
  • 17
  • 25
2

Calculating point around circumference of circle given distance travelled.
For comparison... This may be useful in Game AI when moving around a solid object in a direct path.

enter image description here

public static Point DestinationCoordinatesArc(Int32 startingPointX, Int32 startingPointY,
    Int32 circleOriginX, Int32 circleOriginY, float distanceToMove,
    ClockDirection clockDirection, float radius)
{
    // Note: distanceToMove and radius parameters are float type to avoid integer division
    // which will discard remainder

    var theta = (distanceToMove / radius) * (clockDirection == ClockDirection.Clockwise ? 1 : -1);
    var destinationX = circleOriginX + (startingPointX - circleOriginX) * Math.Cos(theta) - (startingPointY - circleOriginY) * Math.Sin(theta);
    var destinationY = circleOriginY + (startingPointX - circleOriginX) * Math.Sin(theta) + (startingPointY - circleOriginY) * Math.Cos(theta);

    // Round to avoid integer conversion truncation
    return new Point((Int32)Math.Round(destinationX), (Int32)Math.Round(destinationY));
}

/// <summary>
/// Possible clock directions.
/// </summary>
public enum ClockDirection
{
    [Description("Time moving forwards.")]
    Clockwise,
    [Description("Time moving moving backwards.")]
    CounterClockwise
}

private void ButtonArcDemo_Click(object sender, EventArgs e)
{
    Brush aBrush = (Brush)Brushes.Black;
    Graphics g = this.CreateGraphics();

    var startingPointX = 125;
    var startingPointY = 75;
    for (var count = 0; count < 62; count++)
    {
        var point = DestinationCoordinatesArc(
            startingPointX: startingPointX, startingPointY: startingPointY,
            circleOriginX: 75, circleOriginY: 75,
            distanceToMove: 5,
            clockDirection: ClockDirection.Clockwise, radius: 50);
        g.FillRectangle(aBrush, point.X, point.Y, 1, 1);

        startingPointX = point.X;
        startingPointY = point.Y;

        // Pause to visually observe/confirm clock direction
        System.Threading.Thread.Sleep(35);

        Debug.WriteLine($"DestinationCoordinatesArc({point.X}, {point.Y}");
    }
}
legacybass
  • 582
  • 1
  • 7
  • 20
0
int x = (int)(radius * Math.Cos(degree * Math.PI / 180F)) + cCenterX;
int y = (int)(radius * Math.Sin(degree * Math.PI / 180F)) + cCenterY;

The cCenterX and cCenterY are the center point of the circle

Amin Shojaei
  • 5,451
  • 2
  • 38
  • 46