C# 使用 lat/long 数组计算多个曲率

Posted

技术标签:

【中文标题】C# 使用 lat/long 数组计算多个曲率【英文标题】:C# Calculate multiple curvatures with lat/long array 【发布时间】:2021-08-20 15:47:59 【问题描述】:

我有一系列纬度和经度构成从起点到目的地的整条路线,但我真的很难计算整条铁路路线的所有曲率,包括将左转作为负值,将右转作为正值(或反之亦然,以较容易者为准)。

我也有代码可以给我一个轴承以及两个轴承之间的差异,但这是我所掌握的(代码如下)。

从下图中的绿色标记出发,向西(左)行进,有:

向右轻微弯曲 向右急转 向左转 向左小转 大部分是直的 急左 有点直 紧随其后的是一个急右

本质上,它正在计算上述列表/图片中每个转弯的转弯半径。

所需的输出对象

public EdgeCurve[] Curves get; set;

public class EdgeCurve

    public double StartLatitude get;s et;
    public double StartLongitude get; set;

    public double EndLatitude get; set;
    public double EndLongitude get; set;

    public double Curve get; set;

    //Optional
    public double Distance get;set;

轴承代号

public static class BearingHelper


    /// <summary>
    /// Angle between two points, where North is 0 and South is 180.
    /// </summary>
    /// <param name="lat0">Latitude for point A.</param>
    /// <param name="lon0">Longitude for point A.</param>
    /// <param name="lat1">Latitude for point B.</param>
    /// <param name="lon1">Longitude for point B.</param>
    /// <returns>Angle between points A and B, in degrees.</returns>
    public static double Degrees(double lat0, double lon0, double lat1, double lon1)
    
        var dlon = (lon1 - lon0).ToRadians();
        var dphi = Math.Log(Math.Tan(lat1.ToRadians() / 2 + PI_d4) / Math.Tan(lat0.ToRadians() / 2 + PI_d4));

        if (Math.Abs(dlon) > Math.PI)
        
            dlon = dlon > 0 ? -(PI_m2 - dlon) : (PI_m2 + dlon);
        

        return (Math.Atan2(dlon, dphi).ToDegrees() + 360) % 360;
    

    public static double AbsDifference(double bearing0, double bearing1)
    
        double diff = Math.Abs(bearing0 - bearing1);

        if (diff > 180)
            diff -= 360;

        return Math.Abs(diff);
    


public static class CoordinateMath

    /// <summary>
    /// PI multiplied by 2.
    /// </summary>
    public const double PI_m2 = 6.28318530718;

    /// <summary>
    /// PI divided by 4.
    /// </summary>
    public const double PI_d4 = 0.78539816339;

    /// <summary>
    /// Convert degrees to radians.
    /// </summary>
    public static double ToRadians(this double deg) => deg * 0.01745329252;

    /// <summary>
    /// Convert radians to degrees.
    /// </summary>
    public static double ToDegrees(this double rad) => rad * 57.295779513;

纬度/经度数组

[
  
    "Latitude": 53.743647,
    "Longitude": -0.347531
  ,
  
    "Latitude": 53.743635,
    "Longitude": -0.348089
  ,
  
    "Latitude": 53.74365,
    "Longitude": -0.348648
  ,
  
    "Latitude": 53.74369,
    "Longitude": -0.349114
  ,
  
    "Latitude": 53.743754,
    "Longitude": -0.3496
  ,
  
    "Latitude": 53.743867,
    "Longitude": -0.35029
  ,
  
    "Latitude": 53.743941,
    "Longitude": -0.350679
  ,
  
    "Latitude": 53.744063,
    "Longitude": -0.351096
  ,
  
    "Latitude": 53.744518,
    "Longitude": -0.352272
  ,
  
    "Latitude": 53.744557,
    "Longitude": -0.352369
  ,
  
    "Latitude": 53.744888,
    "Longitude": -0.353199
  ,
  
    "Latitude": 53.744925,
    "Longitude": -0.353296
  ,
  
    "Latitude": 53.745078,
    "Longitude": -0.353724
  ,
  
    "Latitude": 53.745176,
    "Longitude": -0.354035
  ,
  
    "Latitude": 53.745339,
    "Longitude": -0.354672
  ,
  
    "Latitude": 53.745494,
    "Longitude": -0.355461
  ,
  
    "Latitude": 53.745591,
    "Longitude": -0.356196
  ,
  
    "Latitude": 53.745644,
    "Longitude": -0.356898
  ,
  
    "Latitude": 53.74566,
    "Longitude": -0.357678
  ,
  
    "Latitude": 53.745633,
    "Longitude": -0.358616
  ,
  
    "Latitude": 53.745577,
    "Longitude": -0.359361
  ,
  
    "Latitude": 53.745521,
    "Longitude": -0.359924
  ,
  
    "Latitude": 53.745439,
    "Longitude": -0.360563
  ,
  
    "Latitude": 53.745344,
    "Longitude": -0.361198
  ,
  
    "Latitude": 53.745192,
    "Longitude": -0.362056
  ,
  
    "Latitude": 53.745051,
    "Longitude": -0.362748
  ,
  
    "Latitude": 53.744811,
    "Longitude": -0.363821
  ,
  
    "Latitude": 53.744539,
    "Longitude": -0.364885
  ,
  
    "Latitude": 53.74428,
    "Longitude": -0.365809
  ,
  
    "Latitude": 53.744023,
    "Longitude": -0.366656
  ,
  
    "Latitude": 53.743862,
    "Longitude": -0.367141
  ,
  
    "Latitude": 53.743723,
    "Longitude": -0.367545
  ,
  
    "Latitude": 53.7434,
    "Longitude": -0.368412
  ,
  
    "Latitude": 53.743096,
    "Longitude": -0.369159
  ,
  
    "Latitude": 53.742528,
    "Longitude": -0.370427
  ,
  
    "Latitude": 53.742197,
    "Longitude": -0.371099
  ,
  
    "Latitude": 53.741909,
    "Longitude": -0.371663
  ,
  
    "Latitude": 53.741679,
    "Longitude": -0.372077
  ,
  
    "Latitude": 53.741462,
    "Longitude": -0.372498
  ,
  
    "Latitude": 53.74131,
    "Longitude": -0.372765
  ,
  
    "Latitude": 53.737842,
    "Longitude": -0.379223
  ,
  
    "Latitude": 53.737396,
    "Longitude": -0.380011
  ,
  
    "Latitude": 53.737152,
    "Longitude": -0.380388
  ,
  
    "Latitude": 53.737006,
    "Longitude": -0.380587
  ,
  
    "Latitude": 53.736736,
    "Longitude": -0.380912
  ,
  
    "Latitude": 53.736466,
    "Longitude": -0.381183
  ,
  
    "Latitude": 53.736294,
    "Longitude": -0.381331
  ,
  
    "Latitude": 53.736187,
    "Longitude": -0.381417
  ,
  
    "Latitude": 53.735827,
    "Longitude": -0.381659
  ,
  
    "Latitude": 53.735664,
    "Longitude": -0.381751
  ,
  
    "Latitude": 53.735378,
    "Longitude": -0.381882
  ,
  
    "Latitude": 53.735185,
    "Longitude": -0.381952
  ,
  
    "Latitude": 53.734976,
    "Longitude": -0.382014
  ,
  
    "Latitude": 53.734575,
    "Longitude": -0.382077
  ,
  
    "Latitude": 53.734372,
    "Longitude": -0.382083
  ,
  
    "Latitude": 53.734044,
    "Longitude": -0.382055
  ,
  
    "Latitude": 53.733148,
    "Longitude": -0.381884
  ,
  
    "Latitude": 53.732913,
    "Longitude": -0.381838
  ,
  
    "Latitude": 53.732526,
    "Longitude": -0.381762
  ,
  
    "Latitude": 53.732156,
    "Longitude": -0.381722
  ,
  
    "Latitude": 53.731976,
    "Longitude": -0.381718
  ,
  
    "Latitude": 53.731854,
    "Longitude": -0.381728
  
]

【问题讨论】:

例如曲线的作用是什么? 2.0 或 -5.7 是什么意思?你本质上是吗?你要求类似***.com/questions/7811761/… 嗨,如果节点太靠近,该链接是关于平滑线的,这是完全不同的。 2.0 表示它朝一个方向转动,-5.7 表示它朝另一个方向转动。我上传了一张更好的照片。 但是量级有什么意义呢?如果我编写了一个代码,将您的曲线声明为 -2312375.234234,这是什么意思?照原样,我认为您的问题不能(或不应该)得到回答,因为它基本上是“这是一个不完整的规范,请为我做我的工作”。将一组线段平滑成一组曲线并不是“完全不同”,这实际上是您显然要求的 当你说线条的平滑时,我会想到 Douglas-Peucker 算法,在该算法中删除数组中的冗余节点。我要问的是..如果火车沿着轨道行驶并开始右转,它开始右转与再次直行或左转之间的角度是多少。我只是不知道所需的数学或伪代码,没有这些,有人怎么知道在哪里看。我是软件开发人员而不是数学家,因此编写需求更加困难。 我想,从算法上讲,如果你站在任何给定的 N 点,那么你应该参考从前一个点 N-1 到当前的。然后,您将知道几件事:下一点是否是航向变化 - 如果不是,那么您处于恒定曲线上,如果是,那么 b) 变化是更靠右还是更靠左,因此(基于无论您已经向右还是向左)它是否更陡或更小,以及它是否代表从右向左的翻转。然后也许只是折叠你的序列 【参考方案1】:

假设您对将路径建模为一系列线段感到满意,您可以通过计算相邻线段之间的符号角度来简单地计算曲率。

在伪代码中

for(var i = 1; i < points.Length - 1; i++)
    var a = (points[i] - points[i-1]).Normalized;
    var b = (points[i+1] - points[i]).Normalized;
    // calculate signed angle between vectors
    angle = atan2( a.x*b.y - a.y*b.x, a.x*b.x + a.y*b.y );

从finding signed angle between vectors计算符号角的代码

如果你想要一个平滑的插值,比如Bézier spline,你仍然可以创建它,将它分割成更短的线段并使用上面的方法。但是,如果您想要平滑段的单个曲率值,则需要定义该值应该是什么。因为平滑函数将具有连续的曲率范围。

请注意,这是假设平面坐标,如果您有纬度/经度,您可能希望重新投影到平面坐标系,可能每个线段对都有一个。

【讨论】:

以上是关于C# 使用 lat/long 数组计算多个曲率的主要内容,如果未能解决你的问题,请参考以下文章

计算 2 lat longs 之间的距离

如何计算具有 lat+long 信息的集合的地理空间距离?

Python:计算两个纬度/经度之间的方位

计算街道的哈希值

减少 nxn 点的距离矩阵的计算

在 MySQL 中获取接近 lat,long 的多边形