如何计算转向方向

5

我有三个经纬度坐标,它们构成了两条线段A到B到C。我还找到了一个可以返回线段A-B或B-C的方向角度的函数,范围为-180到180。然而,我现在遇到了麻烦,无法确定当汽车从A到达B时,它应该向左转还是向右转才能继续前往C。

4个回答

9

编辑:之前的答案是错误的。现在这个才是正确的

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

请看一下我在Scott的回答中所做的评论。 - VOX
1
你是对的,有一个错误。现在我认为我已经修复了它。 - Carlos Muñoz
在GetAngle(Point p1, Point p2)中,我相信返回值中的m是angleFromXAxis? - udjat

3

已经进行修改以解决超过180问题,现在还支持掉头。

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


A = 16.83432,96.17936 B = 16.83378,96.1781 C = 16.83329,96.17831 A-B = -114 B-C = 157 (B-C)-(A-B) = 271 所以,根据你的计算,它应该向右转。但我可以通过肉眼确认它正在向左转。这正是为什么我提出这个问题的原因。谢谢。 - VOX
1
271比180大,所以它向右转了很远,现在已经绕到后面并指向左边。 - Karl

3
我认为,如果你使用向量叉积,你的生活会更加简单。
尽管严格来说,叉积只针对三维向量定义,但对于二维向量p=(px,py)和q=(qx,qy),你可以将它们的叉积p×q看作是pxqy - pyqx。如果p顺时针旋转到q,则该数字将为正数;如果p逆时针旋转到q,则该数字将为负数。如果pq平行,则该数字为零,即指向相同或相反方向。
在你的情况下,你正在使用(lat,lon)。在(x,y)坐标系中的等效坐标为(-lon,lat),因此如果你有两个向量(lat1,lon1)和(lat2,lon2),你需要计算(-lon1,lat1)×(-lon2,lat2),结果为lat1*lon2-lon1*lat2。
如果这个数字为零,您可以使用点积来判断方向是直行还是掉头。
因此,假设 Points 和 Vectors 以 (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 ;
}

好的回答。我不知道叉积只定义在三维向量中。 - LarsH
@larsH:是的,推广到其他维度通常被称为外积或楔积。http://en.wikipedia.org/wiki/Exterior_product - brainjam

0
如果AB是从A到B的方位角,BC是从B到C的方位角,则转向角度为remainder(BC-AB, 360.0)(假设单位为度)。如果结果为正数,则表示向右转。在您的示例中,remainder(BC-AB, 360.0)为remainder(271,360)=-89。

我无法理解你的回答。 - VOX
余数函数是 POSIX 数学库中的标准函数。从“man remainder”中可以得知:当y非零时,这些函数将返回浮点余数r= x- ny。值n是最接近x/y的整数值。当|n-x/y|=0.5时,选择偶数值n。例如,remainder(10,360)将是10,而remainder(350,360)将是-10。通常情况下,我发现在减去角度时最好始终使用余数函数。 - dmuir

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接