获取点与原点之间的角度

10

这个问题可能已经有人回答过了,如果是的话,请原谅。 我需要从原点到目标点得到角度。 例如,原点是(0, 0),我的目标点是(3, 0)

3点钟 = 90度

6点钟 = 180度

9点钟 = 270度

12点钟 = 0度


不知何故,我得进行一些数学计算,找出角度为90度(顶部为0)。 原点可能会变化,因此我需要一个具有两个参数Origin和TargetPoint的方法,返回度数双精度角度。

是的,我意识到这看起来很简短,没有建设性,但我尽可能地让问题简单易懂。所有其他问题都被关闭了-.-

谢谢


3
角度是指两条直线之间的夹角,而不是两个点之间的夹角,除非您在谈论相对于世界本身的某条线的角度?此外...这是为了完成作业吗? - LightStriker
不,我需要原点和一个点之间的角度。可以把它想象成一个时钟,3点钟是关于原点(中心)90度。不,我正在开发一个游戏。 - Dave
5
为什么人们很难理解这个问题呢?当然,从技术上讲,两点之间是没有角度的,但为什么很多程序员不知道这一点却很难理解呢?他们只知道0度是向上的,并需要找到一个角度使一个精灵指向另一个精灵。大多数提出这个问题的程序员只是缺乏数学背景,无法理解需要三个点(或者如果你喜欢,可以说是两条线)才能得出一个角度的概念。[/抱怨] - Clonkex
@Clonkex; 我同意。这也是一种速记方式。当我在寻找“一个点的角度”时,我可以说得更明确一些,比如“我想找到两个点所在的直线与代表零度的x轴之间的角度,其中一个点是虚拟原点,另一个点是待求的变量点”,但我认为可以假设问题的意思,特别是因为作为程序员,你只能从两个点开始工作,而不是一条直线。 - Georgina Davenport
5个回答

20

两点A和B之间的向量为B-A = (B.x-A.x,B.y-A.y)。两个向量之间的角度可以通过点积atan2函数计算。

var vector2 = Target - Origin;
var vector1 = new Point(0, 1) // 12 o'clock == 0°, assuming that y goes from bottom to top

double angleInRadians = Math.Atan2(vector2.Y, vector2.X) - Math.Atan2(vector1.Y, vector1.X);

也可以参考查找向量之间的有向角度


1
那么:Math.Atan2(Origin.Y - Target.Y, Origin.X - Target.X);?这是弧度制,对吗? - Dave
@user2544245:你需要两个向量。第二个向量指向你想要表示0°的方向。顺时针方向,是的。不过你的公式是错误的。 - Sebastian Negraszus
在你的公式中,原点和目标点的位置是否有关系? - Dave
另外,我如何使用弧度角和长度从原点获取一个。或者,我应该为此提出一个新问题吗? - Dave
@user2544245:x = 长度cos(角度); y = 长度sin(角度) - Sebastian Negraszus
显示剩余2条评论

4
假设 x 是正数,可以这样写:
angle = Math.Atan(y / x) * 180 / Math.PI + 90

编辑以允许负数x值:

如果它可以是负数,只需通过情况来处理。像这样:

if (x < 0) {
    angle = 270 - (Math.Atan(y / -x) * 180 / Math.PI);
} else {
    angle = 90 + (Math.Atan(y / x) * 180 / Math.PI);
}

X和Y可以是正数或负数。 - Dave

0

实际上,由于原点是(0,0),所以没有办法找出点和原点之间的角度。我们可以计算两个点之间的角度,因为它们被视为向量,因此它们具有方向,但原点没有方向。因此,如果您想使用时钟的示例来查找角度,您可以计算该点与(1,0)之间的角度,例如该点为0度。

很抱歉我不熟悉C#,但您可以查看这个类似的Java代码:

double getAngle2PointsRad(double p1_x, double p1_y, double p2_x, double p2_y) {
  return Math.acos((((p1_x * p2_x) + (p1_y * p2_y)) / (Math.sqrt(Math.pow(p1_x, 2) + Math.pow(p1_y, 2)) * Math.sqrt(Math.pow(p2_x, 2) + Math.pow(p2_y, 2)))));
}

double getAngle2PointsDeg(double p1_x, double p1_y, double p2_x, double p2_y) {
  return Math.acos((((p1_x * p2_x) + (p1_y * p2_y)) / (Math.sqrt(Math.pow(p1_x, 2) + Math.pow(p1_y, 2)) * Math.sqrt(Math.pow(p2_x, 2) + Math.pow(p2_y, 2))))) * 180 / Math.PI;
}

如果你尝试使用(0,0)进行计算,你会得到NaN,因为它试图除以零。


0
对于任何仍然查看此帖子的人(对我来说,它在谷歌排名靠前),我使用了Sebastian的Atan2解决方案,并且效果非常好。在我的情况下,我正在Unity中以编程方式生成参数化基元,因此原点始终为(0,0,0),无论基元是2D还是3D(为了Mesh顶点)。因此,对于一个球体,我需要以特定的方式对所有顶点进行排序,以便无论参数如何,都可以正确地构建int []以用于网格所需的三角形。

我的排序使用:

this.vertices = vertList.OrderByDescending(o => o.y)
                        .ThenBy(o => Utilities.GetAngle(o)).ToArray();

GetAngle() 方法看起来像这样:

public static float GetAngle(Vector3 v)
{
    return Mathf.Atan2(0, 0) - Mathf.Atan2(v.z, v.x);
}

将顶点列表从上到下排序(因此1个单位的球体在(0f,0.5f,0f)处有一个“顶部”点,并且那将是第一个顶点),然后按沿X和Z平面的角度计算结果浮点数排序。这种排序对于 Linq 来说非常有效并且出奇地快。

另外需要注意的一点是:由于它忽略了Y平面,因此每个顶点层/级别/带在Y轴上的不同点无关紧要 - 它基本上将每个顶点都计算为如果它们只在y = 0处。如果您想在X/Y或Y/Z上进行排序,则可以做相同的事情,只需省略要忽略的平面即可。

这在更复杂的情况下可能不起作用,或者当您的原点不是(0,0,0)时,但至少对于我的情况而言是有效的。


0
public static double GetAngleDegree(Point origin, Point target) {
    var n = 270 - (Math.Atan2(origin.Y - target.Y, origin.X - target.X)) * 180 / Math.PI;
    return n % 360;
}

static void Main(string[] args)
{
    Console.WriteLine(GetAngleDegree(new Point(0, 0), new Point(0, 3)));//0
    Console.WriteLine(GetAngleDegree(new Point(0, 0), new Point(3, 0)));//90
    Console.WriteLine(GetAngleDegree(new Point(0, 0), new Point(0, -3)));//180
    Console.WriteLine(GetAngleDegree(new Point(0, 0), new Point(-3, 0)));//270 
}

1
这看起来像是逆时针旋转,**(0, 3)** 是0度。 - Dave

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