开发者

How to calculate turning direction

I have a three lat-lon coordinates that make up two line segment A to B to C. I also found a function that can return north-bearing of a line segment A-B o开发者_如何学编程r B-C in -180 to 180 manner. However, I'm having trouble to determine when a car reaches from A to B, should it turn right or left to continue to C.


EDIT: Previous answer was wrong. now this is the correct

public Direction GetDirection(Point a, Point b, Point c)
{
    double theta1 = GetAngle(a, b); 
    double theta2 = GetAngle(b, c);
    double delta = NormalizeAngle(theta2 - theta1);

    if ( delta == 0 )
        return Direction.Straight;
    else if ( delta == Math.PI )
        return Direction.Backwards;
    else if ( delta < Math.PI )
        return Direction.Left;
    else return Direction.Right;
}

private Double GetAngle(Point p1, Point p2)
{
    Double angleFromXAxis = Math.Atan ((p2.Y - p1.Y ) / (p2.X - p1.X ) ); // where y = m * x + K
    return  p2.X - p1.X < 0 ? m + Math.PI : m ); // The will go to the correct Quadrant
}

private Double NormalizeAngle(Double angle)
{
    return angle < 0 ? angle + 2 * Math.PI : angle; //This will make sure angle is [0..2PI]
}


Edited to fix the over 180 issue, also now supports U-Turns.

const int THRESHOLD = 0;
Direction TurnLeftOrRight(Point A, Point B, Point C)
{
    int angle = ToAngle(B,C) - ToAngle(A,B);
    if((angle > THRESHOLD && angle < 180 - THREASHOLD) || angle < -180 - THREASHOLD)
        return Direction.Right;
    else if ((angle < 0 - THREASHOLD && angle > -180 + THREASHOLD) || angle > 180 + THREASHOLD)
        return Direction.Left;
    else if (angle >= 0 - THREASHOLD && angle <= THREASHOLD)
        return Direction.Straight
    else
        return Direction.UTurn;
}

You could also do tolerances between left right and strait just change the first angle > 0 to angle > 45 and the second one to angle < -45


I think your life will be simpler if you use the vector cross product.

Although strictly speaking cross product is defined only for 3D vectors, for 2D vectors p=(px,py) and q=(qx,qy), you can think of their cross product p×q as as pxqy - pyqx. This latter number will be positive if p is clockwise from q, and negative if p is counter-clockwise from q. It will be zero if p and q are parallel - i.e. point in the same or opposite directions.

In your case, you are using (lat,lon). The equivalent in (x,y) coordinates is (-lon, lat), so if you have two vectors (lat1,lon1) and (lat2,lon2), you want to calculate (-lon1, lat1)×(-lon2, lat2), which comes out to lat1*lon2-lon1*lat2.

If this number is zero, you can use the dot product to tell whether the direction is straight or a U-turn.

So your code could look like this, assuming Points and Vectors are written in (lat, lon) form (the code would be a little different if they are in x and y):

public Direction GetTurnDirection(Point A, Point B, Point C)
{
    Vector v1 = B - A ;
    Vector v2 = C - B ;
    double cross = v1.lat*v2.lon - v1.lon*v2.lat ;
    if (cross > 0) { return Direction.Left ; } 
    if (cross < 0) { return Direction.Right ; }
    double dot =  v1.lat*v2.lat + v1.lon*v2.lon ;
    if (dot > 0) { return Direction.Straight ; }
    return Direction.UTurn ;
}


If AB is the bearing of B from A, and BC that of C from B, the turn angle is remainder( BC-AB, 360.0); (assuming degrees). If this is positive the turn is to the right. In your example remainder( BC-AB, 360.0) is remainder(271,360) = -89.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜