两个坐标的相对基数方向

时间:2016-01-30 17:48:08

标签: c# algorithm

定义了以下枚举:

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

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

4 个答案:

答案 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)消除嵌套的跟随控制语句。请注意,我假设点类型的XY属性定义为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类型将XY属性定义为浮点类型,则以下内容将返回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;

Working sample