2014-01-06 103 views
4

如果我有兩個點p1和p2,其中p1是樞軸點,p2是用戶前進的原始方向,並且它們有多個可能的方向以隨機順序前進到p3 ... pn。我如何獲得選擇和由p1,p2形成的片段之間的角度作爲順時針(右手)0至360之間的正值,以便我可以將它們從最小到最大排序?2D中的順時針旋轉角度?

此外,點p1 ... pn將在任何象限中,我不能假設它們將始終處於正x,y方向。網格是一個標準的笛卡爾網格而不是屏幕座標,因此當你下降不大時,Y會變小。

在這個例子中

所以(對不起,窮人圖紙,但塗料是所有我對我的筆記本電腦),我需要的角度:

Grid showing the points and angles

(P2-P1- P3) (P2-P1-P4) (P2-P1-P5) (P2-P1-P6)

在這個順序(最小的右手轉大右轉): [(P2-P1-P4),(P2-P1-P6),(P2-P1-P5),(P2-P1-P3)]

在我的情況的點是一個所謂的頂點類:

public class Vertex 
{ 
    public double X = 0; 
    public double Y = 0; 
    public Vertex() { } 
    public Vertex(double x, double y) 
    { 
     X = x; 
     Y = y; 
    } 
} 

併爲獲取角度,現在的排序看起來像這樣的權利,但代碼中有一個問題:

private static IEnumerable<Vertex> SortByAngle(Vertex original, Vertex pivot, List<Vertex> choices) 
    { 
     choices.Sort((v1, v2) => GetTurnAngle(original, pivot, v1).CompareTo(GetTurnAngle(original, pivot, v2))); 
     return choices; 
    } 

    private static double GetTurnAngle(Vertex original, Vertex pivot, Vertex choice) 
    { 
     var a = original.X - pivot.X; 
     var b = original.Y - pivot.Y; 
     var c = choice.X - pivot.X; 
     var d = choice.Y - pivot.Y; 

     var rads = Math.Acos(((a * c) + (b * d))/((Math.Sqrt(a * a + b * b)) * (Math.Sqrt(c * c + d * d)))); 

     return (180/Math.PI * rads); 

    } 

的問題是上面的是,如果我檢查了:原來 66,-66 支點280,-191 選擇200,-180

我得到的角度是22.460643124,而不是337.539356876,這意味着它從原來的方向逆時針旋轉得到那個角度。我需要它總是順時針旋轉來獲得角度。

我在做什麼錯,我該如何解決?

更新:行,所以根據在說什麼你們我大概可以使用一些跨產品如數學來確定CW VS CCW因此新的方法是這樣的:

private static double GetTurnAngle(Vertex original, Vertex pivot, Vertex choice) 
    { 
     var a = original.X - pivot.X; 
     var b = original.Y - pivot.Y; 
     var c = choice.X - pivot.X; 
     var d = choice.Y - pivot.Y; 


     var angle = Math.Acos(((a * c) + (b * d))/((Math.Sqrt(a * a + b * b)) * (Math.Sqrt(c * c + d * d)))); 
     angle = (180/Math.PI * angle); 


     var z = (choice.X - pivot.X) * (original.Y - pivot.Y) - (choice.Y - pivot.Y) * (original.X - pivot.X); 
     if (z < 0) 
     { 
      return 360 - angle; 
     } 
     return angle; 

    } 

更新2:

使用接受的解決方案,現在看起來像這樣:

private static double GetTurnAngle(Vertex original, Vertex pivot, Vertex choice) 
    { 

     var angle1 = Math.Atan2(original.Y - pivot.Y, original.X - pivot.X); 
     var angle2 = Math.Atan2(choice.Y - pivot.Y, choice.X - pivot.X); 
     var angleDiff = (180/Math.PI * (angle2 - angle1)); 

     if (angleDiff > 0)//It went CCW so adjust 
     { 
      return 360 - angleDiff; 
     } 
     return -angleDiff;//I need the results to be always positive so flip sign 

    } 

到目前爲止,我可以告訴大家,偉大的工程至今。謝謝你們的幫助!

+0

p2是點還是方向(例如矢量)?第一句話沒有定論。 – kkuilla

+0

實際的差異角度是22度,而不是337.您將需要使用360 - 如果您希望從360開始而不是0開始,則需要使用360結果。 – KSdev

+0

看起來您只能在某處加上/減號 - 您有嗎?嘗試通過排列「a」到「d」的排列來循環嘗試?我意識到理想的解決方案是要知道爲什麼數學是錯誤的,但如果它的工作... – norlesh

回答

2

看看atan2 function。它需要德爾塔y和德爾塔x,因此可以區分所有角度。

angle1 = atan2(p1.y-p0.y, p1.x-p0.x); 
angle2 = atan2(p2.y-p0.y, p2.x-p0.x); 
angle = angle2 - angle1; 

如果角度爲負值,則CW,如果CCW爲正值(或其他方式取決於您的軸方向)。注意|angle|可能是> 180,在這種情況下,如果您在最短路線之後,您可能需要執行360-|angle|並反轉CW CCW結論。

+0

請確保你記住'atan2'的結果是(-180,180),所以如果你想要360,你將不得不調整(-180,0)以適合(180,360) – KSdev

+0

@varocarbas atan2給出所有角度,因此你可以使用它爲CW/CCW – weston

+1

@varocarbas我舉了一個例子。我不同意你不知道atan2提供給你的角度。它總是CW或CCW(取決於你的軸方向),但它從來都不是。關鍵是你給了兩個**兩個論點,而不是一個比例。 – weston