两个坐标的相对基数方向
以下枚举定义如下:
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
当坐标没有精确指向其中一个方向时,它通过检查角度消除嵌套的跟随控制语句( 参见单位圆 )。 请注意,我假设点类型的X
和Y
属性定义为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
类型将X
和Y
属性定义为浮点类型,则类似下面的内容将返回Direction.Undefined
因为它不完全指向东方,所以希望这适合您的意图......
// "Almost" pointing east... dir = GetDirection(new Point(0, 0), new Point(1, 0.001));
输出...
Undefined