1. 程式人生 > >計算兩個latitude-longitude點之間的距離? (Haversine公式)

計算兩個latitude-longitude點之間的距離? (Haversine公式)

org 程序 沒有 this rgs 完整 替換 5.5 self

問題描述

如何計算緯度和經度指定的兩點之間的距離?
為了澄清,我想要距離公裏;這些點使用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的長度和長度。非常,非常近,你做一個小的球形觸發,但糾正事實,地球不是一個球體,使公式更復雜。

參考文獻

  • Calculate distance between two latitude-longitude points? (Haversine formula)

註:本文內容整合自google/baidu/bing輔助翻譯的英文資料結果。如果您對結果不滿意,可以加入我們改善翻譯效果:gxnotes#qq.com(#替換為@)。

計算兩個latitude-longitude點之間的距離? (Haversine公式)