ChatGPT解决这个技术问题 Extra ChatGPT

计算两个经纬度点之间的距离? (Haversine 公式)

如何计算经纬度指定的两点之间的距离?

为了澄清起见,我想要以公里为单位的距离;这些点使用 WGS84 系统,我想了解可用方法的相对准确性。

为获得更高的准确性 - 请参阅 stackoverflow.com/questions/1420045/…
请注意,您不能在 WGS 84 等旋转椭球体上应用半正弦公式。您只能在具有半径的球体上应用此方法。
这里的大多数答案都是使用简单的球面三角法,因此与 GPS 系统中使用的 WGS84 椭球距离相比,结果相当粗糙。有些答案确实参考了 Vincenty 的椭球公式,但该算法是为 1960 年代的台式计算器设计的,它具有稳定性和稳定性。准确性问题;我们现在有更好的硬件和软件。请参阅 GeographicLib,了解具有多种语言实现的高质量库。
@MikeT - 虽然这里的许多答案似乎在小距离内很有用:如果您从 WGS 84 中获取纬度/经度,并应用Haversine,就好像这些是球体上的点一样,您不会得到错误仅归因于的答案地球的扁平化系数,所以可能在更准确公式的 1% 以内?需要注意的是,这些距离很短,比如在一个城镇内。
对于这些平台:Mono/.NET 4.5/.NET Core/Windows Phone 8.x/Universal Windows Platform/Xamarin iOS/Xamarin Android,请参阅 stackoverflow.com/a/54296314/2736742

D
Deduplicator

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

摘抄:

该脚本 [in Javascript] 使用“Haversine”公式计算两点之间的大圆距离——即地球表面上的最短距离。

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)
}

这种计算/方法是否说明地球是一个球体(不是一个完美的球体)?最初的问题要求 WGS84 地球上各点之间的距离。不确定使用完美球体会产生多少误差,但我怀疑它可能会很大,具体取决于地球上各点的位置,因此值得牢记这一区别。
Haversine 公式没有说明地球是一个椭球体,因此您会因此而引入一些错误。它不能保证正确到优于 0.5%。不过,这可能是也可能不是可接受的错误级别。
是否有任何理由使用 Math.atan2(Math.sqrt(a), Math.sqrt(1-a)) 而不是 Math.asin(Math.sqrt(h)),这将是 Wikipedia 文章使用的公式的直接实现?它是否更有效和/或更稳定?
@UsmanMutawakil 好吧,您获得的 38 英里是在路上的距离。该算法计算地球表面上的直线距离。谷歌地图有一个距离工具(左下角,“实验室”)可以做同样的事情,用它来比较。
@Forte_201092:因为这不是必需的 - 因为 (sin(x))² 等于 (sin(-x))²
a
angleKH

我需要为我的项目计算很多点之间的距离,所以我继续尝试优化代码,我在这里找到了。平均而言,在不同的浏览器中,我的新实现的运行速度比最受好评的答案快 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, pi

def distance(lat1, lon1, lat2, lon2):
    p = 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


@AngularM,如果您要走一些道路而不是直线,谷歌很可能会计算距离。
谷歌计算行驶距离,这计算“乌鸦飞”
@Ouadie,它会提高速度吗?很可能没有,但对于那些在旧浏览器中复制粘贴的人来说,我最终会得到很多“你的东西不起作用”
是的,但是 // 2 * R; R = 6371 km 代表什么?当前的方法以公里或英里为单位提供答案?需要更好的文档。谢谢
@KhalilKhalaf 你是在开玩笑还是想在这里拖钓? km代表公里。你认为 R 代表什么(尤其是当我们谈论一个 shpere 时)?如果您已经看到公里,猜猜答案是什么单位。您在这里寻找什么样的文档:那里实际上有 4 行。
S
Stefan Steiger

这是一个 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;
    }

}

您使用的是赤道半径,但您应该使用平均半径,即 6371 公里
这不应该是 double dlon = Radians(lon2 - lon1);double dlat = Radians(lat2 - lat1);
我同意克里斯·马里西奇的观点。我使用了原始代码,计算错误。我添加了将增量转换为弧度的调用,它现在可以正常工作。我提交了一个编辑,正在等待它进行同行评审。
我提交了另一个编辑,因为 lat1 & lat2 也需要转换为弧度。我还将分配的公式修改为 a 以匹配此处找到的公式和代码:movable-type.co.uk/scripts/latlong.html
RADIUS 值是否需要像其他答案一样为 6371?
N
Nav

这是Haversine公式的Java实现。

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));
}

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


如果我们想以米为单位计算两点之间的距离,那么更准确的方法是什么?使用 6371000 作为地球的半径? (平均地球半径为 6371000 米)或从您的功能将公里转换为米?
如果您想要里程,将结果乘以 0.621371
D
Deduplicator

非常感谢这一切。我在我的 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;
}

我认为 pow(sin(dlat / 2), 2) + cos(convertToRadians(place1.latitude)) 周围的括号不正确。删除这些,结果与我在此页面上使用其他实现时得到的结果相匹配,或者从头开始实现 Wikipedia 中的 Haversine 公式。
使用 NYC 的坐标 (40.7127837, -74.0059413) 和 LA 的坐标 (34.052234, -118.243685),() 围绕该总和,我得到 3869.75。没有它们,我得到 3935.75,这几乎就是网络搜索出现的结果。
A
AbraCadaver

这是一个简单的 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;
}
?>

如前所述;地球不是一个球体。这就像马克·麦格威尔决定练习的一个古老的棒球——它充满了凹痕和凹凸。更简单的计算(像这样)把它当作一个球体。

根据您在这个不规则卵形上的位置以及您的点相距多远(它们越接近绝对误差范围越小),不同的方法可能或多或少地精确。你的期望越精确,数学就越复杂。

欲了解更多信息:wikipedia geographic distance


这完美!我刚刚添加了 $distance_miles = $km * 0.621371;这就是我所需要的以英里为单位的近似距离!谢谢托尼。
D
Deduplicator

我在这里发布我的工作示例。

列出表中指定点之间的所有点(我们使用随机点 - lat:45.20327, long:23.7806)小于 50 KM,在 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) 中进行了测试。


我认为一个好的方法可能是使用近似值对结果进行预过滤,因此重公式仅适用于某些情况。如果您有其他条件,则特别有用。我将它用于初始 aprox:stackoverflow.com/questions/1253499/…
J
Jaap

在其他答案中,缺少 中的实现。

使用 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
  b <- 2 * asin(pmin(1, sqrt(a))) 
  d = R * b
  return(d)
}

为了确保我清楚您所说的内容:您在帖子末尾给出的代码:这是文森蒂公式的实现吗?据您所知,它应该给出与在地圈中调用文森特相同的答案? [我没有 geosphere 或其他图书馆;只是在寻找一些代码以包含在跨平台应用程序中。我当然会根据已知的好计算器验证一些测试用例。]
@ToolmakerSteve 我答案末尾的函数是 Haversine 方法的实现
嗨@Jaap我能问一下公式的计量单位是什么吗?是米吗?
@Jaap我喜欢“椭圆体的文森蒂公式”的解释,我测试它非常准确。 @Jackson distm(p1, p2, fun = distVincentyEllipsoid) 以米为单位提供输出,您必须将其除以 1000 才能获得以公里为单位的值。
A
Arturo Hernandez

对于大多数情况,haversine 绝对是一个很好的公式,其他答案已经包含它,所以我不打算占用空间。但重要的是要注意,无论使用什么公式(不仅仅是一个)。因为可能的精度范围很大以及所需的计算时间。公式的选择比简单的简单答案需要更多的思考。

这篇来自美国国家航空航天局的人的帖子,是我在讨论选项时发现的最好的帖子

http://www.cs.nyu.edu/visual/home/proj/tiger/gisfaq.html

例如,如果您只是按 100 英里半径内的距离对行进行排序。平面地球公式将比半正弦公式快得多。

HalfPi = 1.5707963;
R = 3956; /* the radius gives you the measurement unit*/

a = HalfPi - latoriginrad;
b = HalfPi - latdestrad;
u = a * a + b * b;
v = - 2 * a * b * cos(longdestrad - longoriginrad);
c = sqrt(abs(u + v));
return R * c;

注意只有一个余弦和一个平方根。在 Haversine 公式中,其中有 9 个。


这是一个很好的可能性。请注意,讨论中建议的最大距离是 12 英里,而不是 100 英里,即便如此,误差可能会蔓延到 30 米(100 英尺),具体取决于地球的位置。
M
Meymann

可能有一个更简单、更正确的解决方案:地球的周长在赤道处为 40,000 公里,格林威治(或任何经度)周期约为 37,000 公里。因此:

pythagoras = function (lat1, lon1, lat2, lon2) {
   function sqr(x) {return x * x;}
   function cosDeg(x) {return Math.cos(x * Math.PI / 180.0);}

   var earthCyclePerimeter = 40000000.0 * cosDeg((lat1 + lat2) / 2.0);
   var dx = (lon1 - lon2) * earthCyclePerimeter / 360.0;
   var dy = 37000000.0 * (lat1 - lat2) / 360.0;

   return Math.sqrt(sqr(dx) + sqr(dy));
};

我同意它应该进行微调,因为我自己说过它是一个椭圆体,所以要乘以余弦的半径会有所不同。但它更准确一些。与谷歌地图相比,它确实显着减少了错误。


这个函数返回距离是公里吗?
这是因为赤道和经度循环以公里为单位。对于英里,只需将 40000 和 37000 除以 1.6。感觉怪怪的,您可以将其转换为 Ris,乘以大约 7 或转换为 parasang,除以 2.2 ;-)
这似乎是这里提供的最佳答案。我希望使用它,但我只是想知道是否有办法验证该算法的正确性。我测试了 f(50,5,58,3)。它给出了 832 公里,而使用“haversine”公式的 movable-type.co.uk/scripts/latlong.html 给出了 899 公里。有这么大的区别吗?
而且,我认为上面代码返回的值是m,而不是km。
这个公式中有一个不准确的数字。通过两极的周长是 6356.752 NASA * 2 Pi = 39940.651 公里。不是 37000。因此,正如 Chong 所见,纬度变化的答案很低。将“37000000.0”替换为“39940651.0”。有了这个修正,我的猜测是精确到 100 分之一,距离可达 1 度。 (未验证。)
K
Keerthana Gopalakrishnan

以上所有答案都假设地球是一个球体。然而,更准确的近似值是扁椭球体。

a= 6378.137#equitorial radius in km
b= 6356.752#polar radius in km

def Distance(lat1, lons1, lat2, lons2):
    lat1=math.radians(lat1)
    lons1=math.radians(lons1)
    R1=(((((a**2)*math.cos(lat1))**2)+(((b**2)*math.sin(lat1))**2))/((a*math.cos(lat1))**2+(b*math.sin(lat1))**2))**0.5 #radius of earth at lat1
    x1=R*math.cos(lat1)*math.cos(lons1)
    y1=R*math.cos(lat1)*math.sin(lons1)
    z1=R*math.sin(lat1)

    lat2=math.radians(lat2)
    lons2=math.radians(lons2)
    R1=(((((a**2)*math.cos(lat2))**2)+(((b**2)*math.sin(lat2))**2))/((a*math.cos(lat2))**2+(b*math.sin(lat2))**2))**0.5 #radius of earth at lat2
    x2=R*math.cos(lat2)*math.cos(lons2)
    y2=R*math.cos(lat2)*math.sin(lons2)
    z2=R*math.sin(lat2)

    return ((x1-x2)**2+(y1-y2)**2+(z1-z2)**2)**0.5

你能在你的公式中添加来源吗?
U
Uri

pip install haversine

Python 实现

起源是美国毗连的中心。

from haversine import haversine, Unit
origin = (39.50, 98.35)
paris = (48.8567, 2.3508)
haversine(origin, paris, unit=Unit.MILES)

要以公里为单位获得答案,只需设置 unit=Unit.KILOMETERS(这是默认设置)。


您正在导入一个完成所有工作的非标准包。我不知道这是否有用。
该包与 numpy 和 scikit-learn 一起作为 python 3 包在 PyPI(Python 包索引)中。不知道为什么将一个与包裹并列。它们往往非常有用。作为开源,人们还可以检查其中包含的方法。我想很多人会发现这个包很有用,所以尽管投反对票,我还是会离开这个帖子。干杯。 :)
它看起来很有用,但我想包含确切的 pip 命令来安装这个包。
S
Steven Christenson

我不喜欢添加另一个答案,但 Google maps API v.3 具有球面几何(以及更多)。将您的 WGS84 转换为十进制度后,您可以执行以下操作:

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

distance = google.maps.geometry.spherical.computeDistanceBetween(
    new google.maps.LatLng(fromLat, fromLng), 
    new google.maps.LatLng(toLat, toLng));

没有关于谷歌的计算有多准确甚至使用什么模型的消息(尽管它确实说“球形”而不是“大地水准面”。顺便说一句,如果一个人在这似乎是每个人都在推测的地球表面。


距离以米为单位。或者,可以使用 computeLength()
A
Andre Cytryn

您可以使用 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。


S
Sel

这是Haversine公式的打字稿实现

static getDistanceFromLatLonInKm(lat1: number, lon1: number, lat2: number, lon2: number): number {
    var deg2Rad = deg => {
        return deg * Math.PI / 180;
    }

    var r = 6371; // Radius of the earth in km
    var dLat = deg2Rad(lat2 - lat1);   
    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;
}

C
Chong Lip Phang

正如所指出的,准确的计算应该考虑到地球不是一个完美的球体。以下是此处提供的各种算法的一些比较:

geoDistance(50,5,58,3)
Haversine: 899 km
Maymenn: 833 km
Keerthana: 897 km
google.maps.geometry.spherical.computeDistanceBetween(): 900 km

geoDistance(50,5,-58,-3)
Haversine: 12030 km
Maymenn: 11135 km
Keerthana: 10310 km
google.maps.geometry.spherical.computeDistanceBetween(): 12044 km

geoDistance(.05,.005,.058,.003)
Haversine: 0.9169 km
Maymenn: 0.851723 km
Keerthana: 0.917964 km
google.maps.geometry.spherical.computeDistanceBetween(): 0.917964 km

geoDistance(.05,80,.058,80.3)
Haversine: 33.37 km
Maymenn: 33.34 km
Keerthana: 33.40767 km
google.maps.geometry.spherical.computeDistanceBetween(): 33.40770 km

在小范围内,Keerthana 的算法似乎与谷歌地图的算法一致。谷歌地图似乎没有遵循任何简单的算法,这表明它可能是这里最准确的方法。

无论如何,这是 Keerthana 算法的 Javascript 实现:

function geoDistance(lat1, lng1, lat2, lng2){
    const a = 6378.137; // equitorial radius in km
    const b = 6356.752; // polar radius in km

    var sq = x => (x*x);
    var sqr = x => Math.sqrt(x);
    var cos = x => Math.cos(x);
    var sin = x => Math.sin(x);
    var radius = lat => sqr((sq(a*a*cos(lat))+sq(b*b*sin(lat)))/(sq(a*cos(lat))+sq(b*sin(lat))));

    lat1 = lat1 * Math.PI / 180;
    lng1 = lng1 * Math.PI / 180;
    lat2 = lat2 * Math.PI / 180;
    lng2 = lng2 * Math.PI / 180;

    var R1 = radius(lat1);
    var x1 = R1*cos(lat1)*cos(lng1);
    var y1 = R1*cos(lat1)*sin(lng1);
    var z1 = R1*sin(lat1);

    var R2 = radius(lat2);
    var x2 = R2*cos(lat2)*cos(lng2);
    var y2 = R2*cos(lat2)*sin(lng2);
    var z2 = R2*sin(lat2);

    return sqr(sq(x1-x2)+sq(y1-y2)+sq(z1-z2));
}

K
Kiran Maniya

这是计算公里距离的SQL实现,

SELECT UserId, ( 3959 * acos( cos( radians( your latitude here ) ) * cos( radians(latitude) ) * 
cos( radians(longitude) - radians( your longitude here ) ) + sin( radians( your latitude here ) ) * 
sin( radians(latitude) ) ) ) AS distance FROM user HAVING
distance < 5  ORDER BY distance LIMIT 0 , 5;

有关通过编程语言实现的更多详细信息,您可以浏览给出的 php 脚本 here


E
Er.Subhendu Kumar Pati

这个脚本 [in PHP] 计算两点之间的距离。

public static function getDistanceOfTwoPoints($source, $dest, $unit='K') {
        $lat1 = $source[0];
        $lon1 = $source[1];
        $lat2 = $dest[0];
        $lon2 = $dest[1];

        $theta = $lon1 - $lon2;
        $dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) +  cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));
        $dist = acos($dist);
        $dist = rad2deg($dist);
        $miles = $dist * 60 * 1.1515;
        $unit = strtoupper($unit);

        if ($unit == "K") {
            return ($miles * 1.609344);
        }
        else if ($unit == "M")
        {
            return ($miles * 1.609344 * 1000);
        }
        else if ($unit == "N") {
            return ($miles * 0.8684);
        } 
        else {
            return $miles;
        }
    }

a
ak-j

根据Haversine公式的Java实现

double calculateDistance(double latPoint1, double lngPoint1, 
                         double latPoint2, double lngPoint2) {
    if(latPoint1 == latPoint2 && lngPoint1 == lngPoint2) {
        return 0d;
    }

    final double EARTH_RADIUS = 6371.0; //km value;

    //converting to radians
    latPoint1 = Math.toRadians(latPoint1);
    lngPoint1 = Math.toRadians(lngPoint1);
    latPoint2 = Math.toRadians(latPoint2);
    lngPoint2 = Math.toRadians(lngPoint2);

    double distance = Math.pow(Math.sin((latPoint2 - latPoint1) / 2.0), 2) 
            + Math.cos(latPoint1) * Math.cos(latPoint2)
            * Math.pow(Math.sin((lngPoint2 - lngPoint1) / 2.0), 2);
    distance = 2.0 * EARTH_RADIUS * Math.asin(Math.sqrt(distance));

    return distance; //km value
}

佚名

要计算球体上两点之间的距离,您需要执行 Great Circle calculation

如果您需要将距离重新投影到平面,有许多 C/C++ 库可帮助您在 MapTools 进行地图投影。为此,您将需要各种坐标系的投影字符串。

您还可以找到 MapWindow 一个有用的工具来可视化这些点。此外,作为它的开源,它是如何使用 proj.dll 库的有用指南,它似乎是核心开源投影库。


佚名

这是我在经过一些搜索后通过十进制度计算距离的java实现。我使用了以公里为单位的世界平均半径(来自维基百科)。如果你想要结果英里然后使用世界半径英里。

public static double distanceLatLong2(double lat1, double lng1, double lat2, double lng2) 
{
  double earthRadius = 6371.0d; // KM: use mile here if you want mile result

  double dLat = toRadian(lat2 - lat1);
  double dLng = toRadian(lng2 - lng1);

  double a = Math.pow(Math.sin(dLat/2), 2)  + 
          Math.cos(toRadian(lat1)) * Math.cos(toRadian(lat2)) * 
          Math.pow(Math.sin(dLng/2), 2);

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

  return earthRadius * c; // returns result kilometers
}

public static double toRadian(double degrees) 
{
  return (degrees * Math.PI) / 180.0d;
}

E
Eduardo Naveda

这是移植到 Java 的公认答案实现,以防万一有人需要它。

package com.project529.garage.util;


/**
 * Mean radius.
 */
private static double EARTH_RADIUS = 6371;

/**
 * Returns the distance between two sets of latitudes and longitudes in meters.
 * <p/>
 * Based from the following JavaScript SO answer:
 * http://stackoverflow.com/questions/27928/calculate-distance-between-two-latitude-longitude-points-haversine-formula,
 * which is based on https://en.wikipedia.org/wiki/Haversine_formula (error rate: ~0.55%).
 */
public double getDistanceBetween(double lat1, double lon1, double lat2, double lon2) {
    double dLat = toRadians(lat2 - lat1);
    double dLon = toRadians(lon2 - lon1);

    double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
            Math.cos(toRadians(lat1)) * Math.cos(toRadians(lat2)) *
                    Math.sin(dLon / 2) * Math.sin(dLon / 2);
    double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    double d = EARTH_RADIUS * c;

    return d;
}

public double toRadians(double degrees) {
    return degrees * (Math.PI / 180);
}

f
fla

这是 postgres sql 中的一个示例(以 km 为单位,对于英里版本,将 1.609344 替换为 0.8684 版本)

CREATE OR REPLACE FUNCTION public.geodistance(alat float, alng float, blat  

float, blng  float)
  RETURNS float AS
$BODY$
DECLARE
    v_distance float;
BEGIN

    v_distance = asin( sqrt(
            sin(radians(blat-alat)/2)^2 
                + (
                    (sin(radians(blng-alng)/2)^2) *
                    cos(radians(alat)) *
                    cos(radians(blat))
                )
          )
        ) * cast('7926.3352' as float) * cast('1.609344' as float) ;


    RETURN v_distance;
END 
$BODY$
language plpgsql VOLATILE SECURITY DEFINER;
alter function geodistance(alat float, alng float, blat float, blng float)
owner to postgres;

K
Korayem

对于那些寻找基于 WGS-84 和 GRS-80 标准的 Excel 公式的人:

=ACOS(COS(RADIANS(90-Lat1))*COS(RADIANS(90-Lat2))+SIN(RADIANS(90-Lat1))*SIN(RADIANS(90-Lat2))*COS(RADIANS(Long1-Long2)))*6371

Source


s
sourav karwa

我在 R 中创建了一个自定义函数,以使用 R 基础包中提供的函数计算两个空间点之间的半正弦距离(km)。

custom_hav_dist <- function(lat1, lon1, lat2, lon2) {
R <- 6371
Radian_factor <- 0.0174533
lat_1 <- (90-lat1)*Radian_factor
lat_2 <- (90-lat2)*Radian_factor
diff_long <-(lon1-lon2)*Radian_factor

distance_in_km <- 6371*acos((cos(lat_1)*cos(lat_2))+ 
                 (sin(lat_1)*sin(lat_2)*cos(diff_long)))
rm(lat1, lon1, lat2, lon2)
return(distance_in_km)
}

样本输出

custom_hav_dist(50.31,19.08,54.14,19.39)
[1] 426.3987

PS:要以英里为单位计算距离,请将函数 (6371) 中的 R 替换为 3958.756(对于海里,请使用 3440.065)。


如何计算速度?
该代码是关于计算两个地球静止空间点之间的距离。不明白为什么这里需要速度计算?
实际上,如果给出时间戳,我们可以计算速度,因为距离是使用公式计算的。但是如果有一分钟的间隔时间戳,并且我们想了解每 5 分钟间隔(任何车辆移动)的速度,我想知道该怎么做?
您可以进一步添加代码来计算速度,但在我的用例中,没有必要因此没有计算速度。很想听听你的方法是什么
a
ayalcinkaya

这里有一个很好的例子来计算 PHP http://www.geodatasource.com/developers/php 的距离:

 function distance($lat1, $lon1, $lat2, $lon2, $unit) {

     $theta = $lon1 - $lon2;
     $dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) +  cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));
     $dist = acos($dist);
     $dist = rad2deg($dist);
     $miles = $dist * 60 * 1.1515;
     $unit = strtoupper($unit);

     if ($unit == "K") {
         return ($miles * 1.609344);
     } else if ($unit == "N") {
          return ($miles * 0.8684);
     } else {
          return $miles;
     }
 }

T
Taiseer Joudeh

这是 VB.NET 的实现,此实现将根据您传递的 Enum 值为您提供 KM 或 Miles 的结果。

Public Enum DistanceType
    Miles
    KiloMeters
End Enum

Public Structure Position
    Public Latitude As Double
    Public Longitude As Double
End Structure

Public Class Haversine

    Public Function Distance(Pos1 As Position,
                             Pos2 As Position,
                             DistType As DistanceType) As Double

        Dim R As Double = If((DistType = DistanceType.Miles), 3960, 6371)

        Dim dLat As Double = Me.toRadian(Pos2.Latitude - Pos1.Latitude)

        Dim dLon As Double = Me.toRadian(Pos2.Longitude - Pos1.Longitude)

        Dim a As Double = Math.Sin(dLat / 2) * Math.Sin(dLat / 2) + Math.Cos(Me.toRadian(Pos1.Latitude)) * Math.Cos(Me.toRadian(Pos2.Latitude)) * Math.Sin(dLon / 2) * Math.Sin(dLon / 2)

        Dim c As Double = 2 * Math.Asin(Math.Min(1, Math.Sqrt(a)))

        Dim result As Double = R * c

        Return result

    End Function

    Private Function toRadian(val As Double) As Double

        Return (Math.PI / 180) * val

    End Function

End Class

在计算“a”时,你是否错误地写了两次 Math.Sin(dLat ..)?
K
Kache

我通过简化公式来压缩计算。

这是在 Ruby 中的:

include Math
earth_radius_mi = 3959
radians = lambda { |deg| deg * PI / 180 }
coord_radians = lambda { |c| { :lat => radians[c[:lat]], :lng => radians[c[:lng]] } }

# from/to = { :lat => (latitude_in_degrees), :lng => (longitude_in_degrees) }
def haversine_distance(from, to)
  from, to = coord_radians[from], coord_radians[to]
  cosines_product = cos(to[:lat]) * cos(from[:lat]) * cos(from[:lng] - to[:lng])
  sines_product = sin(to[:lat]) * sin(from[:lat])
  return earth_radius_mi * acos(cosines_product + sines_product)
end

M
MPaulo
function getDistanceFromLatLonInKm(lat1,lon1,lat2,lon2,units) {
  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; 
  var miles = d / 1.609344; 

if ( units == 'km' ) {  
return d; 
 } else {
return miles;
}}

Chuck 的解决方案,也适用于英里。


s
shanavascet

在 Mysql 中使用以下函数传递参数,如使用 POINT(LONG,LAT)

CREATE FUNCTION `distance`(a POINT, b POINT)
 RETURNS double
    DETERMINISTIC
BEGIN

RETURN

GLength( LineString(( PointFromWKB(a)), (PointFromWKB(b)))) * 100000; -- To Make the distance in meters

END;