The relative cardinal direction of two coordinates

The following enumeration is defined:

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

Given two sets of coordinates in two-dimensional space, I would like to determine the relative cardinal direction from point 2 to 1.

Examples:

  • P1 (1,1) and P2 (0,1) returns the direction. Note like P2 is north of P1
  • P1 (1,1) and P2 (5,4) returns the direction. Southeast
  • P1 (1,1) and P2 (1,1) returns Direction.Undefined

My current approach includes many conditions, i.e.

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 
{
    ...
}

I am looking for a shorter and more elegant solution.

+4
source share
4 answers

My 3 cents - I'm waiting for improvement

Here is the listing:

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

and the conversion is as follows:

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

It does not return Direction.Undefinedbecause

y 0, x 0, θ = 0.

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

+4

, P1 P2, P -> P - P1, P1 2D-.

(0,0) - P2', P2' - t P2 point (P2' = P2 - P1) X.

( 360/8).

dot product

+1

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
+1
source

Let’s break 360 into 8 sectors of 45 degrees each. So, we need to find which of the 8 sectors the vector (p2 - p1) belongs to:

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

+1
source

Source: https://habr.com/ru/post/1626678/


All Articles