2009-12-10 118 views
96

給定圍繞座標的-PI-> PI範圍內的2個角度,它們之間的2個角度中的最小值是多少?2角之間的最小差異

考慮到PI和-PI之間的差異不是2PI,而是零。

實施例:

想象一個圓圈,用2線從中心出來,還有那些線之間的2個角度,它們使在裏面又名較小角度的角度,和所述角度他們在外面製造,又名大角度。兩個角度加起來形成一個完整的圓。假設每個角度都可以在一定範圍內,角度值越小,考慮到翻轉

+2

在我明白你的意思之前,我讀了3次。請添加一個例子,或者更好地解釋... – Kobi 2009-12-10 06:12:04

+0

想象一個圓,從中心向外劃出兩條線,這兩條線之間有兩個角度,它們在內部形成的角度又稱爲較小的角度,以及它們形成的角度在外面,也就是更大的角度。兩個角度加起來形成一個完整的圓。考慮到每個角度都可以在一定的範圍內,考慮到翻轉,角度值越小越好 – 2009-12-10 06:14:32

+0

[如何計算直線與橫軸之間的角度?](https://stackoverflow.com/questions/7586063/how-to-calculation-the-angle-between-a-line-and-the-horizo​​ntal-axis) – 2017-07-09 20:33:49

回答

135

這使任何角度簽署的角度:

a = targetA - sourceA 
a = (a + 180) % 360 - 180 

當心在許多語言中modulo操作返回的值與與紅利相同的符號(如C,C++,C#,JavaScript,full list here)。這需要一個定製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 
+0

更簡單,更有意義的朗讀,儘管實際上是同樣的東西,第一個bti計算出角度,第二個部分確保它始終是2個可能角度中較小的一個 – 2011-10-25 11:48:29

+1

,儘管人們可能想要做一個%360,例如。如果我有角度0和目標角度721,正確的答案將是1,上面給出的答案將是361 – 2011-10-25 11:51:56

+0

是的,這是真實的和有意的,但絕對值得指出。在我的例子中,我先前從'atan2'得到了'targetA'和'sourceA',因此它們的絕對角度決不會大於360. – bennedich 2011-10-26 01:31:56

30

如果你的兩個角度是x和y,那麼它們之間的角度之一是abs(x - Y)。另一個角度是(2 * PI) - abs(x - y)。這樣的最小的2角的值是:

min((2 * PI) - abs(x - y), abs(x - y)) 

這給你的角度的絕對值,它假定輸入是歸一化(即:範圍[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 

注意,%運營商不具有相同的行爲在所有的語言,特別是當負值都參與其中,所以如果移植一些跡象的調整可能是必要的。

+0

測試套件失敗https://gist.github.com/bradphelan/7fe21ad8ebfcb43696b8 – bradgonesurfing 2015-07-13 08:45:19

+1

@bradgonesurfing這是/是真的,但公平地說,你的測試檢查了東西原始問題中沒有指定,特別是非標準化的輸入和標誌保存。編輯答案中的第二個版本應該通過您的測試。 – 2015-07-23 19:20:31

105

x是目標角度。 y是源或起始角度:

atan2(sin(x-y), cos(x-y)) 

它返回帶符號的增量角度。請注意,根據您的API,atan2()函數的參數順序可能不同。

+3

這個工程。爲什麼? – ericsoco 2013-05-11 18:25:52

+8

'x-y'給你角度的不同,但它可能超出了期望的範圍。想想這個角度定義單位圓上的一個點。該點的座標是'(cos(x-y),sin(x-y))'。 'atan2'返回該點的角度(相當於'x-y'),除了它的範圍是[-PI,PI]。 – Max 2013-09-02 16:17:55

+1

這通過測試套件https://gist.github.com/bradphelan/7fe21ad8ebfcb43696b8 – bradgonesurfing 2015-07-13 08:43:09

7

我升到提供簽名回答的挑戰:

def f(x,y): 
    import math 
    return min(y-x, y-x+2*math.pi, y-x-2*math.pi, key=abs) 
+1

啊...答案是順便說一句Python函數。對不起,我暫時處於Python模式。希望沒關係。 – 2010-01-05 16:20:46

+0

我會在樓上的代碼中插入新的公式,看看會發生什麼!(thankyou^_ ^) – 2010-01-05 17:25:42

+1

我很確定PeterB的回答也是正確的。和evilly hackish。 :) – 2010-01-05 18:04:17

5

Ari (與算法相反)解決方案:

angle = Pi - abs(abs(a1 - a2) - Pi); 
+0

測試套件失敗https://gist.github.com/bradphelan/7fe21ad8ebfcb43696b8 – bradgonesurfing 2015-07-13 08:39:58

2

沒有必要計算三角函數。在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 

沒有罪,沒有COS,沒有棕褐色,....只有幾何!

+4

錯誤!由於您將PIV2定義爲「M_PI + M_PI」 ,而不是「(M_PI + M_PI)「,行'arg = arg - PIV2;'擴展爲'arg = arg - M_PI + M_PI',所以什麼都不做。 – canton7 2014-01-19 11:53:03