繁体   English   中英

从中央纬度/经度在具有特定半径的圆中生成点

[英]Producing Points in a Circle with Specific Radius from Central Lat/Long

我需要能够获取一组纬度/经度坐标并在 map 上围绕这些坐标绘制一个圆形“围栏”,其中圆形中的点数和圆的半径都是可配置的。 我的目标是能够输入点、形状的半径和我希望它具有的点数,并接收一个 output 包含一个纬度/经度坐标列表,如果它可以在中心点周围完成一个形状连接的。

我已经能够提出一个可行的解决方案来完成我需要的大部分工作,但是有一些事情并没有按照我的预期工作,而且我对基础数学的理解很弱,以至于我不确定如何解决它们。

我引用了 CSharpHelper 的这篇文章,以在我的起点周围生成一个圆圈中的点,并从这个 StackOverflow 答案中进行数学运算,以尝试将我的英里半径转换为纬度和经度。 这是我到目前为止的代码:

public readonly struct LocationPoint
{
    public LocationPoint(double lat, double lon)
    {
        Lat = lat;
        Lon = lon;
    }
        
    public double Lat { get; }
    public double Lon { get; }
}

private static List<LocationPoint> GetZoneCoordinates(LocationPoint center,
                                                      double radiusInMiles,
                                                      int numberOfPoints)
{
    // Convert input miles to degrees latitude and longitude.
    var radiusKm = radiusInMiles * 0.621371;
    var radiusLon = 1 / (111.319 * Math.Cos(center.Lat)) * radiusKm;
    var radiusLat = 1 / 110.574 * radiusKm;
            
    // Calculate amount to increment angle for number of points.
    var dTheta = 2 * Math.PI / numberOfPoints;
    double theta = 0;

    // Produce points.
    var points = new List<LocationPoint>();
    for (var i = 0; i < numberOfPoints; i++)
    {
        points.Add(new LocationPoint
        (
            center.Lat + radiusLat * Math.Sin(theta),
            center.Lon + radiusLon * Math.Cos(theta)
        ));
        theta += dTheta;
    }
            
    return points;
}

上面的代码可以很好地使用我给它的点数创建一个圆形。 我将以肯尼迪国际机场的中心点为例。 如果我以 5 英里和 8 个点的半径运行上述内容,我会得到一组坐标 map 到以下点:

在此处输入图像描述

这个形状有两个问题:

  1. 这是一个垂直椭圆(虽然我不确定这是否真的是一个问题,可能只是在球体上映射并在 2D 地图上显示的结果)
  2. 实际半径远小于我的输入。 我为上面的一组点输入了0.5英里的半径,从右到左的直径实际上更接近0.25英里。

我在这里做错了什么?

您转换为公里是错误的。 var radiusKm = radiusInMiles * 0.621371; 应该是var radiusKm = radiusInMiles / 0.621371; .

一种检测此类错误的直观方法:一公里比一英里短,因此对于任意数量的英里,您应该有比英里的公里。 但是您的公式显然原始数字减少到较小的数字,因此这是不对的。

如果您的原始转换因子带有单位(应该如此),那么检测这种错误的另一种方法是确保在数学中包含单位。 0.621371实际上是0.621371 mile/kilometer 当您在原始公式中包含单位时,您会得到mile * mile/kilometer的单位,而您真正想要的只是kilometer

至于边界不是一个完美的圆,我会说是的,这可能至少部分是因为在那个纬度使用了映射投影。 请注意,map 中包含的网格线也不会形成完美的正方形,但会以与您的边界相同的方式延伸。 但请记住,您使用的公式假设地球是一个完美的球体,而且绝对不是。 与从两极到另一极的直径相比,它在赤道处凸出,因此将其视为完美球体将导致您在此处看到的扭曲。

如果这对其他人有帮助,我可以使用上面代码中的一些数学运算以及@PeterDuniho 的指导,得到一个真正的“大圆”距离计算的非常接近的近似值,现在方法输出创建更均匀圆形的坐标:

private static List<LocationPoint> GetZoneCoordinates(LocationPoint center,
                                                      double radiusInMiles,
                                                      int numberOfPoints)
{
    // Convert input miles to degrees latitude and longitude.
    var radiusKm = radiusInMiles / 0.621371;
    var radiusLon = 1 / (111.319 * Math.Cos(center.Lat * (Math.PI / 180))) * radiusKm;
    var radiusLat = 1 / 110.574 * radiusKm;
            
    // Calculate amount to increment angle for number of points.
    var dTheta = 2 * Math.PI / numberOfPoints;
    double theta = 0;

    // Produce points.
    var points = new List<LocationPoint>();
    for (var i = 0; i < numberOfPoints; i++)
    {
        points.Add(new LocationPoint
        (
            center.Lat + radiusLat * Math.Sin(theta),
            center.Lon + radiusLon * Math.Cos(theta)
        ));
        theta += dTheta;
    }
            
    return points;
}

不同之处在于计算radiusLon的行 - 使用中心点纬度的转换弧度的余弦而不是原始度数。 我希望我可以说我理解为什么这会有所作为,但它在我迄今为止尝试过的所有纬度上都运作良好。

考虑到他在我的原始代码中发现了最严重的错误,我会将 Peter 的回复保留为已接受的答案。 再次感谢您的帮助!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM