两个坐标的相对基数方向

以下枚举定义如下:

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)返回Direction.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.North, else return Direction.Undefined; } else if (P1.Y == P2.Y) { ... } else { ... } 

我正在寻求更短,更优雅的解决方案。

我的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; } 

它不会返回Direction.Undefined ,因为

如果y为0且x为0,则θ= 0。

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

假设您有P1和P2,使用变换P -> P - P1将P1移动到2D空间的原点。

然后计算矢量(0,0) - P2'之间的角度,其中P2'是变换P2点( P2' = P2 - P1 )和X轴。

使用该角度选择方向(每个方向具有360/8角度宽度)。

可以使用点积计算两个矢量之间的角度

让我们在每个45度的8个扇区上打破360度。 所以我们需要的是找到一个向量(p2 – p1)属于的8个扇区中的哪个扇区:

 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; 

工作样本

此解决方案将正确返回您的Direction.Undefined当坐标没有精确指向其中一个方向时,它通过检查角度消除嵌套的跟随控制语句( 参见单位圆 )。 请注意,我假设点类型的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