定义了以下枚举:
public enum Direction
{
North,
South,
East,
West,
Northeast,
Northwest,
Southeast,
Southwest,
Undefined
}
在二维空间中给出两组坐标,我想确定从第2点到第1点的相对基数方向。
示例:
我目前的做法涉及一系列条件,即
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
{
...
}
我正在寻求更短更优雅的解决方案。
答案 0 :(得分:5)
我的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)
答案 1 :(得分:1)
假设您有P1和P2,使用转换P -> P - P1
将P1移动到2D空间的原点。
然后计算向量(0,0) - P2'
之间的角度,其中P2'
是变换P2
点(P2' = P2 - P1
)和X轴。
使用该角度选择方向(每个方向都有360/8
角度宽度)。
可以使用dot product
计算两个向量之间的角度答案 2 :(得分:1)
当坐标未指向其中一个方向时,此解决方案将正确返回Direction.Undefined
,并通过检查角度(see unit circle)消除嵌套的跟随控制语句。请注意,我假设点类型的X
和Y
属性定义为int
,但即使将它们定义为浮点类型值(例如,浮点数,小数或双)。
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
答案 3 :(得分:1)
让我们在每个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;