如何计算圆周上的一个点?

251

如何在不同编程语言中实现以下函数?

给定以下输入值,计算圆周上的(x,y)点:

  • 半径
  • 角度
  • 原点(可选参数,如果语言支持)
6个回答

649

圆的参数方程是parametric equation for a circle

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

其中r是半径,cx,cy是原点,a是角度。

这个公式很容易用基本三角函数在任何编程语言中进行适应。 请注意,大多数编程语言在三角函数中使用弧度制,因此您需要在0..2PI弧度之间循环,而不是0..360度之间循环。


118
请注意,a 必须以弧度为单位 - 对于我这样的初学者来说,这真的很难理解。 - ioan
13
我已经努力推导这个方程一个小时了,谢谢。谁能想到你在高中学习的三角恒等式会如此有帮助。 - Isioma Nnodum
1
@Dean 不需要额外的括号,因为有运算符优先级。当你有 +* 像这两个方程式一样,并且没有任何括号时,你总是先选择 * 然后再选择 + - rbaleksandar
13
@IsiomaNnodum可能并没有提供太多帮助,因为我们都要回到这里来记住这个方程式是什么。 - arkon

56

我的 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);
}

6
使用硬编码数字预先计算转换系数,这样可以减少输错转换值的可能性。 - Scottie T

18

当你拥有复数时,谁还需要三角函数呢:

#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 ) );
}

这是如何工作的?在速度方面它如何比较?为什么它不被更广泛地使用? - Mark A. Ropper
@MarkA.Ropper 复数是如何工作的?-查找数学教程或从https://en.wikipedia.org/wiki/Euler%27s_identity开始,如果您已经知道什么是复数。与实现正弦作为查找表相比,它可能不太高效,但有时您使用复数来表示整个点以利用它们的其他属性。类似于使用四元数进行3D旋转,它并不是速度,而是它们给您带来的功能。 - Pete Kirkham

9

使用 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 ];

}

用法:

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>


2

根据移动的距离计算圆周上的点。
作为比较... 在直接路径中绕过实体物体时,这可能在游戏AI中很有用。

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}");
    }
}

0
int x = (int)(radius * Math.Cos(degree * Math.PI / 180F)) + cCenterX;
int y = (int)(radius * Math.Sin(degree * Math.PI / 180F)) + cCenterY;

cCenterXcCenterY是圆的中心点。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接