1

我有下面的代码来计算从 A(60.054166,-35.542222)到 B(-48.175833,-8.541111)的距离。以上坐标采用 EPSG:4326 系统(这是标准 GPS 纬度/经度坐标)。

默认测量单位是角度,所以我将所有内容转换为 EPSG:3857,其中测量单位是米

static void Main(string[] args) {

        /* we will convert everything from 4326 (lat/lon) to 3857 since the latter's default unit is meters instead of rads */

        geomFactory = new GeometryFactory(new PrecisionModel(1e6), 3857);

        var cs4326 = ProjNet.CoordinateSystems.GeographicCoordinateSystem.WGS84;
        var cs3857 = ProjNet.CoordinateSystems.ProjectedCoordinateSystem.WebMercator;
        var ctFactory = new ProjNet.CoordinateSystems.Transformations.CoordinateTransformationFactory();
        var ct = ctFactory.CreateFromCoordinateSystems(cs4326, cs3857);
        var mt = ct.MathTransform;

        var p1 = new double[] { -35.5422222, 60.054166 };
        var p2 = new double[] { -8.541111, -48.1758333 };

        var r1 = mt.Transform(p1);
        var r2 = mt.Transform(p2);

        var lineString = geomFactory.CreateLineString(new Coordinate[] { new Coordinate(r1[0], r1[1]), new Coordinate(r2[0], r2[1]) });
        Console.WriteLine("Distance is: " + lineString.Length / 1000 + " km.");
        Console.ReadLine();
}

我得到的输出是: 14,855.22 公里,但谷歌地图测量工具输出 12,343.32 相同的坐标

有些东西告诉我谷歌的输出是正确的,所以问题是我在这里遗漏了什么?

4

1 回答 1

1

在更仔细地检查了图书馆之后,我跳进了 NetTopologySuite/src/NetTopologySuite/Algorithm/Length.cs

using System;
using NetTopologySuite.Geometries;
namespace NetTopologySuite.Algorithm {

/// <summary>
/// Functions for computing length.
/// </summary>
/// <author>
/// Martin Davis
/// </author>
public class Length
{
    /// <summary>
    /// Computes the length of a <c>LineString</c> specified by a sequence of points.
    /// </summary>
    /// <param name="pts">The points specifying the <c>LineString</c></param>
    /// <returns>The length of the <c>LineString</c></returns>
    public static double OfLine(CoordinateSequence pts)
    {
        // optimized for processing CoordinateSequences
        int n = pts.Count;
        if (n <= 1)
            return 0.0;

        double len = 0.0;

        var p = pts.GetCoordinateCopy(0);
        double x0 = p.X;
        double y0 = p.Y;

        for (int i = 1; i < n; i++)
        {
            pts.GetCoordinate(i, p);
            double x1 = p.X;
            double y1 = p.Y;
            double dx = x1 - x0;
            double dy = y1 - y0;

            len += Math.Sqrt(dx * dx + dy * dy);

            x0 = x1;
            y0 = y1;
        }
        return len;
    }

}}

现在很明显为什么我与谷歌计算有如此大的偏差。它使用欧几里得距离,我怀疑谷歌使用的是 Haversine 公式。

如果我这样添加 LineString 的扩展方法

public static class NetTopologySuiteGeometriesExtension
{

    public static double ToRadians(this double degrees)
    {
        double radians = (Math.PI / 180) * degrees;
        return (radians);
    }

    
    public static double HaversineDistance(this LineString s)
    {
        // optimized for processing CoordinateSequences
        var cs = s.CoordinateSequence;
        int n = cs.Count;
        if (n <= 1)
            return 0.0;

        double len = 0.0;

        var p = cs.GetCoordinateCopy(0);
        double x0 = p.X;
        double y0 = p.Y;

        for (int i = 1; i < n; i++)
        {
            cs.GetCoordinate(i, p);
            double x1 = p.X;
            double y1 = p.Y;
            double dx = x1 - x0;
            double dy = y1 - y0;

            double R = 6371000;
            var lat = dx.ToRadians();
            var lng = dy.ToRadians();
            var h1 = Math.Sin(lat / 2) * Math.Sin(lat / 2) +
                          Math.Cos(x0.ToRadians()) * Math.Cos(x1.ToRadians()) *
                          Math.Sin(lng / 2) * Math.Sin(lng / 2);
            var h2 = 2 * Math.Asin(Math.Min(1, Math.Sqrt(h1)));
            len += R * h2;

            x0 = x1;
            y0 = y1;
        }
        return len;
    }
}

那么如果我改变

Console.WriteLine("Distance is: " + lineString.Length / 1000 + " km.");

Console.WriteLine("Distance is: " + lineString.HaversineDistance() / 1000 + " km.");

我得到 12,212.01 公里。这与谷歌很接近并且有一定的意义。

不是一个非常“通用”的解决方案,更多的是一个肮脏的解决方法 -如果它是正确的,那就是.

于 2020-08-26T12:11:15.447 回答