【发布时间】:2011-03-26 01:30:47
【问题描述】:
我有一个三个纬度坐标,它们组成两条线段 A 到 B 到 C。我还找到了一个函数,可以以 -180 到 180 的方式返回线段 A-B 或 B-C 的北向。但是,我无法确定汽车何时从 A 到达 B,应该右转还是左转继续前往 C。
【问题讨论】:
标签: c# geometry navigation geolocation gis
我有一个三个纬度坐标,它们组成两条线段 A 到 B 到 C。我还找到了一个函数,可以以 -180 到 180 的方式返回线段 A-B 或 B-C 的北向。但是,我无法确定汽车何时从 A 到达 B,应该右转还是左转继续前往 C。
【问题讨论】:
标签: c# geometry navigation geolocation gis
编辑:之前的答案是错误的。现在这是正确的
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]
}
【讨论】:
编辑修复了 180 多个问题,现在还支持 U 形转弯。
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;
}
您也可以在左右和海峡之间设置公差,只需将第一个 angle > 0 更改为 angle > 45 并将第二个更改为 angle < -45
【讨论】:
如果您使用vector cross product,我认为您的生活会更简单。
虽然严格来说叉积仅针对 3D 向量定义,但对于 2D 向量 p=(px,py) 和 q=(qx,qy),您可以将他们的叉积 p×q 视为 pxqy - pyqx。如果 p 从 q 顺时针方向,则后面的数字将为正数,如果 p 从 q 逆时针方向,则后一个数字将为负数>。如果 p 和 q 平行 - 即指向相同或相反的方向,它将为零。
在您的情况下,您使用的是 (lat,lon)。 (x,y)坐标中的等价物是(-lon, lat),所以如果你有两个向量(lat1,lon1)和(lat2,lon2),你要计算(-lon1, lat1)×(-lon2, lat2),得出 lat1*lon2-lon1*lat2。
如果此数字为零,您可以使用dot product 来判断方向是直行还是掉头。
因此,假设点和向量以 (lat, lon) 形式编写(如果它们是 x 和 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 ;
}
【讨论】:
如果 AB 是 B 与 A 的轴承,BC 是 C 与 B 的轴承,则 转角为余数(BC-AB,360.0); (假设学位)。如果这 是正的,转弯是向右的。在您的示例余数中(BC-AB,360.0) 是余数(271,360) = -89。
【讨论】: