给定一个二维圆,在 -PI-> PI的范围内有两个角,它们之间的最小角度值是多少?
-PI
PI
考虑到 PI 和-PI 之间的差别不是2 PI 而是0。
举个例子:
想象一个圆,有两条线从中心出来,这两条线之间有两个角度,它们在内部的角度,也就是 较小的角度,和它们在外部的角度,也就是更大的角度。
两个角度加起来是一个完整的圆。假设每个角度都能在一定范围内适合,考虑到翻转,较小的角度值是多少
如果你的两个角是 x 和 y,那么它们之间的一个角是 abs (x-y)。另一个角是(2 * PI)-abs (x-y)。所以这两个角中最小的值是:
min((2 * PI) - abs(x - y), abs(x - y))
这将给出角度的绝对值,并假设输入已经规范化(即: 在 [0, 2π)范围内)。
[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
请注意,%操作符在所有语言中的行为并不相同,特别是当涉及到负值时,因此如果移植一些符号调整可能是必要的。
%
X 是目标角,y 是源角或起始角:
atan2(sin(x-y), cos(x-y))
它返回带符号的 delta 角度。注意,根据 API 的不同,atan2()函数的参数顺序可能不同。
我勇敢地接受挑战,提供一个经过签名的答案:
def f(x,y): import math return min(y-x, y-x+2*math.pi, y-x-2*math.pi, key=abs)
这给出了任意角度的符号角度:
a = targetA - sourceA a = (a + 180) % 360 - 180
注意,在许多语言中,modulo操作返回一个与红利符号相同的值(如 C、 C + + 、 C # 、 JavaScript、 完整的清单在这里)。这需要像下面这样的自定义 mod函数:
modulo
mod
mod = (a, n) -> a - floor(a/n) * n
大概是这样:
mod = (a, n) -> (a % n + n) % n
如果角度在[ -180,180]之内,这个方法也有效:
a = targetA - sourceA a += (a>180) ? -360 : (a<-180) ? 360 : 0
更详细地说:
a = targetA - sourceA a -= 360 if a > 180 a += 360 if a < -180
算术(相对于算法)解决方案:
angle = Pi - abs(abs(a1 - a2) - Pi);
不需要计算三角函数,用 C 语言编写的简单代码是:
#include <math.h> #define PIV2 M_PI+M_PI #define C360 360.0000000000000000000 double difangrad(double x, double y) { double arg; arg = fmod(y-x, PIV2); if (arg < 0 ) arg = arg + PIV2; if (arg > M_PI) arg = arg - PIV2; return (-arg); } double difangdeg(double x, double y) { double arg; arg = fmod(y-x, C360); if (arg < 0 ) arg = arg + C360; if (arg > 180) arg = arg - C360; return (-arg); }
让 dif = a-b,以弧度表示
dif = difangrad(a,b);
让 dif = a-b,以度为单位
dif = difangdeg(a,b); difangdeg(180.000000 , -180.000000) = 0.000000 difangdeg(-180.000000 , 180.000000) = -0.000000 difangdeg(359.000000 , 1.000000) = -2.000000 difangdeg(1.000000 , 359.000000) = 2.000000
没有罪恶,没有因为,没有晒黑,... ... 只有几何! ! !
对于 UnityEngine 用户,简单的方法就是使用 Mathf 三角形。
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); }
在这里可以看到: Https://www.desmos.com/calculator/sbgxyfchjr
符号角度: return fmod(fabs(x - y) + c, 2*c) - c;
return fmod(fabs(x - y) + c, 2*c) - c;
在其他一些负数的 mod 为正的编程语言中,可以消除内部的 abs。
我在 C + + 中使用的一个简单方法是:
double deltaOrientation = angle1 - angle2; double delta = remainder(deltaOrientation, 2*M_PI);
我非常喜欢 彼得 · B上面的答案,但是如果你需要一个非常简单的方法来产生相同的结果,这里是:
function absAngle(a) { // this yields correct counter-clock-wise numbers, like 350deg for -370 return (360 + (a % 360)) % 360; } function angleDelta(a, b) { // https://gamedev.stackexchange.com/a/4472 let delta = Math.abs(absAngle(a) - absAngle(b)); let sign = absAngle(a) > absAngle(b) || delta >= 180 ? -1 : 1; return (180 - Math.abs(delta - 180)) * sign; } // sample output for (let angle = -370; angle <= 370; angle+=20) { let testAngle = 10; console.log(testAngle, "->", angle, "=", angleDelta(testAngle, angle)); }
需要注意的一点是,我故意翻转了这个符号: 逆时针方向的三角形是负的,而顺时针方向的三角形是正的