尝试计算两个角度之间的差异(atan2)

4

Atan2(y,x)会返回一个介于 -pi 和 pi 之间的浮点数。我想计算两个角度之间的距离,但非连续性使我感到困扰。

查看此处以更好地理解。

我希望能够计算角度1和角度2之间的距离。

整个目的是为了能够从中心创建一个锥形到指定角度。实际上,我将进行评估:

if(DistanceFromAngle1 < pi/4 [45°])
{
  Angle2 is part of cone
}

1
从左上象限逆时针旋转到左下象限时,如何在不穿过0的情况下从正数跳到负数。(但是顺时针旋转会经过负数、0、正数。) - ATD
啊,我明白了。如果你先转换成度数,这将是一个简单的计算。 - Sam Axe
你的意思是指连接两个截距点的直线距离吗? - António Almeida
1
@Dan-o 如果用角度表示会更简单吗?你仍然会得到从-179跳到180/-180,从179跳到...或者从359,360/0,1跳转的情况。 - ATD
@ToniAlmeida - 我的意思是两个角度之间的最小角度。因此,Angle1 = -3pi/4 和 Angle2 = 3pi/4 之间的旋转差应该是 pi/2,而不是 3pi/2。 - ATD
@ATD:请看下面我的回答。 - Sam Axe
6个回答

7
如果你所说的距离是指两个拦截点之间的直线距离,你可以通过以下方法计算距离:
SQRT( ( ABS|cos(A) - cos(B)| )^2 + ( ABS|sin(A) - sin(B)| )^2 )

SQRT = 平方根

ABS = 绝对值

如果距离是角度,则可以通过以下伪代码进行计算:

var angle = ABS(A - B)
if(angle > pi) angle = 2*pi - angle
return angle

5
dAngle1 = //convert angle1 to degrees
dAngle2 = // convert to degrees

delta = Math.Max(dAngle1, dAngle2) - Math.Min(dAngle1, dAngle2)
if (180 < delta) {
  delta = 360 - delta;
}

// convert delta to radians if you want

左侧:0 | 顶部:90 | 右侧:180 | 底部:270。假设你的圆是这样的...如果Angle1 = 45且Angle2 = 315,则delta = 90(正确)。然而,如果Angle1 = 0且Angle2 = 225,则delta = 45(不正确)。0和225之间的距离与(360-225)相同,应为135。接近,但不完全正确。 - ATD
我大约在你发表评论的时候编辑了我的答案。我相信这次修改是正确的。 - Sam Axe
好的,现在可以运行了。另外,顺便提一下,您可以使用Math.abs(dAngle1 - dAngle2)而不是max/min方法。 - ATD

1

π/2是90°,而不是45°。我假设您想知道角度2是否在以角度1为中心,并向两个方向延伸45°的区间内。

您可以计算角度2和角度1之间的差值,并对2π取模,直到差值在[-π,π)范围内。这将给出角度2和角度1之间的有符号距离。然后,检查它是否在(-π/4,π/4)范围内。由于atan2返回的值始终在-π和π之间,原始差异将始终在-2π和2π之间,因此您可以将所有这些内容合并为一个检查:

 if (angle2 - angle1 < -7π/4 || 
     (angle2 - angle1 > -π/4 && angle2 - angle1 < π/4) ||
     angle2 - angle1 > 7π/4)
 {
   angle2 is less than 45° away from angle1
 }

1

角度差计算的两种变体:

procedure TForm1.sButton1Click(Sender: TObject);
Var a, b, dif : Extended;
begin
  a := sCalcEdit1.Value;
  b := sCalcEdit2.Value;
  If ((a < 180) and (b >= 180) or
      (a >= 180) and (b < 180)) and (abs(a - b) < 180)  then
  Begin
  End else
  If (a < 180) and (b >= 180) then
  Begin
    b := b - 360;
  End else
  If ((a >= 180) and (b < 180)) then
  Begin
    a := a - 360;
  End;
  dif := abs(a - b);
  sCalcEdit3.Value := dif;
end;

procedure TForm1.sButton2Click(Sender: TObject);
Var a, b, dif : Extended;
begin
  a := sCalcEdit1.Value * pi / 180;
  b := sCalcEdit2.Value * pi / 180;
  dif := arccos(cos(a - b));
  sCalcEdit3.Value := dif * 180 / pi;
end;

0

编辑:我不确定这会不会起作用。我从一些python代码中翻译过来,但我不确定divmod(radians, math.pi*2)[1]是否与System.Math.IEEERemainder(radians, Math.PI*2.0)具有相同的行为。需要测试...

编辑2:我认为使用%是正确的

编辑3:糟糕,它对于负数返回负值。有没有人知道如何在C#中获得python divmod?

如何计算两个角度之间的角度:

public static double NormalizeAngle(double radians)
{
 return fmod(radians,Math.PI*2.0); # this method doesn't exist, see above
}

public static double ArcLength(double radians1, double radians2)
{
 radians1 = NormalizeAngle(radians1);
 radians2 = NormalizeAngle(radians2);
 return Math.Min(NormalizeAngle(radians1 - radians2, NormalizeAngle(radians2 - radians1));
}

它的工作原理是尝试两种方式,所有计算模2pi,并选择距离较小的那个。

0

我想提供一种替代方案:您可以使用向量数学。例如,如果您有两个向量作为起点(这似乎是您的情况),则可以使用它。

给定两个标准化向量ab,它们之间的角度变为acos(dot(a, b)) = acos(ax*bx + ay*by)

要从角度alpha获得标准化向量,可以使用a = vec2(cos(alpha), sin(alpha)),例如。

要规范化非规范化向量,请使用na = a / length(a) = a / sqrt(dot(a, a))


什么是“点”?这在C#中吗? - ATD
点积是两个向量之间的点积:dot(a, b) = ax*bx + ay*by,其中 a = (ax, ay)b = (bx, by) - rasmus
啊,好的。我找到了。谢谢! - ATD

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