1057

緯度と経度で指定された 2 点間の距離を計算するにはどうすればよいですか?

明確にするために、距離をキロメートルでお願いします。ポイントは WGS84 システムを使用しており、利用可能なアプローチの相対的な精度を理解したいと思います。

4

48 に答える 48

1291

このリンクは、距離を計算するためのHaversine式の使用について詳しく説明しているため、役立つ場合があります。

抜粋:

このスクリプト[Javascript]は、「Haversine」式を使用して、2点間の大円距離(つまり、地表上の最短距離)を計算します。

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)
}
于 2008-08-26T12:55:53.030 に答える
75

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

}
于 2008-10-19T01:30:13.380 に答える
70

以下は、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));
}

ここでは、答えを最も近い km に丸めていることに注意してください。

于 2012-09-26T11:00:31.457 に答える
43

これまでありがとうございました。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;
}

緯度と経度は 10 進数です。私が使用している距離が非常に小さいため、asin() 呼び出しには min() を使用しませんでした。

ラジアンで値を渡すまで、間違った答えが返されました-今では、Appleのマップアプリから取得した値とほとんど同じです:-)

余分な更新:

iOS4 以降を使用している場合、Apple はこれを行うためのいくつかの方法を提供しているため、次の方法で同じ機能を実現できます。

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

    MKMapPoint  start, finish;


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

    return MKMetersBetweenMapPoints(start, finish) / 1000;
}
于 2010-12-07T13:56:51.290 に答える
41

これは単純な 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;
}
?>

前に言ったように; 地球は球体ではありません。それはマーク・マグワイアが練習することに決めた昔の古い野球のようなものです - それはへこみと隆起でいっぱいです. より単純な計算 (このような) では、球体のように扱われます。

この不規則な卵形のどこにいるか、およびポイントがどれだけ離れているかに応じて、さまざまな方法が多かれ少なかれ正確になる場合があります (それらが近ければ近いほど、絶対誤差マージンは小さくなります)。期待値が正確であるほど、計算は複雑になります。

詳細情報:ウィキペディアの地理的距離

于 2012-06-24T14:11:01.257 に答える
31

ここに私の作業例を投稿します。

指定されたポイント (ランダムなポイントを使用 - 緯度: 45.20327、経度: 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) でテストされました。

于 2012-03-12T23:37:29.810 に答える
30

の実装がありません。

パッケージのdistm関数を使用すると、2 点間の距離を簡単に計算できます。geosphere

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 式がおそらく距離を計算する最良の方法です。したがって、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)
}
于 2014-04-15T21:59:38.877 に答える
9

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(これがデフォルトです)。

于 2015-07-14T05:52:12.000 に答える
9

上記のすべての答えは、地球が球体であることを前提としています。ただし、より正確な近似は、扁平回転楕円体の近似になります。

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
于 2016-06-16T22:25:37.767 に答える
8

さらに別の回答を追加するのは好きではありませんが、Google マップ API v.3 には球状のジオメトリ (およびその他) があります。WGS84 を 10 進度に変換した後、次の操作を実行できます。

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

Google の計算がどれほど正確であるか、またどのモデルが使用されているかについては何も言われていません (ただし、「ジオイド」ではなく「球状」と書かれています。ちなみに、「直線」距離は、人が地球上を移動する場合の距離とは明らかに異なります。誰もが推測しているように見える地球の表面。

于 2014-07-20T00:10:07.003 に答える
6

これは、Haversine 式のtypescript実装です。

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;
}
于 2015-12-12T15:59:02.940 に答える
6

これは、距離を km で計算するための 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 スクリプトを参照してください。

于 2018-10-09T10:14:42.723 に答える
3

球上の2点間の距離を計算するには、大円の計算を行う必要があります。

平面への距離を再投影する必要がある場合に、 MapToolsでの地図投影に役立つC /C++ライブラリがいくつかあります。これを行うには、さまざまな座標系の投影文字列が必要になります。

MapWindowは、ポイントを視覚化するための便利なツールでもあります。また、そのオープンソースとして、コアオープンソースプロジェクションライブラリのように見えるproj.dllライブラリの使用方法に関する便利なガイドです。

于 2008-10-19T01:30:09.213 に答える
3

これは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;
于 2016-12-21T07:34:02.520 に答える
3

誰かがそれを必要とする場合に備えて、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);
}
于 2015-10-12T20:59:53.627 に答える
3

Rベースパッケージで利用可能な関数を使用して、2つの空間ポイント間のhaversine distance(km)を計算するRでカスタム関数を作成しました。

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 を使用します)。

于 2020-10-05T18:12:09.727 に答える
2

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;
于 2014-05-28T08:59:44.193 に答える
2

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;
     }
 }
于 2013-01-15T01:48:23.067 に答える
2
function getDistanceFromLatLonInKm(position1, position2) {
    "use strict";
    var deg2rad = function (deg) { return deg * (Math.PI / 180); },
        R = 6371,
        dLat = deg2rad(position2.lat - position1.lat),
        dLng = deg2rad(position2.lng - position1.lng),
        a = Math.sin(dLat / 2) * Math.sin(dLat / 2)
            + Math.cos(deg2rad(position1.lat))
            * Math.cos(deg2rad(position2.lat))
            * Math.sin(dLng / 2) * Math.sin(dLng / 2),
        c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    return R * c;
}

console.log(getDistanceFromLatLonInKm(
    {lat: 48.7931459, lng: 1.9483572},
    {lat: 48.827167, lng: 2.2459745}
));
于 2015-04-29T14:22:25.870 に答える
2
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;
}}

マイルにも有効なチャックのソリューション。

于 2013-11-08T06:34:35.100 に答える
0
//JAVA
    public Double getDistanceBetweenTwoPoints(Double latitude1, Double longitude1, Double latitude2, Double longitude2) {
    final int RADIUS_EARTH = 6371;

    double dLat = getRad(latitude2 - latitude1);
    double dLong = getRad(longitude2 - longitude1);

    double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(getRad(latitude1)) * Math.cos(getRad(latitude2)) * Math.sin(dLong / 2) * Math.sin(dLong / 2);
    double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    return (RADIUS_EARTH * c) * 1000;
    }

    private Double getRad(Double x) {
    return x * Math.PI / 180;
    }
于 2014-06-05T10:46:18.170 に答える