根据距离、方位和起点计算终点

12

我正在尝试找到目标点,已知起始点的纬度/经度、方位角和距离。该网站下面的计算器给出了我想要的结果。

http://www.movable-type.co.uk/scripts/latlong.html

当我尝试通过代码实现相同的功能时,我没有得到正确的结果。

以下是我的代码 -

    private  GLatLng pointRadialDistance(double lat1, double lon1,
               double radianBearing, double radialDistance)
    {
        double rEarth = 6371.01;
        lat1 = DegreeToRadian(lat1);
        lon1 = DegreeToRadian(lon1);
        radianBearing = DegreeToRadian(radianBearing);
        radialDistance = radialDistance / rEarth;
        double lat = Math.Asin(Math.Sin(lat1) * Math.Cos(radialDistance) + Math.Cos(lat1)
                        * Math.Sin(radialDistance) * Math.Cos(radianBearing));
        double lon;
        if (Math.Cos(lat) == 0)
        {  // Endpoint a pole 
            lon = lon1;
        }
        else
        {
            lon = ((lon1 - Math.Asin(Math.Sin(radianBearing) * Math.Sin(radialDistance) / Math.Cos(lat))
                            + Math.PI) % (2 * Math.PI)) - Math.PI;
        }
        lat = RadianToDegree(lat);
        lon = RadianToDegree(lon);
        GLatLng newLatLng = new GLatLng(lat, lon);
        return newLatLng;
    }

    public  double Bearing(double lat1, double long1, double lat2, double long2)
    {
        //Convert input values to radians   
        lat1 = DegreeToRadian(lat1);
        long1 = DegreeToRadian(long1);
        lat2 = DegreeToRadian(lat2);
        long2 = DegreeToRadian(long2);

        double deltaLong = long2 - long1;

        double y = Math.Sin(deltaLong) * Math.Cos(lat2);
        double x = Math.Cos(lat1) * Math.Sin(lat2) -
                Math.Sin(lat1) * Math.Cos(lat2) * Math.Cos(deltaLong);
        double bearing = Math.Atan2(y, x);
        return bearing;
    }   

   public double DegreeToRadian(double angle)
    {
    return Math.PI * angle / 180.0;
    }

    public double RadianToDegree(double angle)
    {
        return 180.0 * angle / Math.PI;
    }

从主程序中,我按以下方式调用子过程 -

double bearing = Bearing(-41.294444, 174.814444, -40.90521, 175.6604);
GLatLng endLatLng = pointRadialDistance(-41.294444, 174.814444, bearing, 80);

我得到以下的结果 -

Bearing=1.02749621782165
endLatLng=-40.5751022737927,174.797458881699

我期望的答案是 -40.939722,175.646389(来自上述网站链接)。

有人能否提出我在这段代码中犯了什么错误?


1
首先,Bearing 函数返回的结果应该被转换成度数。 - user780503
4个回答

23

以下是能实现你所需功能的代码。

public static GeoLocation FindPointAtDistanceFrom(GeoLocation startPoint, double initialBearingRadians, double distanceKilometres)
{
    const double radiusEarthKilometres = 6371.01;
    var distRatio = distanceKilometres / radiusEarthKilometres;
    var distRatioSine = Math.Sin(distRatio);
    var distRatioCosine = Math.Cos(distRatio);

    var startLatRad = DegreesToRadians(startPoint.Latitude);
    var startLonRad = DegreesToRadians(startPoint.Longitude);

    var startLatCos = Math.Cos(startLatRad);
    var startLatSin = Math.Sin(startLatRad);

    var endLatRads = Math.Asin((startLatSin * distRatioCosine) + (startLatCos * distRatioSine * Math.Cos(initialBearingRadians)));

    var endLonRads = startLonRad
        + Math.Atan2(
            Math.Sin(initialBearingRadians) * distRatioSine * startLatCos,
            distRatioCosine - startLatSin * Math.Sin(endLatRads));

    return new GeoLocation
    {
        Latitude = RadiansToDegrees(endLatRads),
        Longitude = RadiansToDegrees(endLonRads)
    };
}

public struct GeoLocation
{
    public double Latitude { get; set; }
    public double Longitude { get; set; }
}

public static double DegreesToRadians(double degrees)
{
    const double degToRadFactor = Math.PI / 180;
    return degrees * degToRadFactor;
}

public static double RadiansToDegrees(double radians)
{
    const double radToDegFactor = 180 / Math.PI;
    return radians * radToDegFactor;
}

7

这是我从http://www.movable-type.co.uk/scripts/latlong.html转换成C#的代码,它应该很容易使用。

public static (double Lat, double Lon) Destination((double Lat, double Lon) startPoint, double distance, double bearing)
    {
        var radius = 6378001;
        double lat1 = startPoint.Lat * (Math.PI / 180);
        double lon1 = startPoint.Lon * (Math.PI / 180);
        double brng = bearing * (Math.PI / 180);
        double lat2 = Math.Asin(Math.Sin(lat1) * Math.Cos(distance / radius) + Math.Cos(lat1) * Math.Sin(distance / radius) * Math.Cos(brng));
        double lon2 = lon1 + Math.Atan2(Math.Sin(brng) * Math.Sin(distance / radius) * Math.Cos(lat1), Math.Cos(distance / radius) - Math.Sin(lat1) * Math.Sin(lat2));
        return (lat2 * (180 / Math.PI), lon2 * (180 / Math.PI));
    }

radius是地球半径的常数,单位为米。

使用元组以便您可以通过.Lat.Lon单独访问纬度或经度。


1
如果我可以提供一些建设性的反馈,我认为最好将变量名称更改为大多数人可以轻松输入的更具描述性的内容。除此之外,回答不错:D - grooveplex
1
这些是我在 Java 中使用的网站名称,但我太懒了不想改。但我会进行修改。 - TrueCP5
3
为什么不能显示实际的“半径”以使示例更完整,而不是声明它是多少? - ΩmegaMan

1
以下是我为自己编写并在自己的项目中使用的JavaScript代码实现,可在http://www.movable-type.co.uk/scripts/latlong.html找到。如果您愿意,可以将其应用于您的项目。
注:Coordinate是一个具有X(经度)、Y(纬度)和Z(海拔)属性的类。ToDegree()和ToRadian()是Double类型的扩展。最后,GetTarget()是Coordinate实例的扩展。
/// <summary>Calculates the destination coordinate by given angle and distance.</summary>
/// <param name="origin">Origin.</param>
/// <param name="bearing">Azimuth.</param>
/// <param name="distance">Distance (km).</param>
/// <returns>Coordinate.</returns>
public static Coordinate GetTarget(
this Coordinate origin, double bearing, double distance, double altitude = 0)
{
    var d = distance / 6371;
    var rlat = origin.Y.ToRadian();
    var rlon = origin.X.ToRadian();
    var rbearing = bearing.ToRadian();
    var lat2 = rlat + (d * Math.Cos(rbearing));
    var dlat = lat2 - rlat;
    var dphi = Math.Log((Math.Tan((lat2 / 2) + (Math.PI / 4))) / (Math.Tan((rlat / 2) + (Math.PI / 4))));
    var q =
        Math.Abs(dlat) > 0.0000000001
        ? dlat / dphi
        : Math.Cos(rlat);
    var dlon = (d * Math.Sin(rbearing)) / q;

    if (Math.Abs(lat2) > Math.PI / 2)
    {
        lat2 = lat2 > 0 ? Math.PI : Math.PI - lat2;
    }

    var lon2 = (rlon + dlon + Math.PI) % (2 * Math.PI) - Math.PI;

    return new Coordinate
    {
        X = lon2.ToDegree(),
        Y = lat2.ToDegree(),
        Z = origin.Z
    };
}

-1

在几何库(V3)中有一个非常简单的解决方案,如果您不介意使用Google Maps API V3(根据应用程序 - 例如实时资产跟踪 - 免费许可证不适用或者您可能不想从V2重构到V3)。

第一步:除了当前声明外,再声明一个额外的库:

<script type="text/javascript" src="http://maps.google.com/maps/api/js?libraries=geometry&sensor=false"></script>

第二步:确定起点、方向和距离

var nyc = new google.maps.LatLng(40.715, -74.002);
var distance = 5576673;
var heading = 51.2145;

第三步:前往那里

var endPoint = google.maps.geometry.spherical.computeOffset(nyc, distance, heading);
var london = new google.maps.Marker({
  position: endPoint,
  map: map
});

完成了,你现在在伦敦。想了解更多关于computeDistance、computeHeading和computeArea的信息:

http://www.svennerberg.com/2011/04/calculating-distances-and-areas-in-google-maps-api-3/

http://code.google.com/intl/en/apis/maps/documentation/javascript/geometry.html


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接