计算两个latitude-longitude点之间的距离? (Haversine公式)

问题描述

如何计算纬度和经度指定的两点之间的距离?
为了澄清,我想要距离公里;这些点使用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.

function getDistanceFromLatLonInKm(lat1,lon1,lat2,lon2) {
  var R = 6371; // Radius of the earth in km
  var dLat = deg2rad(lat2-lat1);  // deg2rad below
  var dLon = deg2rad(lon2-lon1);
  var a =
    Math.sin(dLat/2) * Math.sin(dLat/2) +
    Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) *
    Math.sin(dLon/2) * Math.sin(dLon/2)
    ;
  var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
  var d = R * c; // Distance in km
  return d;
}

function deg2rad(deg) {
  return deg * (Math.PI/180)
}

次佳解决方案

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

function distance(lat1, lon1, lat2, lon2) {
  var p = 0.017453292519943295;    // Math.PI / 180
  var c = Math.cos;
  var a = 0.5 - c((lat2 - lat1) * p)/2 +
          c(lat1 * p) * c(lat2 * p) *
          (1 - c((lon2 - lon1) * p))/2;

  return 12742 * Math.asin(Math.sqrt(a)); // 2 * R; R = 6371 km
}

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

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

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

为了完整性:维基上的Haversine

第三种解决方案

这是一个C#实现:

static class DistanceAlgorithm
{
    const double PIx = 3.141592653589793;
    const double RADIUS = 6378.16;

    /// <summary>
    /// Convert degrees to Radians
    /// </summary>
    /// <param name="x">Degrees</param>
    /// <returns>The equivalent in radians</returns>
    public static double Radians(double x)
    {
        return x * PIx / 180;
    }

    /// <summary>
    /// Calculate the distance between two places.
    /// </summary>
    /// <param name="lon1"></param>
    /// <param name="lat1"></param>
    /// <param name="lon2"></param>
    /// <param name="lat2"></param>
    /// <returns></returns>
    public static double DistanceBetweenPlaces(
        double lon1,
        double lat1,
        double lon2,
        double lat2)
    {
        double dlon = Radians(lon2 - lon1);
        double dlat = Radians(lat2 - lat1);

        double a = (Math.Sin(dlat / 2) * Math.Sin(dlat / 2)) + Math.Cos(Radians(lat1)) * Math.Cos(Radians(lat2)) * (Math.Sin(dlon / 2) * Math.Sin(dlon / 2));
        double angle = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
        return angle * RADIUS;
    }

第四种方案

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

描述
java.lang.Math.toRadians(double angdeg) 转换为度大致相等的角度,以弧度为单位的角度。从角度到弧度的转换通常是不精确的。

声明
以下是声明java.lang.Math.toRadians()方法

public static double toRadians(double angdeg)

参数
angdeg -- an angle, in degrees

返回值
此方法返回的的角度angdeg弧度测量。

异常
NA
import java.lang.*;

public class MathDemo {

   public static void main(String[] args) {

      // get two double numbers numbers
      double x = 45;
      double y = -180;

      // convert them in radians
      x = Math.toRadians(x);
      y = Math.toRadians(y);

      // print the hyperbolic tangent of these doubles
      System.out.println("Math.tanh(" + x + ")=" + Math.tanh(x));
      System.out.println("Math.tanh(" + y + ")=" + Math.tanh(y));

   }
}

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

Math.tanh(0.7853981633974483)=0.6557942026326724
Math.tanh(-3.141592653589793)=-0.99627207622075
public final static double AVERAGE_RADIUS_OF_EARTH_KM = 6371;
public int calculateDistanceInKilometer(double userLat, double userLng,
  double venueLat, double venueLng) {

    double latDistance = Math.toRadians(userLat - venueLat);
    double lngDistance = Math.toRadians(userLng - venueLng);

    double a = Math.sin(latDistance / 2) * Math.sin(latDistance / 2)
      + Math.cos(Math.toRadians(userLat)) * Math.cos(Math.toRadians(venueLat))
      * Math.sin(lngDistance / 2) * Math.sin(lngDistance / 2);

    double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));

    return (int) (Math.round(AVERAGE_RADIUS_OF_EARTH_KM * c));
}

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

第五种方案

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

const double PIx = 3.141592653589793;
const double RADIO = 6371; // Mean radius of Earth in Km

double convertToRadians(double val) {

   return val * PIx / 180;
}

-(double)kilometresBetweenPlace1:(CLLocationCoordinate2D) place1 andPlace2:(CLLocationCoordinate2D) place2 {

        double dlon = convertToRadians(place2.longitude - place1.longitude);
        double dlat = convertToRadians(place2.latitude - place1.latitude);

        double a = ( pow(sin(dlat / 2), 2) + cos(convertToRadians(place1.latitude))) * cos(convertToRadians(place2.latitude)) * pow(sin(dlon / 2), 2);
        double angle = 2 * asin(sqrt(a));

        return angle * RADIO;
}

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

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

额外更新:

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

-(double)kilometresBetweenPlace1:(CLLocationCoordinate2D) place1 andPlace2:(CLLocationCoordinate2D) place2 {

    MKMapPoint  start, finish;

    start = MKMapPointForCoordinate(place1);
    finish = MKMapPointForCoordinate(place2);

    return MKMetersBetweenMapPoints(start, finish) / 1000;
}

第六种方案

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

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
FROM obiective
WHERE coord_lat<>‘‘
    AND coord_long<>‘‘
HAVING distanta<50
ORDER BY distanta desc

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

第七种方案

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

<?php function distance($lat1, $lon1, $lat2, $lon2) {

    $pi80 = M_PI / 180;
    $lat1 *= $pi80;
    $lon1 *= $pi80;
    $lat2 *= $pi80;
    $lon2 *= $pi80;

    $r = 6372.797; // mean radius of Earth in km
    $dlat = $lat2 - $lat1;
    $dlon = $lon2 - $lon1;
    $a = sin($dlat / 2) * sin($dlat / 2) + cos($lat1) * cos($lat2) * sin($dlon / 2) * sin($dlon / 2);
    $c = 2 * atan2(sqrt($a), sqrt(1 - $a));
    $km = $r * $c;

    //echo ‘<br/>‘.$km;
    return $km;
}
?>

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

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

更多信息:wikipedia geographic distance

第八种方案

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

CLLocation *location1 = [[CLLocation alloc] initWithLatitude:latitude1 longitude:longitude1];
CLLocation *location2 = [[CLLocation alloc] initWithLatitude:latitude2 longitude:longitude2];
[self distanceInMetersFromLocation:location1 toLocation:location2]

- (int)distanceInMetersFromLocation:(CLLocation*)location1 toLocation:(CLLocation*)location2 {
    CLLocationDistance distanceInMeters = [location1 distanceFromLocation:location2];
    return distanceInMeters;
}

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

第九种方案

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

distm(p1, p2, fun = distHaversine)

哪里:

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

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

distm(p1, p2, fun = distVincentyEllipsoid)

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

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

第十种方案

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

参考文献

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

时间: 2024-10-10 22:20:13

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

计算两个GPS经纬度坐标之间的距离 PHP

不多说了,自己代码就行,你可以直接拿来用. /** * 计算两个坐标之间的距离(米) * @param float $fP1Lat 起点(纬度) * @param float $fP1Lon 起点(经度) * @param float $fP2Lat 终点(纬度) * @param float $fP2Lon 终点(经度) * @return int */ function distanceBetween($fP1Lat, $fP1Lon, $fP2Lat, $fP2Lon){ $fEARTH_

Lua 计算两个GPS坐标点之间的距离

local EARTH_RADIUS = 6378.137local function rad(d) return d * math.pi / 180.0end local function getDistance(lat1,lng1,lat2,lng2) local radLat1 = rad(lat1) local radLat2 = rad(lat2) local a = radLat1 - radLat2 local b = rad(lng1) - rad(lng2) local s =

根据2个经纬度点,计算这2个经纬度点之间的距离

原文  http://www.cnblogs.com/softfair/p/distance_of_two_latitude_and_longitude_points.html 根据 2 个经纬度点,计算这 2 个经纬度点之间的距离 球面上任意两点之间的距离计算公式可以参考维基百科上的下述文章. Great-circle distance Haversine formula 值得一提的是,维基百科推荐使用Haversine公式,理由是Great-circle distance公式用到了大量余弦函

比较字符串总结:如果计算两个字符串的相似度或者距离

有关字符串相关比较问题,一般处理方法都选择动态规划处理方法.或者是单个循环,或者是多个循环:dp 遇到这种两个串的问题,很容易想到DP.但是这道题的递推关系不明显.可以先尝试做一个二维的表int[][] dp,用来记录匹配子序列的个数(以S="rabbbit",T = "rabbit"为例): r a b b b i t 1 1 1 1 1 1 1 1 r 0 1 1 1 1 1 1 1 a 0 0 1 1 1 1 1 1 b 0 0 0 1 2 3 3 3 b 0

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

/**  * 求两个已知经纬度之间的距离,单位为米  *   * @param lng1 $ ,lng2 经度  * @param lat1 $ ,lat2 纬度  * @return float 距离,单位米  * @author www.Alixixi.com   */ function getdistance($lng1, $lat1, $lng2, $lat2) {     // 将角度转为狐度     $radLat1 = deg2rad($lat1); //deg2rad()函数将角

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

一 丶 -(double)distanceBetweenOrderBy:(double) lat1 :(double) lat2 :(double) lng1 :(double) lng2{ CLLocation *curLocation = [[CLLocation alloc] initWithLatitude:lat1 longitude:lng1]; CLLocation *otherLocation = [[CLLocation alloc] initWithLatitude:lat2

给你两个经纬度,计算他们之间的距离

原文:给你两个经纬度,计算他们之间的距离 这些经纬线是怎样定出来的呢?地球是在不停地绕地轴旋转(地轴是一根通过地球南北两极和地球中心的假想线),在地球中腰画一个与地轴垂直的大圆圈,使圈上的每一点都和南北两极的距离相等,这个圆圈就叫作“赤道”.在赤道的南北两边,画出许多和赤道平行的圆圈,就是“纬圈”:构成这些圆圈的线段,叫做纬线.我们把赤道定为纬度零度,向南向北各为90度,在赤道以南的叫南纬,在赤道以北的叫北纬.北极就是北纬90度,南极就是南纬90度.纬度的高低也标志着气候的冷热,如赤道和低纬度地

利用SQL计算两个地理坐标(经纬度)之间的地表距离

两个地理坐标(经纬度)地表距离计算公式: 公式解释如下: Long1,Lat1表示A点经纬度,Long2,Lat2表示B点经纬度: a=Lat1–Lat2 为两点纬度之差,b=Long1-Long2为两点经度之差: 6378.137为地球半径,单位为千米: 计算出来的结果单位为千米,若将半径改为米为单位则计算的结果单位为米; 计算精度与谷歌地图的距离精度差不多,相差范围在0.2米以下. 引用自https://segmentfault.com/a/1190000013922206 SQL语句实现如

计算两个日期之间相差几天(Date类型与String类型互相转换)

一:计算两个日期之间相差几天 1 /** 2 * 3 */ 4 package com.hlcui.date; 5 6 import java.text.ParseException; 7 import java.text.SimpleDateFormat; 8 import java.util.Calendar; 9 import java.util.Date; 10 11 import org.junit.Test; 12 13 /** 14 * @author Administrator