簡體   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