2个角度之间的最小差异

Tom*_*ell 127 language-agnostic geometry angle

给定坐标范围内的2个角度-PI - > PI,它们之间的两个角度中最小的值是多少?

考虑到PI和-PI之间的差异不是2 PI而是零.

例:

想象一个圆圈,从中心出来2条线,这些线之间有2个角度,它们在内部的角度就是较小的角度,以及它们在外部产生的角度,也就是更大的角度.加起来时两个角度都会形成一个完整的圆圈.假设每个角度都可以在一定范围内,那么考虑到翻转,角度值越小

ben*_*ich 175

这为任何角度提供了一个有角度的角度:

a = targetA - sourceA
a = (a + 180) % 360 - 180
Run Code Online (Sandbox Code Playgroud)

请注意,在许多语言中,modulo操作返回一个与被除数相同符号的值(如C,C++,C#,JavaScript,此处为完整列表).这需要一个自定义mod函数,如下所示:

mod = (a, n) -> a - floor(a/n) * n
Run Code Online (Sandbox Code Playgroud)

或者:

mod = (a, n) -> (a % n + n) % n
Run Code Online (Sandbox Code Playgroud)

如果角度在[-180,180]之内,这也有效:

a = targetA - sourceA
a += (a>180) ? -360 : (a<-180) ? 360 : 0
Run Code Online (Sandbox Code Playgroud)

以更冗长的方式:

a = targetA - sourceA
a -= 360 if a > 180
a += 360 if a < -180
Run Code Online (Sandbox Code Playgroud)

  • 虽然有人可能想要做一个 % 360,例如如果我有角度 0 和目标角度 721,正确答案是 1,上面给出的答案是 361 (2认同)
  • “任意角度的有符号角”示例似乎在大多数情况下都有效,只有一个例外。在场景`double targetA = 2; double sourceA = 359;` 'a' 将等于 -357.0 而不是 3.0 (2认同)
  • 在C ++中,您可以使用std :: fmod(a,360)或fmod(a,360)来使用浮点模。 (2认同)
  • 如果 `%` 运算符的作用类似于您语言中的余数(保留符号),您可以简单地添加一个额外的 360,而不是定义模函数: `a = (a + 540) % 360 - 180` 如上所述,这只适用于彼此 360 度以内的角度,这种情况可能经常发生。否则:`a = ((a % 360) + 540) % 360 - 180` (2认同)

Pet*_*r B 138

x是目标角度.y是来源或起始角度:

atan2(sin(x-y), cos(x-y))
Run Code Online (Sandbox Code Playgroud)

它返回有符号的delta角度.请注意,根据您的API,atan2()函数的参数顺序可能不同.

  • `xy`给出了角度的差异,但它可能超出了预期的范围.想想这个角度定义单位圆上的一个点.该点的坐标是`(cos(xy),sin(xy))`.`atan2`返回该点的角度(相当于`xy`),但其范围是[-PI,PI]. (11认同)
  • 这通过了测试套件https://gist.github.com/bradphelan/7fe21ad8ebfcb43696b8 (3认同)
  • 一线简单的解决方案,并为我解决(不是选定的答案;))。但是棕褐色逆过程是一个昂贵的过程。 (2认同)
  • 对我来说,最优雅的解决方案。可惜它可能在计算上昂贵。 (2认同)
  • 不幸的是,这也不像其他解决方案那么精确。 (2认同)

Lau*_*ves 35

如果你的两个角是x和y,那么它们之间的一个角是abs(x-y).另一个角度是(2*PI) - abs(x-y).所以2个角度中最小的角度的值是:

min((2 * PI) - abs(x - y), abs(x - y))
Run Code Online (Sandbox Code Playgroud)

这将为您提供角度的绝对值,并假设输入已标准化(即:在范围内[0, 2?)).

如果您想保留角度的符号(即:方向)并接受范围之外的角度,[0, 2?)您可以概括上述内容.这是通用版本的Python代码:

PI = math.pi
TAU = 2*PI
def smallestSignedAngleBetween(x, y):
    a = (x - y) % TAU
    b = (y - x) % TAU
    return -a if a < b else b
Run Code Online (Sandbox Code Playgroud)

请注意,%操作符在所有语言中的行为都不相同,尤其是涉及负值时,因此如果需要移植某些符号调整,则需要进行操作.

  • 请注意,从 Python 3 开始,您实际上可以本机使用 tau!只需写“from math import tau”即可。 (2认同)

Dav*_*nes 9

我接受提供签名答案的挑战:

def f(x,y):
  import math
  return min(y-x, y-x+2*math.pi, y-x-2*math.pi, key=abs)
Run Code Online (Sandbox Code Playgroud)

  • 但这一个不包含触发功能:) (4认同)

Adr*_* Jr 7

在 C++ 中适用于任何角度和两者的有效代码:弧度和度数是:

inline double getAbsoluteDiff2Angles(const double x, const double y, const double c)
{
    // c can be PI (for radians) or 180.0 (for degrees);
    return c - fabs(fmod(fabs(x - y), 2*c) - c);
}
Run Code Online (Sandbox Code Playgroud)

  • 好主意,但它不会产生有符号的角度。 (3认同)

小智 6

对于UnityEngine用户,简单的方法就是使用Mathf.DeltaAngle.

  • 没有带符号的输出 (2认同)

Rud*_*ing 5

Arithmetical(与算法相对)解决方案:

angle = Pi - abs(abs(a1 - a2) - Pi);
Run Code Online (Sandbox Code Playgroud)

  • 这使测试套件失败https://gist.github.com/bradphelan/7fe21ad8ebfcb43696b8 (3认同)