给定当前点、距离和方位角,获取纬度/经度

114

给定一个经纬度坐标点,以及距离(以公里为单位)和方位角(以弧度表示的角度),我想要计算新的经纬度坐标。这个网站一次又一次地出现,但是我就是无法使公式对我起作用。

上述链接中提供的公式如下:

lat2 = asin(sin(lat1)*cos(d/R) + cos(lat1)*sin(d/R)*cos(θ))

lon2 = lon1 + atan2(sin(θ)*sin(d/R)*cos(lat1), cos(d/R)sin(lat1)*sin(lat2))

上述公式适用于MSExcel,其中-

asin          = arc sin()   
d             = distance (in any unit)   
R             = Radius of the earth (in the same unit as above)  
and hence d/r = is the angular distance (in radians)  
atan2(a,b)    = arc tan(b/a)  
θ is the bearing (in radians, clockwise from north);  

这是我在Python中得到的代码。

import math

R = 6378.1 #Radius of the Earth
brng = 1.57 #Bearing is 90 degrees converted to radians.
d = 15 #Distance in km

#lat2  52.20444 - the lat result I'm hoping for
#lon2  0.36056 - the long result I'm hoping for.

lat1 = 52.20472 * (math.pi * 180) #Current lat point converted to radians
lon1 = 0.14056 * (math.pi * 180) #Current long point converted to radians

lat2 = math.asin( math.sin(lat1)*math.cos(d/R) +
             math.cos(lat1)*math.sin(d/R)*math.cos(brng))

lon2 = lon1 + math.atan2(math.sin(brng)*math.sin(d/R)*math.cos(lat1),
                     math.cos(d/R)-math.sin(lat1)*math.sin(lat2))

print(lat2)
print(lon2)

我得到

lat2 = 0.472492248844 
lon2 = 79.4821662373

1
@GWW,我得到了一个不合理的答案。这个不合理的原因是因为我没有将答案转换回度数。代码已更改并包含在原帖中作为编辑。 - David M
6
你应该将编辑后的内容直接提交为答案,并接受该答案,以便更清楚地表明您解决了自己的问题。否则,Stack Overflow会对您未解决的问题进行惩罚,这会使未来的用户更有可能不愿回答您的问题。 - Cerin
如果您使用numpy对象,您将获得更好的精度和结果。 - Mike Pennington
应该是“lat1 = 52.20472 * (math.pi */180)”吗? - Tushar Seth
如果方位角为90度,为什么纬度会改变呢?这不只是沿着经线移动吗? - danjampro
可能可以忽略不计,但如果您需要绝对精度,您可以将地球半径设置为3个小数位,R = 6378.137 - 来自Google Maps的几何库文档“默认半径是地球半径6378137米”- https://developers.google.com/maps/documentation/javascript/reference/geometry - Esteban Ortega
15个回答

1

只需要在 atan2(y,x) 函数中交换值即可,不是 atan2(x,y)!


1

虽然已经晚了,但对于那些可能会发现这个问题的人来说,您可以使用geographiclib库获得更准确的结果。查看大地测量问题描述和JavaScript示例,以便轻松入门如何回答主题问题以及许多其他问题。在包括Python在内的各种语言中实现。如果您关心准确性,比编写自己的代码要好得多;比之前“使用库”的建议中的VincentyDistance更好。正如文档所说:“重点是返回与舍入误差接近(约5-15纳米)的准确结果。”


0

这是一个基于Ed Williams航空公式的PHP版本。在PHP中,模数处理方式略有不同。这对我来说很有效。

function get_new_waypoint ( $lat, $lon, $radial, $magvar, $range )
{

   // $range in nm.
   // $radial is heading to or bearing from    
   // $magvar for local area.

   $range = $range * pi() /(180*60);
   $radial = $radial - $magvar ;

   if ( $radial < 1 )
     {
        $radial = 360 + $radial - $magvar; 
     }
   $radial =  deg2rad($radial);
   $tmp_lat = deg2rad($lat);
   $tmp_lon = deg2rad($lon);
   $new_lat = asin(sin($tmp_lat)* cos($range) + cos($tmp_lat) * sin($range) * cos($radial));
   $new_lat = rad2deg($new_lat);
   $new_lon = $tmp_lon - asin(sin($radial) * sin($range)/cos($new_lat))+ pi() % 2 * pi() -  pi();
   $new_lon = rad2deg($new_lon);

   return $new_lat." ".$new_lon;

}

你能解释一下这几个变量吗?像$range和$magvar这样的变量对于像我这样的初学者来说需要更多的解释。 - Tommie C.
请查看我的答案以及使用的公式链接,以及我们可以期望的精度。 - not2qubit

0

对于那些对Java解决方案感兴趣的人,这是我的代码: 我注意到初始解决方案需要一些调整才能返回正确的经度值,特别是当点位于极点之一时。 此外,有时需要进行四舍五入操作,因为在0纬度/经度上的结果似乎略微偏离0。对于小距离,四舍五入将有所帮助。

private static final double EARTH_RADIUS = 6371; // average earth radius

    /**
     * Returns the coordinates of the point situated at the distance specified, in
     * the direction specified. Note that the value is an approximation, not an
     * exact result.
     *
     * @param startPointLatitude
     * @param startPointLongitude
     * @param distanceInKm
     * @param bearing:            0 means moving north, 90 moving east, 180 moving
     *                            south, 270 moving west. Max value 360 min value 0;
     * @return new point location
     */
    public static LocationDTO getPointAt(double startPointLatitude, double startPointLongitude, double distanceInKm,
            double bearing) {
        if (Math.abs(startPointLatitude) > 90) {
            throw new BadRequestException(ExceptionMessages.INVALID_LATITUDE);
        } else if (Math.abs(startPointLatitude) == 90) {
            startPointLatitude = 89.99999 * Math.signum(startPointLatitude); // we have to do this conversion else the formula doesnt return the correct longitude value 
        }
        if (Math.abs(startPointLongitude) > 180) {
            throw new BadRequestException(ExceptionMessages.INVALID_LONGITUDE);
        }
        double angularDistance = distanceInKm / EARTH_RADIUS;
        bearing = deg2rad(bearing);
        startPointLatitude = deg2rad(startPointLatitude);
        startPointLongitude = deg2rad(startPointLongitude);
        double latitude = Math.asin(Math.sin(startPointLatitude) * Math.cos(angularDistance)
                + Math.cos(startPointLatitude) * Math.sin(angularDistance) * Math.cos(bearing));
        double longitude = startPointLongitude
                + Math.atan2(Math.sin(bearing) * Math.sin(angularDistance) * Math.cos(startPointLatitude),
                        Math.cos(angularDistance) - Math.sin(startPointLatitude) * Math.sin(latitude));
        longitude = (rad2deg(longitude) + 540) % 360 - 180; // normalize longitude to be in -180 +180 interval 
        LocationDTO result = new LocationDTO();
        result.setLatitude(roundValue(rad2deg(latitude)));
        result.setLongitude(roundValue(longitude));
        return result;
    }

    private static double roundValue(double value) {
        DecimalFormat df = new DecimalFormat("#.#####");
        df.setRoundingMode(RoundingMode.CEILING);
        return Double.valueOf(df.format(value));
    }


    // This function converts decimal degrees to radians
    private static double deg2rad(double deg) {
        return (deg * Math.PI / 180.0);
    }

    // This function converts radians to decimal degrees
    private static double rad2deg(double rad) {
        return (rad * 180.0 / Math.PI);
    }

-1
非常晚才来参加派对,但这里有一个用R语言的答案,供有兴趣的人参考。我唯一做出的改变是将半径设置为米,所以d也需要设置为米。
get_point_at_distance <- function(lon, lat, d, bearing, R = 6378137) {
  # lat: initial latitude, in degrees
  # lon: initial longitude, in degrees
  # d: target distance from initial point (in m)
  # bearing: (true) heading in degrees
  # R: mean radius of earth (in m)
  # Returns new lat/lon coordinate {d} m from initial, in degrees
  ## convert to radians
  lat1 <- lat * (pi/180)
  lon1 <- lon * (pi/180)
  a <- bearing * (pi/180)
  ## new position
  lat2 <- asin(sin(lat1) * cos(d/R) + cos(lat1) * sin(d/R) * cos(a))
  lon2 <- lon1 + atan2(
    sin(a) * sin(d/R) * cos(lat1),
    cos(d/R) - sin(lat1) * sin(lat2)
  )
  ## convert back to degrees
  lat2 <- lat2 * (180/pi)
  lon2 <- lon2 * (180/pi)
  ## return
  return(c(lon2, lat2))
}

lat = 52.20472
lon = 0.14056
distance = 15000
bearing = 90
get_point_at_distance(lon = lon, lat = lat, d = distance, bearing = bearing)
# [1]  0.3604322 52.2045157

这个帖子明确标记了Python,所以不需要在其他语言中提供更多答案。 - not2qubit
这个帖子明确标记为“Python”,所以不需要提供其他语言的答案了。 - undefined
1
那么,对于每种语言,我们都应该提出新的问题来实现这个功能吗? - undefined
那么,对于每种语言的实现,我们应该提出新的问题吗? - KaanKaant
是的,没错。除非问题明确指定任何语言并且没有标记语言标签。 - not2qubit

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