在具有给定中心点,半径和度数的圆上找到点


82

自从我做这样的数学运算已经有10年了……我正在用2D编程游戏并移动一名玩家。当我四处移动播放器时,我正在尝试在-360至360之间的正或负角度(度)下,计算距播放器位置200像素的圆上的点。屏幕为1280x720,0,0为中心点屏幕的 玩家在整个笛卡尔坐标系中移动。我试图找到的要点可能不在屏幕上。

我尝试了文章“找到具有半径和角度的点”中的公式,但是我不相信我理解什么是“角度”,因为当我将-360到360的角度传递给Cos(angle)或Sin时,我得到了奇怪的结果(角度)。

例如,我有...

  • 笛卡尔平面上的1280x720
  • 中心点(玩家位置):
    • 令x =最小值-640到最大值640之间的数字
    • 令y =最小值-360到最大值360之间的数字
  • 玩家周围的圆半径:令r始终= 200
  • 角度:让a = -360到360之间的一个数字(允许负号指向下方或正号指向上方,因此-10和350将给出相同的答案)

在圆上返回X的公式是什么?

在圆上返回Y的公式是什么?

在此处输入图片说明 在此处输入图片说明


16
这是一个很好的问题!!!+1
FrostyFire

1
问题:不是大多数游戏的左上角都有0,0的坐标吗?y轴下降而不是上升?
Persijn

Answers:


73

来自链接的简单方程式给出了圆上的点相对于圆心的X和Y坐标。

X = r * cosine(angle)  
Y = r * sine(angle)

这告诉您该点距圆心的偏移量。由于您具有中心坐标(Cx,Cy),因此只需添加计算出的偏移量即可。

圆上的点的坐标为:

X = Cx + (r * cosine(angle))  
Y = Cy + (r * sine(angle))

1
我的困惑首先是角度和角度的区别。我以为他们是同一回事。然后我以为我在平面上得到了点(x,y),但实际上是在获得x和y边的长度。我将其画在纸上,然后以Excel格式放入,以覆盖度数范围以检查公式。现在可以在我的代码中使用了。
凯尔·安德森

3
X = xcircle + (r * sine(angle))应该X = xcircle + (r * cosine(angle))(反之亦然Y)吗?
txtechhelp

4
注意,角度应为弧度值!
罗曼M

17

您应该发布您正在使用的代码。这将有助于准确地确定问题。

但是,由于提到以-360到360来测量角度,因此您的数学库可能使用了错误的单位。三角函数的大多数实现都使用弧度作为输入。如果您改用度数,那么...您的答案将是错误的。

x_oncircle = x_origin + 200 * cos (degrees * pi / 180)
y_oncircle = y_origin + 200 * sin (degrees * pi / 180)

请注意,您可能还会遇到象限不是您所期望的情况。可以通过仔细选择角度零的位置或手动检查期望的象限并将自己的符号应用于结果值来解决此问题。


1
这实际上应该是评论而不是答案。但是,弧度与度的关系很好。
yoozer8

僵尸帖子问题:以原谅,是(deg * (pi / 180))那样((deg * pi) / 180)吗?也感谢您指定rad与deg之间的差异。
monsto

@monsto僵尸仍会发送通知。:)。内部乘数没有关系,因为乘法和除法是可交换的演示。wolfram.com/…。我对在代码中添加过多的括号感到内。我假装是为了清楚起见,但显然这并不是严格意义上的,否则您不会被它打扰。
塞斯·巴丁

6

我强烈建议将矩阵用于这种类型的操作。这是最通用的方法,请参见下面的示例:

// The center point of rotation
var centerPoint = new Point(0, 0);
// Factory method creating the matrix                                        
var matrix = new RotateTransform(angleInDegrees, centerPoint.X, centerPoint.Y).Value;
// The point to rotate
var point = new Point(100, 0);
// Applying the transform that results in a rotated point                                      
Point rotated = Point.Multiply(point, matrix); 
  • 旁注,惯例是逆时针测量角度起始形式(正)X轴

5

当我将-360到360度的角度传递给Cos(角度)或Sin(角度)时,我得到的结果很奇怪。

我认为您的尝试失败的原因是您传递的角度为度。在sincos三角函数预计弧度表示的角度,所以这些数字应该是从02*M_PI。对于d学位,您会通过M_PI*d/180.0M_PI是在math.h标头中定义的常量。


我认为角度和度数可能不是同一件事,所以我正确地说:Angle = M_PI * d / 180.0,其中d可以是-360到360之间的数字,还是我需要其他步骤?
凯尔·安德森

1
@Kyled是从0360或从-180180(一个完整的圆圈),而不是从-360360(两个完整的圆圈)。
谢尔盖·卡利尼琴科

4

我还需要用它来形成代码中的时钟指针的运动。我尝试了几个公式,但是它们没有用,所以这是我想出的:

  • 运动-顺时针
  • 点-每6度(因为360度除以60分钟是6度)
  • 手长-65像素
  • 中心-x = 75,y = 75

所以公式是

x=Cx+(r*cos(d/(180/PI))
y=Cy+(r*sin(d/(180/PI))

其中x和y是圆的圆周上的点,Cx和Cy是中心的x,y坐标,r是半径,d是度数。


2

这是c#实现。该方法将返回圆形点这需要radiuscenterangle interval作为参数。角度作为弧度传递。

public static List<PointF> getCircularPoints(double radius, PointF center, double angleInterval)
        {
            List<PointF> points = new List<PointF>();

            for (double interval = angleInterval; interval < 2 * Math.PI; interval += angleInterval)
            {
                double X = center.X + (radius * Math.Cos(interval));
                double Y = center.Y + (radius * Math.Sin(interval));

                points.Add(new PointF((float)X, (float)Y));
            }

            return points;
        }

和调用示例:

List<PointF> LEPoints = getCircularPoints(10.0f, new PointF(100.0f, 100.0f), Math.PI / 6.0f);

请注意,由于舍入错误,这可能比预期少返回1个项目!因此,我添加了一些技巧,以便最终获得正确数量的项目(我的示例中的浮动对象是double而不是float);为(浮动间隔= angleInterval;间隔<2 * Math.PI + 0.0000099f;区间+ = angleInterval)
sommmen

1

我想分享您的上述贡献如何帮助我制作了Arduino LCD指南针。我希望这是正确的礼节...我刚刚加入了stackoverflow,所以我要谢谢大家。

站在上面的几何巨人的肩膀上,我能够制作出这个示例指南针: 带有多个轴承的Arduino TFT指南针

我反复调用的函数的代码(对于不同的方位,您会看到黄色的细小文本)是用Arduino(有点像“ C”)编写的,并且很容易翻译:

void PaintCompassNeedle( int pBearingInDegrees, int pRadius, TSPoint pCentrePt ) {
    // ******************************************************************************
    // * Formula for finding pointX on the circle based on degrees around the circle:
    // * x_oncircle = x_origin + radius * cos (degrees * pi / 180)  
    // * y_oncircle = y_origin - radius * sin (degrees * pi / 180) //minus explained
    // * Thanks to folks at stackoverflow...standing on the shoulders of giants. :) 

    float bearingInRads = (pBearingInDegrees) * PI / 180; 
    // Degrees vs Rads...The math folks use Rads in their formulas

    // *******************************************************************
    // * bearingPt is the point on the circle that we are trying to find
    TSPoint bearingPt;
    // Find the X on the circle starting with orgin (centre)
    bearingPt.x = pCentrePt.x + pRadius * sin(bearingInRads); 
    // Notice the "minus" R * cos()...because TFT the y is upside down bearingPt.y = 
    pCentrePt.y - pRadius * cos(bearingInRads); 
    // * Extra Explanation: The TFT is the graphical display I'm using and it
    // * calculates x & y from the top left of screen (portrait mode) as (0,0)
    // * ...so by Subtracting from the Y orgin...I flip it vertically
    // * Other folks using x,y as increasing to the right and up respectively
    // * would keep the plus sign after the pCentrePt.y
    // *************************************************************************

    // ***************************************************************
    // * This part will change for the final product...but leaving
    // * it because when call numerous times it shows it working for
    // * a number of different quadrants (displaying yellow degrees text)
    tft.fillCircle( bearingPt.x, bearingPt.y, 5, RED); 
    tft.setCursor( bearingPt.x, bearingPt.y );
    tft.setTextSize( 1 );
    tft.setTextColor( YELLOW );
    tft.print( pBearingInDegrees );

    TSPoint innerPt;
    innerPt.x = pCentrePt.x + pRadius/2 * sin(bearingInRads);
    innerPt.y = pCentrePt.y - pRadius/2 * cos(bearingInRads);
    tft.drawLine(innerPt.x, innerPt.y, bearingPt.x, bearingPt.y, RED);

}


0

推荐:

 public static Vector3 RotatePointAroundPivot(Vector3 point, Vector3 
pivot, Vector3 angles)
    {
	    return Quaternion.Euler(angles) * (point - pivot) + pivot;
    }


-3

您可以使用此:

圆方程

(xk)2 +(yv)2 = R 2

其中k和v为常数,R为半径

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.