คำนวณระยะทางระหว่าง 2 พิกัด GPS


371

ฉันจะคำนวณระยะห่างระหว่างสองพิกัด GPS (โดยใช้ละติจูดและลองจิจูด) ได้อย่างไร


1
ขั้นตอนวิธีการนี้เป็นที่รู้จักกันเป็นระยะทางที่ดีวงกลม
เกร็กฮิวกิลล์

คำตอบ:


406

คำนวณระยะทางระหว่างสองพิกัดโดยละติจูดและลองจิจูดรวมถึงการใช้ Javascript

ที่ตั้งทางทิศตะวันตกและทิศใต้เป็นลบ จำนาทีและวินาทีไม่เกิน 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.prototype.toRad = function() { return this * (Math.PI / 180); }; ต้นแบบเช่น: หรือตามที่ระบุไว้ด้านล่างคุณสามารถแทนที่(Math.PI/2)ด้วย 0.0174532925199433 (... ความแม่นยำใด ๆ ที่คุณคิดว่าจำเป็น) เพื่อประสิทธิภาพที่เพิ่มขึ้น
Vinney Kelly

44
หากใครก็ตามโดยเฉพาะพวกคุณที่ไม่ได้มองหาการแสดงความคิดเห็นในตอนท้ายกำลังดูสูตรนี้และค้นหาหน่วยของระยะทางหน่วยคือ km :)
Dylan Knowles

1
พิมพ์ผิด @VinneyKelly ขนาดเล็ก แต่แทนที่ (Math.PI / 180) ไม่ (Math.PI / 2) ขอบคุณสำหรับทุกคนช่วยเหลือ
แพทริคเมอร์ฟี่

1
@ChristianKRider ดูบรรทัดแรก คิดเกี่ยวกับความRหมายตามปกติของคณิตศาสตร์แล้วค้นหาปริมาณที่เกี่ยวข้องกับโลกเพื่อดูว่าตัวเลขตรงกันหรือไม่
คดีของกองทุนโมนิกา

3
สำหรับหน่วยจักรวรรดิ (ไมล์) คุณสามารถเปลี่ยนearthRadiusKmเป็นvar earthRadiusMiles = 3959;fyi
chapeljuice

59

มองหา haversine ด้วย Google; นี่คือทางออกของฉัน:

#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

3
ในแง่ของประสิทธิภาพ: หนึ่งสามารถคำนวณ sin (dlat / 2.0) เพียงครั้งเดียวเก็บไว้ในตัวแปร a1 และแทนที่จะ pow (, 2) มันจะดีกว่าถ้าใช้ a1 * a1 เช่นเดียวกันสำหรับ pow อื่น ๆ (, 2)
pms

71
ใช่หรือเพียงแค่ใช้คอมไพเลอร์หลังยุค 60
rightfold

17
ไม่จำเป็นต้อง "เพิ่มประสิทธิภาพ" (M_PI / 180.0) เป็นค่าคงที่ที่ไม่มีใครเข้าใจโดยไม่มีบริบท คอมไพเลอร์คำนวณคำที่คงที่เหล่านี้ให้คุณ!
Patrick Cornelissen

2
@ TõnuSamuelขอบคุณมากสำหรับความคิดเห็นของคุณ ฉันซาบซึ้งจริงๆ มันทำให้รู้สึกว่าคอมไพเลอร์ที่มีการเปิดใช้งานการเพิ่มประสิทธิภาพ (-O) สามารถคำนวณการดำเนินงานของค่าคงที่ล่วงหน้าทำให้การยุบคู่มือไม่มีประโยชน์ ฉันจะทดสอบมันเมื่อฉันมีเวลา
Hlung

44

เวอร์ชั่น C # ของ Haversine

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 Fiddle นี้คุณจึงสามารถทดสอบด้วย Lat / Longs ของคุณเอง


1
ฉันได้เพิ่มซอฟต์เดอร์ NET. checky เพื่อให้ผู้คนสามารถทดสอบได้อย่างง่ายดาย
Pure.Krome

7
. Net Framework มีการสร้างในวิธีการ GeoCoordinate.GetDistanceTo แอสเซมบลี System.Device จะต้องมีการอ้างอิง บทความ MSDN msdn.microsoft.com/en-us/library/…
fnx

27

อัลกอริทึม Haversine เวอร์ชั่น Java ตามการตอบกลับของ Roman Makarov

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 ตรวจสอบให้แน่ใจว่าคุณใช้อย่างถูกต้องและไม่แลกเปลี่ยน lat / log เมื่อส่งผ่านไปยังวิธีการใด ๆ
เปาโล Miguel Miguel Almeida

1
ฉันได้รับคำตอบที่สมเหตุสมผลโดยใช้สูตรนี้ ฉันใช้ความแม่นยำในการใช้เว็บไซต์นี้: movable-type.co.uk/scripts/latlong.htmlซึ่งให้ทางฉันเป็น0.07149ระยะทางขณะที่สูตรของคุณให้ฉัน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 เป็น SRID สำหรับโมเดลโลกของ Wip84 elipsoidal


19

นี่คือฟังก์ชัน Haversine ใน Python ที่ฉันใช้:

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

11

ฉันต้องคำนวณระยะทางจำนวนมากระหว่างจุดต่าง ๆ สำหรับโครงการของฉันดังนั้นฉันจึงไปข้างหน้าและพยายามเพิ่มประสิทธิภาพของรหัสฉันพบที่นี่ โดยเฉลี่ยในเบราว์เซอร์ที่แตกต่างกันการใช้งานใหม่ของฉันทำงานเร็วกว่าคำตอบ upvoted ที่สุด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))

และเพื่อความสมบูรณ์: ฮาวาซีนบนวิกิ


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

5

ถ้าคุณต้องการบางสิ่งบางอย่างที่ถูกต้องมากขึ้นแล้วมีดูที่นี้

สูตรของ Vincenty เป็นสองวิธีวนซ้ำที่เกี่ยวข้องที่ใช้ในหน่วยพื้นที่เพื่อคำนวณระยะห่างระหว่างจุดสองจุดบนพื้นผิวของทรงกลมที่พัฒนาโดยแธดเดียส Vincenty (1975a) พวกมันมีพื้นฐานมาจากการสันนิษฐานว่า มีความแม่นยำมากกว่าวิธีการเช่นระยะทางวงกลมใหญ่ซึ่งถือว่าโลกเป็นทรงกลม

วิธีแรก (โดยตรง) คำนวณตำแหน่งของจุดซึ่งเป็นระยะทางที่กำหนดและมุมราบ (ทิศทาง) จากจุดอื่น วิธีที่สอง (ผกผัน) คำนวณระยะทางภูมิศาสตร์และมุมราบระหว่างจุดสองจุดที่กำหนด มีการใช้กันอย่างแพร่หลายในหน่วยพื้นที่เนื่องจากมีความแม่นยำถึงภายใน 0.5 มม. (0.020″) บนทรงรีโลก


5

I. เกี่ยวกับวิธีการ "Breadcrumbs"

  1. รัศมีโลกแตกต่างกันไปตาม Lat สิ่งนี้จะต้องนำมาพิจารณาในอัลกอริทึม Haversine
  2. พิจารณาการเปลี่ยนตลับลูกปืนซึ่งเปลี่ยนเป็นเส้นตรงไปยังส่วนโค้ง (ซึ่งยาวกว่า)
  3. การเปลี่ยนความเร็วเป็นบัญชีจะทำให้ส่วนโค้งเป็นเกลียว (ซึ่งยาวกว่าหรือสั้นกว่าโค้ง)
  4. การเปลี่ยนระดับความสูงจะเปลี่ยนเกลียวแบนให้เป็น 3 มิติ (ซึ่งจะนานกว่า) สิ่งนี้สำคัญมากสำหรับพื้นที่ที่เป็นภูเขา

ด้านล่างดูฟังก์ชันใน C ซึ่งพิจารณา # 1 และ # 2:

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

ครั้งที่สอง มีวิธีที่ง่ายกว่าซึ่งให้ผลลัพธ์ที่ดีงาม

โดยความเร็วเฉลี่ย

Trip_distance = Trip_average_speed * Trip_time

เนื่องจากความเร็วของ GPS ถูกตรวจพบโดยเอฟเฟ็กต์ Doppler และไม่เกี่ยวข้องโดยตรงกับ [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 นี้ดัดแปลงจากสิ่งที่พบใน Wikipedia และในเครื่องมือGPSbabelของ Robert Lipe :

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

นี่คือรุ่นจาก "Henry Vilinskiy" ดัดแปลงสำหรับ MySQL และกิโลเมตร:

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

นี่คือการคำนวณ "กฎหมายทรงกลมแห่งความผาสุก" ซึ่งเป็นวิธีการคำนวณระยะทางที่แม่นยำและผิดพลาดน้อยที่สุด
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
}

ฉัน Curried ฟังก์ชั่นเพื่อให้สามารถสร้างฟังก์ชั่นที่มีหนึ่งในสองตำแหน่งคงที่ได้อย่างง่ายดายและต้องการเพียง lat / lon คู่เดียวในการสร้างระยะทาง


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 ให้ลบ * 1000 ในการคำนวณ $ distance
  3. เปลี่ยน $ earthsRadius = 3963.19059 และลบ * 1,000 ในการคำนวณ $ distance เพื่อคำนวณระยะทางเป็นไมล์
  4. ฉันใช้ Haversine เนื่องจากโพสต์อื่น ๆ ได้ชี้ให้เห็นว่าสูตรของ Vincenty นั้นแม่นยำกว่ามาก

    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

รุ่นสกาล่า

  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

// อาจเป็นข้อผิดพลาดที่พิมพ์ผิด?
เรามีตัวแปร dlon ที่ไม่ได้ใช้ใน GetDirection
ฉันถือว่า

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

ควรจะเป็น

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

1
นี่ไม่ใช่คำตอบมันเป็นความเห็นที่ดีที่สุด
เควิน

1

นี่คือการดำเนินการของฉันใน Elixir

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 เป็นคำถามที่ดี เป็นเพราะฉันได้รับสิ่งนี้จากรุ่น Java ของ Paulo Miguel Almeida ดูเหมือนว่ารุ่น C # จะใช้ระยะทางนั้นด้วย รุ่นอื่นที่นี่มี 6371 แต่คุณต้องตระหนักว่าอัลกอริธึมเหล่านี้ทั้งหมดอาจไม่สามารถจัดการรูปร่างของโลกได้อย่างสมบูรณ์ อย่าลังเลที่จะแก้ไขและใช้ 6371 ถ้าคุณบอกฉันว่านำไปสู่ค่าที่แม่นยำยิ่งขึ้นฉันจะเปลี่ยนคำตอบของฉัน
Csaba Toth

1
6371.008 เป็นที่นิยมใช้เพราะมันช่วยลดความผิดพลาดของสูตรตามที่อธิบายไว้ในหมายเหตุประกอบในหน้าmovable-type.co.uk/scripts/latlong.html#ellipsoid
user13044086

ยุติธรรมพอ! ฉันจะแก้ไขคำตอบของฉันในวันพรุ่งนี้
Csaba จนถึง

@ user13044086 ขอบคุณสำหรับลิงค์ฉันได้แก้ไขคำตอบของฉันสักครู่แล้วตามที่
Csaba Toth
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.