2つのGPS座標間の距離を計算する


回答:


406

JavaScriptの実装を含め、緯度と経度2つの座標間の距離を計算します。

西南の場所はマイナスです。分と秒は60から外れるので、S31 30 'は-31.50度です。

度をラジアン変換することを忘れないでください。多くの言語がこの機能を備えています。またはその簡単な計算:radians = degrees * PI / 180

function degreesToRadians(degrees) {
  return degrees * Math.PI / 180;
}

function distanceInKmBetweenEarthCoordinates(lat1, lon1, lat2, lon2) {
  var earthRadiusKm = 6371;

  var dLat = degreesToRadians(lat2-lat1);
  var dLon = degreesToRadians(lon2-lon1);

  lat1 = degreesToRadians(lat1);
  lat2 = degreesToRadians(lat2);

  var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
          Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2); 
  var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 
  return earthRadiusKm * c;
}

次に使用例をいくつか示します。

distanceInKmBetweenEarthCoordinates(0,0,0,0)  // Distance between same 
                                              // points should be 0
0

distanceInKmBetweenEarthCoordinates(51.5, 0, 38.8, -77.1) // From London
                                                          // to Arlington
5918.185064088764

17
はっきりしない場合は、toRad()メソッドは次のようなNumberプロトタイプのカスタマイズですNumber.prototype.toRad = function() { return this * (Math.PI / 180); }; 。または、以下に示すように、(Math.PI/2)パフォーマンスを向上させるために0.0174532925199433(...必要と思われる精度であれば何でも)に置き換えることができます。
Vinney Kelly 2013

44
誰か、特に行末のコメントを探していない人がこの公式を凝視して距離の単位を探している場合、その単位はkmです。:)
ディランノウルズ

1
@VinneyKellyの小さなタイプミスですが、(Math.PI / 2)ではなく(Math.PI / 180)に置き換えてください。みんなの助けに感謝
Patrick Murphy

1
@ChristianKRider最初の行を見てください。R数学における通常の意味について考え、関連する地球関連の量を調べて、数値が一致するかどうかを確認します。
モニカの訴訟に資金

3
帝国単位(マイル)のためには、変更される可能性がearthRadiusKmあることをvar earthRadiusMiles = 3959;FYI、。
chapeljuice 2017

59

Googleでhasrsineを探してください。これが私の解決策です:

#include <math.h>
#include "haversine.h"

#define d2r (M_PI / 180.0)

//calculate haversine distance for linear distance
double haversine_km(double lat1, double long1, double lat2, double long2)
{
    double dlong = (long2 - long1) * d2r;
    double dlat = (lat2 - lat1) * d2r;
    double a = pow(sin(dlat/2.0), 2) + cos(lat1*d2r) * cos(lat2*d2r) * pow(sin(dlong/2.0), 2);
    double c = 2 * atan2(sqrt(a), sqrt(1-a));
    double d = 6367 * c;

    return d;
}

double haversine_mi(double lat1, double long1, double lat2, double long2)
{
    double dlong = (long2 - long1) * d2r;
    double dlat = (lat2 - lat1) * d2r;
    double a = pow(sin(dlat/2.0), 2) + cos(lat1*d2r) * cos(lat2*d2r) * pow(sin(dlong/2.0), 2);
    double c = 2 * atan2(sqrt(a), sqrt(1-a));
    double d = 3956 * c; 

    return d;
}

3
(M_PI / 180.0)を0.0174532925199433に置き換えると、パフォーマンスが向上します。
Hlung 2011

3
パフォーマンスの点では、sin(dlat / 2.0)を1回だけ計算し、それを変数a1に格納できます。pow(、2)の代わりに、a1 * a1を使用するのがはるかに優れています。他のpow(、2)も同じです。
pms

71
そう、あるいは60年代以降のコンパイラを使用するだけです。
2014年

17
コンテキストなしでは誰も理解できない定数に「最適化」する必要はありません(M_PI / 180.0)。コンパイラーはこれらの固定項を計算します!
Patrick Cornelissen

2
@TõnuSamuelコメントありがとうございます。ほんとうにありがとう。最適化を有効にしたコンパイラ(-O)は定数の演算を事前に計算できるため、手動での折りたたみは役に立たないのは当然です。時間があるときに試してみます。
Hlung

44

HaversineのC#バージョン

double _eQuatorialEarthRadius = 6378.1370D;
double _d2r = (Math.PI / 180D);

private int HaversineInM(double lat1, double long1, double lat2, double long2)
{
    return (int)(1000D * HaversineInKM(lat1, long1, lat2, long2));
}

private double HaversineInKM(double lat1, double long1, double lat2, double long2)
{
    double dlong = (long2 - long1) * _d2r;
    double dlat = (lat2 - lat1) * _d2r;
    double a = Math.Pow(Math.Sin(dlat / 2D), 2D) + Math.Cos(lat1 * _d2r) * Math.Cos(lat2 * _d2r) * Math.Pow(Math.Sin(dlong / 2D), 2D);
    double c = 2D * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1D - a));
    double d = _eQuatorialEarthRadius * c;

    return d;
}

これが.NETフィドルです。独自の緯度/経度でテストできます。


1
私はまた、人々が簡単にこれをテストできるように、気の利いた.NETフィドルを追加しました。
Pure.Krome 2014

7
.Net Frameworkには、GeoCoordinate.GetDistanceToメソッドが組み込まれています。アセンブリSystem.Deviceを参照する必要があります。MSDNの記事msdn.microsoft.com/en-us/library/...
FNX

27

このスレッドへのRoman Makarovの返信に基づくHaversineアルゴリズムのJavaバージョン

public class HaversineAlgorithm {

    static final double _eQuatorialEarthRadius = 6378.1370D;
    static final double _d2r = (Math.PI / 180D);

    public static int HaversineInM(double lat1, double long1, double lat2, double long2) {
        return (int) (1000D * HaversineInKM(lat1, long1, lat2, long2));
    }

    public static double HaversineInKM(double lat1, double long1, double lat2, double long2) {
        double dlong = (long2 - long1) * _d2r;
        double dlat = (lat2 - lat1) * _d2r;
        double a = Math.pow(Math.sin(dlat / 2D), 2D) + Math.cos(lat1 * _d2r) * Math.cos(lat2 * _d2r)
                * Math.pow(Math.sin(dlong / 2D), 2D);
        double c = 2D * Math.atan2(Math.sqrt(a), Math.sqrt(1D - a));
        double d = _eQuatorialEarthRadius * c;

        return d;
    }

}

@Raduは、それを正しく使用していることを確認し、メソッドに渡すときに緯度/経度の場所を交換しないようにします。
Paulo Miguel Almeida

1
私はこの式を使用してかなり近い答えを得ました。私はこのウェブサイトを使用して精度をベースにしました:moveable-type.co.uk/scripts/latlong.htmlこれは0.07149kmを与えまし0.07156たが、あなたの公式は約99%の精度を与えました
Janac Meena

24

これは、SQL Server 2008の地理タイプを使用すると非常に簡単です。

SELECT geography::Point(lat1, lon1, 4326).STDistance(geography::Point(lat2, lon2, 4326))
-- computes distance in meters using eliptical model, accurate to the mm

4326はWGS84楕円体地球モデルのSRIDです


19

これが私が使っているPythonのHaversine関数です:

from math import pi,sqrt,sin,cos,atan2

def haversine(pos1, pos2):
    lat1 = float(pos1['lat'])
    long1 = float(pos1['long'])
    lat2 = float(pos2['lat'])
    long2 = float(pos2['long'])

    degree_to_rad = float(pi / 180.0)

    d_lat = (lat2 - lat1) * degree_to_rad
    d_long = (long2 - long1) * degree_to_rad

    a = pow(sin(d_lat / 2), 2) + cos(lat1 * degree_to_rad) * cos(lat2 * degree_to_rad) * pow(sin(d_long / 2), 2)
    c = 2 * atan2(sqrt(a), sqrt(1 - a))
    km = 6367 * c
    mi = 3956 * c

    return {"km":km, "miles":mi}

16

ピンポイントの精度が必要な場合は、どれほど正確である必要があるかによって異なりますが、Vincentyのアルゴリズムのように球ではなく楕円を使用するアルゴリズムを検討するのが最適です。http://en.wikipedia.org/wiki/Vincenty%27s_algorithm


11

ここでは、C#(ラジアンでの緯度と経度)で示しています。

double CalculateGreatCircleDistance(double lat1, double long1, double lat2, double long2, double radius)
{
    return radius * Math.Acos(
        Math.Sin(lat1) * Math.Sin(lat2)
        + Math.Cos(lat1) * Math.Cos(lat2) * Math.Cos(long2 - long1));
}

緯度と経度が度単位の場合は、180 / PIで除算してラジアンに変換します。


1
これは「余弦の球の法則」の計算であり、大円の距離を計算する最も正確でなく、エラーが発生しやすい方法です。
John Machin 2017年

11

プロジェクトのポイント間の多くの距離を計算する必要があったので、先に進んでコードを最適化しようとしましたが、ここで見つかりました。さまざまなブラウザーで平均して、私の新しい実装は最も支持されている回答の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で遊んで、結果をここで確認できます

最近私は同じことをpythonで行う必要があったので、ここにpython実装があります

from math import cos, asin, sqrt
def distance(lat1, lon1, lat2, lon2):
    p = 0.017453292519943295
    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))

そして、完全を期すために、WikiのHaversine


11

PHPバージョン:

deg2rad()座標が既にラジアンの場合は、すべて削除してください。)

$R = 6371; // km
$dLat = deg2rad($lat2-$lat1);
$dLon = deg2rad($lon2-$lon1);
$lat1 = deg2rad($lat1);
$lat2 = deg2rad($lat2);

$a = sin($dLat/2) * sin($dLat/2) +
     sin($dLon/2) * sin($dLon/2) * cos($lat1) * cos($lat2); 

$c = 2 * atan2(sqrt($a), sqrt(1-$a)); 
$d = $R * $c;

1
lat1とlat2を$ lat1 nad $ lat2に変更してください。
代わりに

7

中心の距離でレコードを選択するために使用するT-SQL関数

Create Function  [dbo].[DistanceInMiles] 
 (  @fromLatitude float ,
    @fromLongitude float ,
    @toLatitude float, 
    @toLongitude float
  )
   returns float
AS 
BEGIN
declare @distance float

select @distance = cast((3963 * ACOS(round(COS(RADIANS(90-@fromLatitude))*COS(RADIANS(90-@toLatitude))+ 
SIN(RADIANS(90-@fromLatitude))*SIN(RADIANS(90-@toLatitude))*COS(RADIANS(@fromLongitude-@toLongitude)),15)) 
)as float) 
  return  round(@distance,1)
END

これは「余弦の球の法則」の計算であり、大円の距離を計算する最も正確でなく、エラーが発生しやすい方法です。
John Machin 2017年

5

あなたはより正確なものが必要なら、持ってこれを見て

ビンセンティの公式は、測地学で使用される2つの関連する反復法であり、回転楕円体の表面上の2点間の距離を計算します。これは、Thaddeus Vincenty(1975a)によって開発されました。大圏距離など、球体地球を想定した方法よりも正確です。

最初の(直接)メソッドは、別のポイントからの距離と方位角(方向)であるポイントの位置を計算します。2番目の(逆)メソッドは、2つの指定されたポイント間の地理的な距離と方位角を計算します。それらは地球の楕円体上で0.5 mm(0.020インチ)以内の精度であるため、測地学で広く使用されています。


5

I.「ブレッドクラム」法について

  1. 地球の半径は、緯度によって異なります。これは、Haversineアルゴリズムで考慮する必要があります。
  2. 直線をアーチ(より長い)に変えるベアリングの変更を検討してください
  3. 速度の変化を考慮すると、アーチがスパイラルに変わります(アーチよりも長いか短い)。
  4. 高度を変更すると、フラットスパイラルが3Dスパイラルに変わります(これもまた長くなります)。これは丘陵地帯では非常に重要です。

以下は、#1と#2を考慮したCの関数を示しています。

double   calcDistanceByHaversine(double rLat1, double rLon1, double rHeading1,
       double rLat2, double rLon2, double rHeading2){
  double rDLatRad = 0.0;
  double rDLonRad = 0.0;
  double rLat1Rad = 0.0;
  double rLat2Rad = 0.0;
  double a = 0.0;
  double c = 0.0;
  double rResult = 0.0;
  double rEarthRadius = 0.0;
  double rDHeading = 0.0;
  double rDHeadingRad = 0.0;

  if ((rLat1 < -90.0) || (rLat1 > 90.0) || (rLat2 < -90.0) || (rLat2 > 90.0)
              || (rLon1 < -180.0) || (rLon1 > 180.0) || (rLon2 < -180.0)
              || (rLon2 > 180.0)) {
        return -1;
  };

  rDLatRad = (rLat2 - rLat1) * DEGREE_TO_RADIANS;
  rDLonRad = (rLon2 - rLon1) * DEGREE_TO_RADIANS;
  rLat1Rad = rLat1 * DEGREE_TO_RADIANS;
  rLat2Rad = rLat2 * DEGREE_TO_RADIANS;

  a = sin(rDLatRad / 2) * sin(rDLatRad / 2) + sin(rDLonRad / 2) * sin(
              rDLonRad / 2) * cos(rLat1Rad) * cos(rLat2Rad);

  if (a == 0.0) {
        return 0.0;
  }

  c = 2 * atan2(sqrt(a), sqrt(1 - a));
  rEarthRadius = 6378.1370 - (21.3847 * 90.0 / ((fabs(rLat1) + fabs(rLat2))
              / 2.0));
  rResult = rEarthRadius * c;

  // Chord to Arc Correction based on Heading changes. Important for routes with many turns and U-turns

  if ((rHeading1 >= 0.0) && (rHeading1 < 360.0) && (rHeading2 >= 0.0)
              && (rHeading2 < 360.0)) {
        rDHeading = fabs(rHeading1 - rHeading2);
        if (rDHeading > 180.0) {
              rDHeading -= 180.0;
        }
        rDHeadingRad = rDHeading * DEGREE_TO_RADIANS;
        if (rDHeading > 5.0) {
              rResult = rResult * (rDHeadingRad / (2.0 * sin(rDHeadingRad / 2)));
        } else {
              rResult = rResult / cos(rDHeadingRad);
        }
  }
  return rResult;
}

II。かなり良い結果を与える簡単な方法があります。

平均速度で。

Trip_distance = Trip_average_speed * Trip_time

GPS速度はドップラー効果によって検出され、[Lon、Lat]に直接関係しないため、主な距離計算方法としてではなくても、少なくともセカンダリ(バックアップまたは補正)と見なすことができます。


4

.NETを使用している場合は、ホイールを再設定しないでください。System.Device.Locationを参照してください。別の回答のコメントでfnxへのクレジット。

using System.Device.Location;

double lat1 = 45.421527862548828D;
double long1 = -75.697189331054688D;
double lat2 = 53.64135D;
double long2 = -113.59273D;

GeoCoordinate geo1 = new GeoCoordinate(lat1, long1);
GeoCoordinate geo2 = new GeoCoordinate(lat2, long2);

double distance = geo1.GetDistanceTo(geo2);

3

このLuaコードは、ウィキペディアとRobert LipeのGPSbabelツールにあるものを改変したものです。

local EARTH_RAD = 6378137.0 
  -- earth's radius in meters (official geoid datum, not 20,000km / pi)

local radmiles = EARTH_RAD*100.0/2.54/12.0/5280.0;
  -- earth's radius in miles

local multipliers = {
  radians = 1, miles = radmiles, mi = radmiles, feet = radmiles * 5280,
  meters = EARTH_RAD, m = EARTH_RAD, km = EARTH_RAD / 1000, 
  degrees = 360 / (2 * math.pi), min = 60 * 360 / (2 * math.pi)
}

function gcdist(pt1, pt2, units) -- return distance in radians or given units
  --- this formula works best for points close together or antipodal
  --- rounding error strikes when distance is one-quarter Earth's circumference
  --- (ref: wikipedia Great-circle distance)
  if not pt1.radians then pt1 = rad(pt1) end
  if not pt2.radians then pt2 = rad(pt2) end
  local sdlat = sin((pt1.lat - pt2.lat) / 2.0);
  local sdlon = sin((pt1.lon - pt2.lon) / 2.0);
  local res = sqrt(sdlat * sdlat + cos(pt1.lat) * cos(pt2.lat) * sdlon * sdlon);
  res = res > 1 and 1 or res < -1 and -1 or res
  res = 2 * asin(res);
  if units then return res * assert(multipliers[units])
  else return res
  end
end

3
    private double deg2rad(double deg)
    {
        return (deg * Math.PI / 180.0);
    }

    private double rad2deg(double rad)
    {
        return (rad / Math.PI * 180.0);
    }

    private double GetDistance(double lat1, double lon1, double lat2, double lon2)
    {
        //code for Distance in Kilo Meter
        double theta = lon1 - lon2;
        double dist = Math.Sin(deg2rad(lat1)) * Math.Sin(deg2rad(lat2)) + Math.Cos(deg2rad(lat1)) * Math.Cos(deg2rad(lat2)) * Math.Cos(deg2rad(theta));
        dist = Math.Abs(Math.Round(rad2deg(Math.Acos(dist)) * 60 * 1.1515 * 1.609344 * 1000, 0));
        return (dist);
    }

    private double GetDirection(double lat1, double lon1, double lat2, double lon2)
    {
        //code for Direction in Degrees
        double dlat = deg2rad(lat1) - deg2rad(lat2);
        double dlon = deg2rad(lon1) - deg2rad(lon2);
        double y = Math.Sin(dlon) * Math.Cos(lat2);
        double x = Math.Cos(deg2rad(lat1)) * Math.Sin(deg2rad(lat2)) - Math.Sin(deg2rad(lat1)) * Math.Cos(deg2rad(lat2)) * Math.Cos(dlon);
        double direct = Math.Round(rad2deg(Math.Atan2(y, x)), 0);
        if (direct < 0)
            direct = direct + 360;
        return (direct);
    }

    private double GetSpeed(double lat1, double lon1, double lat2, double lon2, DateTime CurTime, DateTime PrevTime)
    {
        //code for speed in Kilo Meter/Hour
        TimeSpan TimeDifference = CurTime.Subtract(PrevTime);
        double TimeDifferenceInSeconds = Math.Round(TimeDifference.TotalSeconds, 0);
        double theta = lon1 - lon2;
        double dist = Math.Sin(deg2rad(lat1)) * Math.Sin(deg2rad(lat2)) + Math.Cos(deg2rad(lat1)) * Math.Cos(deg2rad(lat2)) * Math.Cos(deg2rad(theta));
        dist = rad2deg(Math.Acos(dist)) * 60 * 1.1515 * 1.609344;
        double Speed = Math.Abs(Math.Round((dist / Math.Abs(TimeDifferenceInSeconds)) * 60 * 60, 0));
        return (Speed);
    }

    private double GetDuration(DateTime CurTime, DateTime PrevTime)
    {
        //code for speed in Kilo Meter/Hour
        TimeSpan TimeDifference = CurTime.Subtract(PrevTime);
        double TimeDifferenceInSeconds = Math.Abs(Math.Round(TimeDifference.TotalSeconds, 0));
        return (TimeDifferenceInSeconds);
    }

1
GetDistance関数はメートル単位で値を返すと思います
Przemek

これは正しいです?GetDirection()は「dlat」を利用しません。
gubby

3

これは、MySQLとキロメートルに対応した「Henry Vilinskiy」のバージョンです。

CREATE FUNCTION `CalculateDistanceInKm`(
  fromLatitude float,
  fromLongitude float,
  toLatitude float, 
  toLongitude float
) RETURNS float
BEGIN
  declare distance float;

  select 
    6367 * ACOS(
            round(
              COS(RADIANS(90-fromLatitude)) *
                COS(RADIANS(90-toLatitude)) +
                SIN(RADIANS(90-fromLatitude)) *
                SIN(RADIANS(90-toLatitude)) *
                COS(RADIANS(fromLongitude-toLongitude))
              ,15)
            )
    into distance;

  return  round(distance,3);
END;

MySQLと述べたSomething is wrong in your syntax near '' on line 8 // declare distance float;
Legionar 14

これは「コサインの球面法則」計算であり、大円距離の計算の最も正確でなく、エラーが発生しやすい方法です
John Machin

3

これが答えからのSwift実装です

func degreesToRadians(degrees: Double) -> Double {
    return degrees * Double.pi / 180
}

func distanceInKmBetweenEarthCoordinates(lat1: Double, lon1: Double, lat2: Double, lon2: Double) -> Double {

    let earthRadiusKm: Double = 6371

    let dLat = degreesToRadians(degrees: lat2 - lat1)
    let dLon = degreesToRadians(degrees: lon2 - lon1)

    let lat1 = degreesToRadians(degrees: lat1)
    let lat2 = degreesToRadians(degrees: lat2)

    let a = sin(dLat/2) * sin(dLat/2) +
    sin(dLon/2) * sin(dLon/2) * cos(lat1) * cos(lat2)
    let c = 2 * atan2(sqrt(a), sqrt(1 - a))
    return earthRadiusKm * c
}

3

私はトップアンサーを選び、それをScalaプログラムで使用しました

import java.lang.Math.{atan2, cos, sin, sqrt}

def latLonDistance(lat1: Double, lon1: Double)(lat2: Double, lon2: Double): Double = {
    val earthRadiusKm = 6371
    val dLat = (lat2 - lat1).toRadians
    val dLon = (lon2 - lon1).toRadians
    val latRad1 = lat1.toRadians
    val latRad2 = lat2.toRadians

    val a = sin(dLat / 2) * sin(dLat / 2) + sin(dLon / 2) * sin(dLon / 2) * cos(latRad1) * cos(latRad2)
    val c = 2 * atan2(sqrt(a), sqrt(1 - a))
    earthRadiusKm * c
}

2つの位置の1つが固定され、距離を生成するために緯度/経度のペアのみを必要とする関数を簡単に生成できるように、関数をカレーしました。


2

地球の曲率に沿ってそれが欲しいと思います。あなたの2点と地球の中心は平面上にあります。地球の中心は、その平面上の円の中心であり、2つの点は(おおよそ)その円の周囲にあります。そこから、ある点から他の点までの角度が何であるかを見つけることにより、距離を計算できます。

ポイントが同じ高さではない場合、または地球が完全な球体ではないことを考慮する必要がある場合は、もう少し難しくなります。


2

私は最近同じことをしなければなりませんでした。私が見つかりました。このウェブサイトは、一緒に従うことは簡単だった例を用いて球状三角関数を説明する非常に有用であることを。


2

あなたはに(いくつかの良い説明と)これの実装を見つけることができるのF#fssnip

ここに重要な部分があります:


let GreatCircleDistance<[<Measure>] 'u> (R : float<'u>) (p1 : Location) (p2 : Location) =
    let degToRad (x : float<deg>) = System.Math.PI * x / 180.0<deg/rad>

    let sq x = x * x
    // take the sin of the half and square the result
    let sinSqHf (a : float<rad>) = (System.Math.Sin >> sq) (a / 2.0<rad>)
    let cos (a : float<deg>) = System.Math.Cos (degToRad a / 1.0<rad>)

    let dLat = (p2.Latitude - p1.Latitude) |> degToRad
    let dLon = (p2.Longitude - p1.Longitude) |> degToRad

    let a = sinSqHf dLat + cos p1.Latitude * cos p2.Latitude * sinSqHf dLon
    let c = 2.0 * System.Math.Atan2(System.Math.Sqrt(a), System.Math.Sqrt(1.0-a))

    R * c

2

これをPowerShellに実装する必要がありました。他の人の役に立つことを願っています。この方法についての注意事項

  1. 行を分割しないでください。分割すると、計算が間違ってしまいます
  2. KMで計算するには、$ distanceの計算で* 1000を削除します
  3. $ earthsRadius = 3963.19059を変更し、$ distanceの計算で* 1000を削除して、距離をマイルで計算します
  4. 他の投稿でヴィンセンティの式の方がはるかに正確であると指摘しているので、私はHaversineを使用しています

    Function MetresDistanceBetweenTwoGPSCoordinates($latitude1, $longitude1, $latitude2, $longitude2)  
    {  
      $Rad = ([math]::PI / 180);  
    
      $earthsRadius = 6378.1370 # Earth's Radius in KM  
      $dLat = ($latitude2 - $latitude1) * $Rad  
      $dLon = ($longitude2 - $longitude1) * $Rad  
      $latitude1 = $latitude1 * $Rad  
      $latitude2 = $latitude2 * $Rad  
    
      $a = [math]::Sin($dLat / 2) * [math]::Sin($dLat / 2) + [math]::Sin($dLon / 2) * [math]::Sin($dLon / 2) * [math]::Cos($latitude1) * [math]::Cos($latitude2)  
      $c = 2 * [math]::ATan2([math]::Sqrt($a), [math]::Sqrt(1-$a))  
    
      $distance = [math]::Round($earthsRadius * $c * 1000, 0) #Multiple by 1000 to get metres  
    
      Return $distance  
    }
    

2

Scalaバージョン

  def deg2rad(deg: Double) = deg * Math.PI / 180.0

  def rad2deg(rad: Double) = rad / Math.PI * 180.0

  def getDistanceMeters(lat1: Double, lon1: Double, lat2: Double, lon2: Double) = {
    val theta = lon1 - lon2
    val dist = Math.sin(deg2rad(lat1)) * Math.sin(deg2rad(lat2)) + Math.cos(deg2rad(lat1)) *
      Math.cos(deg2rad(lat2)) * Math.cos(deg2rad(theta))
    Math.abs(
      Math.round(
        rad2deg(Math.acos(dist)) * 60 * 1.1515 * 1.609344 * 1000)
    )
  }

1

//たぶんタイプミス?
GetDirectionに未使用の変数dlonがあると
思います

double y = Math.Sin(dlon) * Math.Cos(lat2);
// cannot use degrees in Cos ?

する必要があります

double y = Math.Sin(dlon) * Math.Cos(dlat);

1
これは答えではなく、せいぜいコメントです。
ケビン

1

これがエリクサーでの私の実装です

defmodule Geo do
  @earth_radius_km 6371
  @earth_radius_sm 3958.748
  @earth_radius_nm 3440.065
  @feet_per_sm 5280

  @d2r :math.pi / 180

  def deg_to_rad(deg), do: deg * @d2r

  def great_circle_distance(p1, p2, :km), do: haversine(p1, p2) * @earth_radius_km
  def great_circle_distance(p1, p2, :sm), do: haversine(p1, p2) * @earth_radius_sm
  def great_circle_distance(p1, p2, :nm), do: haversine(p1, p2) * @earth_radius_nm
  def great_circle_distance(p1, p2, :m), do: great_circle_distance(p1, p2, :km) * 1000
  def great_circle_distance(p1, p2, :ft), do: great_circle_distance(p1, p2, :sm) * @feet_per_sm

  @doc """
  Calculate the [Haversine](https://en.wikipedia.org/wiki/Haversine_formula)
  distance between two coordinates. Result is in radians. This result can be
  multiplied by the sphere's radius in any unit to get the distance in that unit.
  For example, multiple the result of this function by the Earth's radius in
  kilometres and you get the distance between the two given points in kilometres.
  """
  def haversine({lat1, lon1}, {lat2, lon2}) do
    dlat = deg_to_rad(lat2 - lat1)
    dlon = deg_to_rad(lon2 - lon1)

    radlat1 = deg_to_rad(lat1)
    radlat2 = deg_to_rad(lat2)

    a = :math.pow(:math.sin(dlat / 2), 2) +
        :math.pow(:math.sin(dlon / 2), 2) *
        :math.cos(radlat1) * :math.cos(radlat2)

    2 * :math.atan2(:math.sqrt(a), :math.sqrt(1 - a))
  end
end

1

ダートバージョン

Haversineアルゴリズム。

import 'dart:math';

class GeoUtils {

  static double _degreesToRadians(degrees) {
    return degrees * pi / 180;
  }

  static double distanceInKmBetweenEarthCoordinates(lat1, lon1, lat2, lon2) {
    var earthRadiusKm = 6371;

    var dLat = _degreesToRadians(lat2-lat1);
    var dLon = _degreesToRadians(lon2-lon1);

    lat1 = _degreesToRadians(lat1);
    lat2 = _degreesToRadians(lat2);

    var a = sin(dLat/2) * sin(dLat/2) +
        sin(dLon/2) * sin(dLon/2) * cos(lat1) * cos(lat2);
    var c = 2 * atan2(sqrt(a), sqrt(1-a));
    return earthRadiusKm * c;
  }
}

0

Rのアルゴリズムのバージョンはまだ欠けていると思います:

gpsdistance<-function(lat1,lon1,lat2,lon2){

# internal function to change deg to rad

degreesToRadians<- function (degrees) {
return (degrees * pi / 180)
}

R<-6371e3  #radius of Earth in meters

phi1<-degreesToRadians(lat1) # latitude 1
phi2<-degreesToRadians(lat2) # latitude 2
lambda1<-degreesToRadians(lon1) # longitude 1
lambda2<-degreesToRadians(lon2) # longitude 2

delta_phi<-phi1-phi2 # latitude-distance
delta_lambda<-lambda1-lambda2 # longitude-distance

a<-sin(delta_phi/2)*sin(delta_phi/2)+
cos(phi1)*cos(phi2)*sin(delta_lambda/2)*
sin(delta_lambda/2)

cc<-2*atan2(sqrt(a),sqrt(1-a))

distance<- R * cc

return(distance)  # in meters
}

0

Kotlinのバリエーションは次のとおりです。

import kotlin.math.*

class HaversineAlgorithm {

    companion object {
        private const val MEAN_EARTH_RADIUS = 6371.0
        private const val D2R = Math.PI / 180.0
    }

    private fun haversineInKm(lat1: Double, lon1: Double, lat2: Double, lon2: Double): Double {
        val lonDiff = (lon2 - lon1) * D2R
        val latDiff = (lat2 - lat1) * D2R
        val latSin = sin(latDiff / 2.0)
        val lonSin = sin(lonDiff / 2.0)
        val a = latSin * latSin + (cos(lat1 * D2R) * cos(lat2 * D2R) * lonSin * lonSin)
        val c = 2.0 * atan2(sqrt(a), sqrt(1.0 - a))
        return EQATORIAL_EARTH_RADIUS * c
    }
}

なぜ平均地球半径の代わりに赤道半径を使用したのですか?
user13044086

@ user13044086いい質問ですね。これは、Paulo Miguel AlmeidaのJavaバージョンから派生したためです。C#バージョンもその距離を使用しているようです。ここの他のバージョンには6371がありますが、これらのすべてのアルゴリズムが地球のジオイド形状を完全に処理できない場合があることを理解する必要があります。これを自由に変更して6371を使用してください。より正確な値につながると言われたら、答えを変更します。
Csaba Toth

1
ページのノートで説明したように、それは式の相対誤差を最小限に抑えるため、6371.008は、一般的に使用されmovable-type.co.uk/scripts/latlong.html#ellipsoid
user13044086

けっこうだ!明日回答を編集します
Csaba Toth

@ user13044086リンクをありがとう、それに基づいて少し前に私の回答を編集しました
Csaba Toth
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.