如何找到给定纬度/长度以北x km的纬度/经度?

Ste*_*eet 27 c# gis geometry

我有一些生成谷歌地图的C#代码.这些代码查看我需要在地图上绘制的所有点,然后计算出矩形的边界以包含这些点.然后,它会将此边界传递给Google Maps API,以适当地设置缩放级别,以显示地图上的所有点.

这段代码工作正常,但我有一个新的要求.

其中一个点可能具有与之相关的精度.如果是这种情况,那么我在半径设置为精度值的点周围绘制一个圆.再次,这工作正常,但我的边界检查现在没有做我想要它做的事情.我希望边界框包含完整的圆圈.

这需要算法采用点x并计算将在x以北z米以及x以南z米的点y.

有没有人有这个算法,最好是在C#中.我确实在这里找到了一个通用算法,但我似乎没有正确实现这个,因为我得到的答案是千米的漂移.

这是通用示例

Lat/lon given radial and distance

A point {lat,lon} is a distance d out on the tc radial from point 1 if:

     lat=asin(sin(lat1)*cos(d)+cos(lat1)*sin(d)*cos(tc))
     IF (cos(lat)=0)
        lon=lon1      // endpoint a pole
     ELSE
        lon=mod(lon1-asin(sin(tc)*sin(d)/cos(lat))+pi,2*pi)-pi
     ENDIF
Run Code Online (Sandbox Code Playgroud)

这是我的C#翻译.

  // Extend a Point North/South by the specified distance
    public static Point ExtendPoint(Point _pt, int _distance, int _bearing )
    {
        Decimal lat = 0.0;
        Decimal lng = 0.0;

        lat = Math.Asin(Math.Sin(_pt.Lat) * Math.Cos(_distance) + Math.Cos(_pt.Lat) * 
            Math.Sin(_distance) * Math.Cos(_bearing));

         if (Math.Cos(lat) == 0)
         {
            lng = _pt.Lng;      // endpoint a pole
         }
         else 
         {
             lng = (
                 (_pt.Lng - Math.Asin(Math.Sin(_bearing) * Math.Sin(_distance) / Math.Cos(lat)) 
                 + Math.PI) % (2 * Math.PI)) - Math.PI;
         }

         ret = new Point(lat,lng);
         return ret;
    }
Run Code Online (Sandbox Code Playgroud)

我调用此函数的轴承为0来计算新的北偏位置,并将值180设置为计算新的南风位置.

任何人都可以看到我做错了或者可能提供一个已知的工作算法吗?

Eri*_*bal 23

我有一段非常相似的代码.与其他实现相比,它让我得到了非常接近的结果.

我认为与你的问题在于你使用"距离"作为以米为单位的线性距离而不是以弧度表示的角距离.

/// <summary>
/// Calculates the end-point from a given source at a given range (meters) and bearing (degrees).
/// This methods uses simple geometry equations to calculate the end-point.
/// </summary>
/// <param name="source">Point of origin</param>
/// <param name="range">Range in meters</param>
/// <param name="bearing">Bearing in degrees</param>
/// <returns>End-point from the source given the desired range and bearing.</returns>
public static LatLonAlt CalculateDerivedPosition(LatLonAlt source, double range, double bearing)
{
    double latA = source.Latitude * UnitConstants.DegreesToRadians;
    double lonA = source.Longitude * UnitConstants.DegreesToRadians;
    double angularDistance = range / GeospatialConstants.EarthRadius;
    double trueCourse = bearing * UnitConstants.DegreesToRadians;

    double lat = Math.Asin(
        Math.Sin(latA) * Math.Cos(angularDistance) + 
        Math.Cos(latA) * Math.Sin(angularDistance) * Math.Cos(trueCourse));

    double dlon = Math.Atan2(
        Math.Sin(trueCourse) * Math.Sin(angularDistance) * Math.Cos(latA), 
        Math.Cos(angularDistance) - Math.Sin(latA) * Math.Sin(lat));

    double lon = ((lonA + dlon + Math.PI) % UnitConstants.TwoPi) - Math.PI;

    return new LatLonAlt(
        lat * UnitConstants.RadiansToDegrees, 
        lon * UnitConstants.RadiansToDegrees, 
        source.Altitude);
}
Run Code Online (Sandbox Code Playgroud)

哪里

public const double EarthRadius = 6378137.0;   //  WGS-84 ellipsoid parameters
Run Code Online (Sandbox Code Playgroud)

和LatLonAlt以度/米为单位(转换在内部进行).根据需要调整.

我假设你可以弄清楚它的价值UnitConstants.DegreesToRadians是什么:)

  • EarthRadius = 6378137.0,TwoPi = Math.PI * 2,DegreesToRadians = 0.0174532925,RadiansToDegrees = 57.2957795。 (3认同)

Zar*_*dan 11

对于懒惰的人(像我一样))复制粘贴解决方案,Erich Mirabal的版本有很小的变化:

using System.Device.Location; // add reference to System.Device.dll
public static class GeoUtils
{
    /// <summary>
    /// Calculates the end-point from a given source at a given range (meters) and bearing (degrees).
    /// This methods uses simple geometry equations to calculate the end-point.
    /// </summary>
    /// <param name="source">Point of origin</param>
    /// <param name="range">Range in meters</param>
    /// <param name="bearing">Bearing in degrees</param>
    /// <returns>End-point from the source given the desired range and bearing.</returns>
    public static GeoCoordinate CalculateDerivedPosition(this GeoCoordinate source, double range, double bearing)
    {
        var latA = source.Latitude * DegreesToRadians;
        var lonA = source.Longitude * DegreesToRadians;
        var angularDistance = range / EarthRadius;
        var trueCourse = bearing * DegreesToRadians;

        var lat = Math.Asin(
            Math.Sin(latA) * Math.Cos(angularDistance) +
            Math.Cos(latA) * Math.Sin(angularDistance) * Math.Cos(trueCourse));

        var dlon = Math.Atan2(
            Math.Sin(trueCourse) * Math.Sin(angularDistance) * Math.Cos(latA),
            Math.Cos(angularDistance) - Math.Sin(latA) * Math.Sin(lat));

        var lon = ((lonA + dlon + Math.PI) % (Math.PI*2)) - Math.PI;

        return new GeoCoordinate(
            lat * RadiansToDegrees,
            lon * RadiansToDegrees,
            source.Altitude);
    }

    private const double DegreesToRadians = Math.PI/180.0;
    private const double RadiansToDegrees = 180.0/ Math.PI;
    private const double EarthRadius = 6378137.0;
}
Run Code Online (Sandbox Code Playgroud)

用法:

[TestClass]
public class CalculateDerivedPositionUnitTest
{
    [TestMethod]
    public void OneDegreeSquareAtEquator()
    {
        var center = new GeoCoordinate(0, 0);
        var radius = 111320;
        var southBound = center.CalculateDerivedPosition(radius, -180);
        var westBound = center.CalculateDerivedPosition(radius, -90);
        var eastBound = center.CalculateDerivedPosition(radius, 90);
        var northBound = center.CalculateDerivedPosition(radius, 0);

        Console.Write($"leftBottom: {southBound.Latitude} , {westBound.Longitude} rightTop: {northBound.Latitude} , {eastBound.Longitude}");
    }
}
Run Code Online (Sandbox Code Playgroud)


rya*_*n_s 7

我不确定我是否在这里遗漏了一些东西,但我认为这个问题可以改为:"我有一个纬度/经度点,而且我想找到该点以北x米和该点以南x米的点. "

如果这是问题,那么你不需要找到新的经度(这会使事情变得更简单),你只需要一个新的纬度.地球上任何地方的纬度大约为60海里,海里距离为1,852米.因此,对于新的纬度x南北:

north_lat = lat + x / (1852 * 60)
north_lat = min(north_lat, 90)

south_lat = lat - x / (1852 * 60)
south_lat = max(south_lat, -90)
Run Code Online (Sandbox Code Playgroud)

这并不完全准确,因为地球不是一个完美的球体,每个纬度之间恰好有60海里.然而,其他答案假设纬度线是等距的,所以我假设你不关心它.如果您对可能引入的错误感兴趣,维基百科上有一个很好的表格,显示了此链接中不同纬度的"纬度每1°变化的表面距离":

http://en.wikipedia.org/wiki/Latitude#Degree_length


Sam*_*152 5

如果您有一个给定的纬度和经度,您可以计算纬度x-km变化的正确纬度和经度,如下所示:

new-lat = ((old-km-north + x-km-change)/40,075) * 360)
           ^ is the ratio of the                  ^ times the ratio of the circle
           of the earth the change                by 360 to get the total ratio 
           covers.                                covered in degrees.
Run Code Online (Sandbox Code Playgroud)

这同样适用于经度.如果您有总距离加上更改,您可以以类似的方式计算总度数.

new-long = ((old-km-east + x-km-change)/40,075) * 360)
           ^ is the ratio of the                  ^ times the ratio of the circle
           of the earth the change                by 360 to get the total ratio 
           covers.                                covered in degrees.
Run Code Online (Sandbox Code Playgroud)

同样,这些计算应该有效,但我在这里运行纯粹的直觉,但逻辑似乎确实如此.

编辑:正如Skizz 40,075指出的那样,需要使用2.pi.r.cos(lat)或40074.cos(lat)在任意给定的纬度调整到地球的周长.

  • 谁能告诉我一个老公里北/老公里东方指的是什么? (5认同)
  • KevDog暗示的是,随着纬度增加,40,075减少 - 在极点附近东边1km将增加赤道以东1km以上的经度.因此,您需要在给定纬度处用圆周替换40,075,即:2.pi.rs.cos(lat),其中rs是地球的半径,lat是纬度.它确实假设地球是球形的.但是,如果你向东1公里然后向北1公里而不是向北1公里然后向东1公里,这种方法会产生不同的结果. (2认同)
  • 如果您只是将度数添加到原始位置,为什么不保持经度相同(因为他只是向北,经度不应该改变)并且只需将km-change/40,075添加到lat?这个等式对我来说似乎非常脆弱,缺乏大量数据.当有非常彻底的方程来描述如何计算时,为什么要直觉? (2认同)