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.
精彩评论