2016-01-30 52 views
4

以下枚舉定義:相對主方向

public enum Direction 
{ 
    North, 
    South, 
    East, 
    West, 
    Northeast, 
    Northwest, 
    Southeast, 
    Southwest, 
    Undefined 
} 

給定兩個座標集在兩維空間中,我想確定從點2的相對基本方向爲1。

實例:

  • P1(1,1)和P2(0,1)返回Direction.North爲P2是P1的
  • P1(1,1)和P2(5,4)返回北方向The n.Southeast
  • P1(1,1)和P2(1,1)返回Direction.Undefined

我目前的做法包括了一堆條件,即

if (P1.X == P2.X) 
{ 
    // either North, South or Undefined 
    if (P1.Y < P2.Y) 
     return Direction.South; 
    else if (P1.Y > P2.Y) 
     return Direction.North, 
    else 
     return Direction.Undefined; 
} 
else if (P1.Y == P2.Y) 
{ 
    ... 
} 
else 
{ 
    ... 
} 

我正在尋找一個更短,更優雅的解決方案。

+1

使用矢量的角度'P2 - P1'(使用'arctan2() '),然後做'if(-15°<= angle <= 15°)返回Direction.North'? (即在numDirections切片中分割整個事物,然後檢查角度是否在一個區間內)。我也不明白爲什麼如果'P1.X

+3

它是以標準笛卡爾座標定義的嗎?如果是這樣,那麼第一個樣本不應該是Direction.West,而第二個Direction.Northeast? – PiotrWolkowski

+1

@PiotrWolkowski顯然,OP沿着負X軸取向爲北,而不是通常的正Y軸。這很奇怪,但是「標準笛卡爾座標」中沒有任何規定北方的方向。 – RBarryYoung

回答

4

我3美分 - 我等待改進

這裏是枚舉:

public enum Direction 
{ 
    North = 0, 
    South = 4, 
    East = 6, 
    West = 2, 
    Northeast = 7, 
    Northwest = 1, 
    Southeast = 5, 
    Southwest = 3, 
    Undefined = -1 
} 

和轉換都按:

public static Direction GetDirection(Point p1, Point p2) { 
    double angle = Math.Atan2(p2.Y - p1.Y, p2.X - p1.X); 
    angle += Math.PI; 
    angle /= Math.PI/4; 
    int halfQuarter = Convert.ToInt32(angle); 
    halfQuarter %= 8; 
    return (Direction)halfQuarter; 
} 

不退還然而,因爲

如果y是0,x是0,θ= 0。

(從https://msdn.microsoft.com/library/system.math.atan2(v=vs.110).aspx

+0

對於'Direction.Undefined'位,你可以檢查'p1-p2'是否足夠接近零向量(通過定義一個小的epsilon,如果座標是浮點值,如果它們是整數,那麼可以直接檢查'p1-p2 ==(0,0)',否則很好的解決方案。 –

1

假設您有P1和P2,請使用轉換P -> P - P1將P1移動到2D空間的原點。

然後計算矢量(0,0) - P2'其中P2'是transformetd P2點(P2' = P2 - P1)和X軸之間的角度。

使用該角度來選擇方向(每個方向都有360/8角寬)。

角之間的兩個向量可以使用dot product

1

該解決方案將正確地返回您Direction.Undefined當座標不沿一個方向恰好指向來計算,它僅通過檢查角(消除嵌套的後續控制語句see unit circle)。請注意,我認爲點類型的XY屬性定義爲int,但即使將它們定義爲浮點類型值(例如float,decimal或double),也應該可以正常工作。

static Direction GetDirection(Point p1, Point p2) 
{ 
    double rad = Math.Atan2(p2.Y - p1.Y, p2.X - p1.X); 

    // Ajust result to be between 0 to 2*Pi 
    if (rad < 0) 
     rad = rad + (2 * Math.PI); 

    var deg = rad * (180/Math.PI); 

    if (deg == 0) 
     return Direction.East; 
    else if (deg == 45) 
     return Direction.Northeast; 
    else if (deg == 90) 
     return Direction.North; 
    else if (deg == 135) 
     return Direction.Northwest; 
    else if (deg == 180) 
     return Direction.West; 
    else if (deg == 225) 
     return Direction.Southwest; 
    else if (deg == 270) 
     return Direction.South; 
    else if (deg == 315) 
     return Direction.Southeast; 
    else 
     return Direction.Undefined; 
} 

一個簡單的測試......

Direction dir; 

dir = GetDirection(new Point(0, 0), new Point(1, 0)); 
Console.WriteLine(dir); 
dir = GetDirection(new Point(0, 0), new Point(1, 1)); 
Console.WriteLine(dir); 
dir = GetDirection(new Point(0, 0), new Point(0, 1)); 
Console.WriteLine(dir); 
dir = GetDirection(new Point(0, 0), new Point(-1, 1)); 
Console.WriteLine(dir); 
dir = GetDirection(new Point(0, 0), new Point(-1, 0)); 
Console.WriteLine(dir); 
dir = GetDirection(new Point(0, 0), new Point(-1, -1)); 
Console.WriteLine(dir); 
dir = GetDirection(new Point(0, 0), new Point(0, -1)); 
Console.WriteLine(dir); 
dir = GetDirection(new Point(0, 0), new Point(1, -1)); 
Console.WriteLine(dir); 

輸出...

East 
Northeast 
North 
Northwest 
West 
Southwest 
South 
Southeast 

注意,如果Point類型定義XY性質爲浮點類型,然後像以下將返回Direction.Undefined,因爲它不是完全指向東方,所以希望這適合您的意圖...

// "Almost" pointing east... 
dir = GetDirection(new Point(0, 0), new Point(1, 0.001)); 

輸出...

Undefined 
1

讓我們休息360上8個扇區的每個45度。 所以,我們需要的是找到其中8個部門的載體(P2 - P1)屬於:

static Direction GetDirection(Point start, Point end) 
{ 

    double dx = end.X - start.X; 
    double dy = end.Y - start.Y; 


    if (Math.Abs(dx) > Math.Abs(dy)) 
    { 
     if (Math.Abs(dy/dx) <= tan_Pi_div_8) 
     { 
      return dx > 0 ? Direction.East : Direction.West;  
     } 

     else if (dx > 0) 
     { 
      return dy > 0 ? Direction.Northeast : Direction.Southeast; 
     } 
     else 
     { 
      return dy > 0 ? Direction.Northwest : Direction.Southwest; 
     } 
    } 

    else if (Math.Abs(dy) > 0) 
    { 
     if (Math.Abs(dx/dy) <= tan_Pi_div_8) 
     { 
      return dy > 0 ? Direction.North : Direction.South; 
     } 
     else if (dy > 0) 
     { 
      return dx > 0 ? Direction.Northeast : Direction.Northwest; 
     } 
     else 
     { 
      return dx > 0 ? Direction.Southeast : Direction.Southwest; 
     } 
    } 
    else 
    { 
     return Direction.Undefined; 
    } 


} 

static readonly double tan_Pi_div_8= Math.Sqrt(2.0) - 1.0; 

Working sample