【问题标题】:How to calculate turning direction如何计算转弯方向
【发布时间】:2011-03-26 01:30:47
【问题描述】:

我有一个三个纬度坐标,它们组成两条线段 A 到 B 到 C。我还找到了一个函数,可以以 -180 到 180 的方式返回线段 A-B 或 B-C 的北向。但是,我无法确定汽车何时从 A 到达 B,应该右转还是左转继续前往 C。

【问题讨论】:

    标签: c# geometry navigation geolocation gis


    【解决方案1】:

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

    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 对我的回答的评论。
    • 你是对的,有一个错误。现在我想我已经修复了它
    • 在 GetAngle(Point p1, Point p2) 中,我相信返回的 m 是 angleFromXAxis?
    【解决方案2】:

    编辑修复了 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 &gt; 0 更改为 angle &gt; 45 并将第二个更改为 angle &lt; -45

    【讨论】:

    • A = 16.83432,96.17936 B = 16.83378,96.1781 C = 16.83329,96.17831 AB = -114 BC = 157 (BC)-(AB) = 271 所以,根据你的说法,它会轮到正确的。但我可以直观地确认它正在向左转。这正是我必须问这个问题的原因。谢谢。
    • 271 比 180 多,所以它向右转了这么远,以至于它绕到了后面,现在指向左边。
    【解决方案3】:

    如果您使用vector cross product,我认为您的生活会更简单。

    虽然严格来说叉积仅针对 3D 向量定义,但对于 2D 向量 p=(px,py) 和 q=(qx,qy),您可以将他们的叉积 p×q 视为 pxqy - pyqx。如果 pq 顺时针方向,则后面的数字将为正数,如果 pq 逆时针方向,则后一个数字将为负数>。如果 pq 平行 - 即指向相同或相反的方向,它将为零。

    在您的情况下,您使用的是 (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 ;
    }
    

    【讨论】:

    【解决方案4】:

    如果 AB 是 B 与 A 的轴承,BC 是 C 与 B 的轴承,则 转角为余数(BC-AB,360.0); (假设学位)。如果这 是正的,转弯是向右的。在您的示例余数中(BC-AB,360.0) 是余数(271,360) = -89。

    【讨论】:

    • 我想不出你的回答有什么意义。
    • 余数函数是 POSIX 数学库中的标准函数。 From 'man remaining' :当 y 不为零时,这些函数应返回浮点余数 r= x- ny。值 n 是最接近精确值 x/y 的整数值。当|n-x/y|=0.5 时,选择n 为偶数。例如,剩余(10,360)将为 10,而剩余(350,360)将为 -10。作为一般规则,我发现在减去角度时最好总是使用余数。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-18
    • 2021-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多