问题描述

如何计算纬度和经度指定的两点之间的距离?
为了澄清,我想要距离公里;这些点使用WGS84系统,我想了解可用方法的相对准确性。
最佳解决方案

这个link可能对您有帮助,因为它详细说明了使用Haversine formula计算距离。

摘抄:

This script [in Javascript] calculates great-circle distances between the two points – that is, the shortest distance over the earth’s surface – using the ‘Haversine’ formula.

  1. function getDistanceFromLatLonInKm(lat1,lon1,lat2,lon2) {
  2. var R = ; // Radius of the earth in km
  3. var dLat = deg2rad(lat2-lat1); // deg2rad below
  4. var dLon = deg2rad(lon2-lon1);
  5. var a =
  6. Math.sin(dLat/) * Math.sin(dLat/) +
  7. Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) *
  8. Math.sin(dLon/) * Math.sin(dLon/)
  9. ;
  10. var c = * Math.atan2(Math.sqrt(a), Math.sqrt(-a));
  11. var d = R * c; // Distance in km
  12. return d;
  13. }
  14.  
  15. function deg2rad(deg) {
  16. return deg * (Math.PI/)
  17. }

次佳解决方案

我需要计算我的项目点数之间的距离,所以我继续尝试优化代码,我在这里找到。平均来说,在不同浏览器中,我的新实现运行速度比最受欢迎的答案快2倍。

  1. function distance(lat1, lon1, lat2, lon2) {
  2. var p = 0.017453292519943295; // Math.PI / 180
  3. var c = Math.cos;
  4. var a = 0.5 - c((lat2 - lat1) * p)/ +
  5. c(lat1 * p) * c(lat2 * p) *
  6. ( - c((lon2 - lon1) * p))/;
  7.  
  8. return * Math.asin(Math.sqrt(a)); // 2 * R; R = 6371 km
  9. }

你可以玩我的jsPerf,看看results here

最近我需要做同样的python,所以这里是一个python实现:

  1. from math import cos, asin, sqrt
  2. def distance(lat1, lon1, lat2, lon2):
  3. p = 0.017453292519943295 #Pi/180
  4. a = 0.5 - cos((lat2 - lat1) * p)/2 + cos(lat1 * p) * cos(lat2 * p) * (1 - cos((lon2 - lon1) * p)) / 2
  5. return 12742 * asin(sqrt(a)) #2*R*asin...

为了完整性:维基上的Haversine

第三种解决方案

这是一个C#实现:

  1. static class DistanceAlgorithm
  2. {
  3. const double PIx = 3.141592653589793;
  4. const double RADIUS = 6378.16;
  5.  
  6. /// <summary>
  7. /// Convert degrees to Radians
  8. /// </summary>
  9. /// <param name="x">Degrees</param>
  10. /// <returns>The equivalent in radians</returns>
  11. public static double Radians(double x)
  12. {
  13. return x * PIx / ;
  14. }
  15.  
  16. /// <summary>
  17. /// Calculate the distance between two places.
  18. /// </summary>
  19. /// <param name="lon1"></param>
  20. /// <param name="lat1"></param>
  21. /// <param name="lon2"></param>
  22. /// <param name="lat2"></param>
  23. /// <returns></returns>
  24. public static double DistanceBetweenPlaces(
  25. double lon1,
  26. double lat1,
  27. double lon2,
  28. double lat2)
  29. {
  30. double dlon = Radians(lon2 - lon1);
  31. double dlat = Radians(lat2 - lat1);
  32.  
  33. double a = (Math.Sin(dlat / ) * Math.Sin(dlat / )) + Math.Cos(Radians(lat1)) * Math.Cos(Radians(lat2)) * (Math.Sin(dlon / ) * Math.Sin(dlon / ));
  34. double angle = * Math.Atan2(Math.Sqrt(a), Math.Sqrt( - a));
  35. return angle * RADIUS;
  36. }

第四种方案

这是一个Java实现的Haversine公式。

  1. 描述
  2. java.lang.Math.toRadians(double angdeg) 转换为度大致相等的角度,以弧度为单位的角度。从角度到弧度的转换通常是不精确的。
  3.  
  4. 声明
  5. 以下是声明java.lang.Math.toRadians()方法
  6.  
  7. public static double toRadians(double angdeg)
  8.  
  9. 参数
  10. angdeg -- an angle, in degrees
  11.  
  12. 返回值
  13. 此方法返回的的角度angdeg弧度测量。
  14.  
  15. 异常
  16. NA
  1. import java.lang.*;
  2.  
  3. public class MathDemo {
  4.  
  5. public static void main(String[] args) {
  6.  
  7. // get two double numbers numbers
  8. double x = 45;
  9. double y = -180;
  10.  
  11. // convert them in radians
  12. x = Math.toRadians(x);
  13. y = Math.toRadians(y);
  14.  
  15. // print the hyperbolic tangent of these doubles
  16. System.out.println("Math.tanh(" + x + ")=" + Math.tanh(x));
  17. System.out.println("Math.tanh(" + y + ")=" + Math.tanh(y));
  18.  
  19. }
  20. }

让我们来编译和运行上面的程序,这将产生以下结果:

  1. Math.tanh(0.7853981633974483)=0.6557942026326724
  2. Math.tanh(-3.141592653589793)=-0.99627207622075
  1. public final static double AVERAGE_RADIUS_OF_EARTH_KM = 6371;
  2. public int calculateDistanceInKilometer(double userLat, double userLng,
  3. double venueLat, double venueLng) {
  4.  
  5. double latDistance = Math.toRadians(userLat - venueLat);
  6. double lngDistance = Math.toRadians(userLng - venueLng);
  7.  
  8. double a = Math.sin(latDistance / 2) * Math.sin(latDistance / 2)
  9. + Math.cos(Math.toRadians(userLat)) * Math.cos(Math.toRadians(venueLat))
  10. * Math.sin(lngDistance / 2) * Math.sin(lngDistance / 2);
  11.  
  12. double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
  13.  
  14. return (int) (Math.round(AVERAGE_RADIUS_OF_EARTH_KM * c));
  15. }

请注意,在这里我们将答案舍入到最近的公里。

第五种方案

非常感谢所有这一切。我在我的Objective-C iPhone应用程序中使用了以下代码:

  1. const double PIx = 3.141592653589793;
  2. const double RADIO = ; // Mean radius of Earth in Km
  3.  
  4. double convertToRadians(double val) {
  5.  
  6. return val * PIx / ;
  7. }
  8.  
  9. -(double)kilometresBetweenPlace1:(CLLocationCoordinate2D) place1 andPlace2:(CLLocationCoordinate2D) place2 {
  10.  
  11. double dlon = convertToRadians(place2.longitude - place1.longitude);
  12. double dlat = convertToRadians(place2.latitude - place1.latitude);
  13.  
  14. double a = ( pow(sin(dlat / ), ) + cos(convertToRadians(place1.latitude))) * cos(convertToRadians(place2.latitude)) * pow(sin(dlon / ), );
  15. double angle = * asin(sqrt(a));
  16.  
  17. return angle * RADIO;
  18. }

纬度和经度是十进制数。我没有使用min()作为asin()调用,因为我使用的距离是如此之小,以至于不需要它。

它给了不正确的答案,直到我通过了Radians的价值观 – 现在它几乎与从Apple的Map应用程序获得的值相同:-)

额外更新:

如果您正在使用iOS4或更高版本,那么Apple提供一些方法来执行此操作,因此可以通过以下方式实现相同的功能:

  1. -(double)kilometresBetweenPlace1:(CLLocationCoordinate2D) place1 andPlace2:(CLLocationCoordinate2D) place2 {
  2.  
  3. MKMapPoint start, finish;
  4.  
  5. start = MKMapPointForCoordinate(place1);
  6. finish = MKMapPointForCoordinate(place2);
  7.  
  8. return MKMetersBetweenMapPoints(start, finish) / ;
  9. }

第六种方案

我在这里张贴我的工作实例。
列出表中具有小于50KM的指定点(我们使用随机点 – 纬度:45.20327,长:23.7806)之间的距离的所有点,纬度&经度在MySQL(表格栏位是coord_lat和coord_long):
列出所有DISTANCE< 50,公里(被认为是地球半径6371 KM):

  1. SELECT denumire, (6371 * acos( cos( radians(45.20327) ) * cos( radians( coord_lat ) ) * cos( radians( 23.7806 ) - radians(coord_long) ) + sin( radians(45.20327) ) * sin( radians(coord_lat) ) )) AS distanta
  2. FROM obiective
  3. WHERE coord_lat<>''
  4. AND coord_long<>''
  5. HAVING distanta<50
  6. ORDER BY distanta desc

以上示例在MySQL 5.0.95和5.5.16(Linux)中进行了测试。

第七种方案

这是一个简单的PHP函数,它将给出非常合理的近似值(低于+/- 1%误差范围)。

  1. <?php function distance($lat1, $lon1, $lat2, $lon2) {
  2.  
  3. $pi80 = M_PI / 180;
  4. $lat1 *= $pi80;
  5. $lon1 *= $pi80;
  6. $lat2 *= $pi80;
  7. $lon2 *= $pi80;
  8.  
  9. $r = 6372.797; // mean radius of Earth in km
  10. $dlat = $lat2 - $lat1;
  11. $dlon = $lon2 - $lon1;
  12. $a = sin($dlat / 2) * sin($dlat / 2) + cos($lat1) * cos($lat2) * sin($dlon / 2) * sin($dlon / 2);
  13. $c = 2 * atan2(sqrt($a), sqrt(1 - $a));
  14. $km = $r * $c;
  15.  
  16. //echo '<br/>'.$km;
  17. return $km;
  18. }
  19. ?>

如前所述:地球不是一个球体。它就像一个老旧的棒球,标记mcguire决定练习 – 它充满了凹痕和颠簸。更简单的计算(像这样)将其视为一个球体。

不同的方法可能根据您在这种不规则卵形上的位置或多或少精确,并且您的点距离相差甚远(绝对误差越小越小)。你的期望越准确,数学越复杂。

更多信息:wikipedia geographic distance

第八种方案

您可以使用CLLocationDistance中的构建来计算:

  1. CLLocation *location1 = [[CLLocation alloc] initWithLatitude:latitude1 longitude:longitude1];
  2. CLLocation *location2 = [[CLLocation alloc] initWithLatitude:latitude2 longitude:longitude2];
  3. [self distanceInMetersFromLocation:location1 toLocation:location2]
  4.  
  5. - (int)distanceInMetersFromLocation:(CLLocation*)location1 toLocation:(CLLocation*)location2 {
  6. CLLocationDistance distanceInMeters = [location1 distanceFromLocation:location2];
  7. return distanceInMeters;
  8. }

在你的情况下,如果你想要千分之一除以1000。

第九种方案

在其他答案中,缺少r中的一个实现。
使用geosphere封装的distm功能计算两点之间的距离是非常简单的:

  1. distm(p1, p2, fun = distHaversine)

哪里:

  1. p1 = longitude/latitude for point(s)
  2. p2 = longitude/latitude for point(s)
  3. # type of distance calculation
  4. fun = distCosine / distHaversine / distVincentySphere / distVincentyEllipsoid

由于地球不是完美的球面,Vincenty formula for ellipsoids可能是计算距离的最佳方式。因此,在geosphere包中,您可以使用:

  1. distm(p1, p2, fun = distVincentyEllipsoid)

当然你也不一定要用geosphere包,还可以用R的基础距离计算一下功能:

  1. hav.dist <- function(long1, lat1, long2, lat2) {
  2. R <- 6371
  3. diff.long <- (long2 - long1)
  4. diff.lat <- (lat2 - lat1)
  5. a <- sin(diff.lat/2)^2 + cos(lat1) * cos(lat2) * sin(diff.long/2)^2
  6. c <- 2 * asin(min(1,sqrt(a)))
  7. d = R * c
  8. return(d)
  9. }

第十种方案

它取决于你想要的准确程度,以及所定义的datum的长度和长度。非常,非常近,你做一个小的球形触发,但纠正事实,地球不是一个球体,使公式更复杂。

参考文献

注:本文内容整合自google/baidu/bing辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:gxnotes#qq.com(#替换为@)。

计算两个latitude-longitude点之间的距离? (Haversine公式)的更多相关文章

  1. PHP计算两个已知经纬度之间的距离

    /** *求两个已知经纬度之间的距离,单位为千米 *@param lng1,lng2 经度 *@param lat1,lat2 纬度 *@return float 距离,单位千米 **/ privat ...

  2. c#计算 坐标点与坐标点之间的距离

    PointF p = new PointF(116.305671f, 39.966051f); PointF p2 = new PointF(116.595428f, 39.828327f); dou ...

  3. php计算两个经纬度地点之间的距离(转)

    php计算两个指定的经纬度地点之间的距离,这个在做计算给定某个地点的经纬度,计算其附近的商业区,以及给定地点与附近各商业区之间的距离的时候,还是用的到的.下面是具体的函数代码以及用法示例. 关于如何获 ...

  4. PHP计算两个经纬度地点之间的距离

    /**  * 求两个已知经纬度之间的距离,单位为米  *   * @param lng1 $ ,lng2 经度  * @param lat1 $ ,lat2 纬度  * @return float 距 ...

  5. PHP通过经纬坐标计算两个地址的距离

    <?php /** *求两个已知经纬度之间的距离,单位为米 * *@param lng1,lng2 经度 * *@param lat1,lat2 纬度 * *@return float 距离,单 ...

  6. PHP计算经纬度之间的距离

    <?php /** * 求两个已知经纬度之间的距离,单位为米 * * @param lng1 $ ,lng2 经度 * @param lat1 $ ,lat2 纬度 * @return floa ...

  7. IOS 计算两个经纬度之间的距离

    IOS 计算两个经纬度之间的距离 一 丶 -(double)distanceBetweenOrderBy:(double) lat1 :(double) lat2 :(double) lng1 :(d ...

  8. HTML5地理定位(已知经纬度,计算两个坐标点之间的距离)

    事实上,地球上任意两个坐标点在地平线上的距离并不是直线,而是球面的弧线. 下面介绍如何利用正矢公式计算已知经纬度数据的两个坐标点之间的距离.半正矢公式也成为Haversine公式,它最早时航海学中的重 ...

  9. reactjs中使用高德地图计算两个经纬度之间的距离

    第一步下载依赖 npm install --save react-amap 第二步,在组件中使用 import React, { Component } from 'react' import { L ...

随机推荐

  1. ANDROID 中设计模式的采用--行为模式

     1 职责链模式 职责链模式的意图为:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系.将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止.使多个对象都有 ...

  2. Android Widget小组件开发(一)——Android实现时钟Widget组件的步骤开发,这些知识也是必不可少的!

    Android Widget小组件开发(一)--Android实现时钟Widget组件的步骤开发,这些知识也是必不可少的! PS:学习自某网站(不打广告) 这个小组件相信大家都很熟悉吧,以前的墨迹天气 ...

  3. 测试驱动开发TDD(test drive development)

    classpath,路径列表.告诉java需要加载类的存放位置, java会去搜寻.这种机制实现了动态加载. java -cp 加载类路径 执行类名   : 加载类路径可是绝对,也可以相对. 代码重构 ...

  4. MongoDB之整库备份还原单表collection备份还原

    MongoDB之整库备份还原单表collection备份还原 cd D:\MongoDB\bin 1整库备份: mongodump -h dbhost -d dbname -o dbdirectory ...

  5. linux下64位汇编的系统调用(4)

    经过上一篇的铺垫貌似可以很轻松的用汇编写出mmap的代码来,可仔细一看,还是有不少问题需要解决: 1.系统调用mmap如果出错并不直接返回MAP_FAILED(-1),而是一个"类似&quo ...

  6. app ionic1 微信 微博 分享功能的实现

    微信分享 1.登录微信开放平台注册账户 2.创建一个移动应用  (app)  审核过后会有一个appid 之后安装插件的时候会用到 3.在这个应用上面填写 包名 和  签名   就可以了 包名和签名的 ...

  7. Python 可视化TVTK CubeSource管线初使用

    CubeSource对象是长方体数据源对象.本次在安装成功TVTK库的基础上显示一个长方体对象.通过以下代码,我们设置一个长宽高分别为1.0,2.0,3.0的长方体数据源并通过管线显示出来. from ...

  8. Objective-C 空指针和野指针

    一.什么是空指针和野指针 1.空指针 1> 没有存储任何内存地址的指针就称为空指针(NULL指针) 2> 空指针就是被赋值为0的指针,在没有被具体初始化之前,其值为0. 下面两个都是空指针 ...

  9. 《转》iOS 平台 Cocos2d-x 项目接入新浪微博 SDK 的坑

    最近在做一个 iOS 的 cocos2d-x 项目接入新浪微博 SDK 的时候被“坑”了,最后终于顺利的解决了.发现网上也有不少人遇到一样的问题,但是能找到的数量有限的解决办法写得都不详细,很难让人理 ...

  10. JAVA代码设置selector不同状态下的背景颜色

    代码实现Shape 代码实现Selector StateListDrawable与GradientDrawable 的运用 在Android开发中,我们时常会用到自定义drawable样式,在draw ...