ฟังก์ชั่นคำนวณระยะทางระหว่างสองพิกัด


137

ฉันกำลังใช้ฟังก์ชันด้านล่างและทำงานไม่ถูกต้อง ตาม Google Maps ระยะห่างระหว่างพิกัดเหล่านี้ (จาก59.3293371,13.4877472ถึง59.3225525,13.4619422) คือ2.2กิโลเมตรในขณะที่ฟังก์ชันส่งกลับ1.6กิโลเมตร ฉันจะทำให้ฟังก์ชันนี้คืนระยะทางที่ถูกต้องได้อย่างไร?

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

jsFiddle: http://jsfiddle.net/edgren/gAHJB/



4
ฉันมาที่นี่เพื่อรับสูตรนี้ขอบคุณ :)
David Callanan

คำตอบ:


173

สิ่งที่คุณใช้เรียกว่าสูตรฮาเวอร์ไซน์ซึ่งคำนวณระยะห่างระหว่างจุดสองจุดบนทรงกลมขณะที่อีกาบินเป็นนกกาบินลิงก์ Google Maps ที่คุณระบุแสดงระยะทาง 2.2 กม. เนื่องจากไม่ใช่เส้นตรง

Wolphram Alpha เป็นแหล่งข้อมูลที่ยอดเยี่ยมสำหรับการคำนวณทางภูมิศาสตร์และยังแสดงระยะทาง1.652 กม. ระหว่างสองจุดนี้

ระยะทางขับเทียบกับระยะทางเส้นตรง (เส้นสีแดงของฉัน)

หากคุณกำลังมองหาระยะทางเป็นเส้นตรง (เป็นไฟล์อีกา) แสดงว่าฟังก์ชันของคุณทำงานได้อย่างถูกต้อง หากสิ่งที่คุณต้องการคือระยะทางในการขับขี่ (หรือระยะทางจักรยานหรือระยะทางขนส่งสาธารณะหรือระยะทางเดิน) คุณจะต้องใช้ API แผนที่ ( GoogleหรือBingเป็นที่นิยมมากที่สุด) เพื่อให้ได้เส้นทางที่เหมาะสมซึ่งจะรวมระยะทางด้วย

อนึ่ง Google Maps API มีวิธีการแพ็กเกจสำหรับระยะทางทรงกลมในgoogle.maps.geometry.sphericalเนมสเปซ (มองหาcomputeDistanceBetween) น่าจะดีกว่าการหมุนตัวเอง (สำหรับผู้เริ่มใช้ค่าที่แม่นยำกว่าสำหรับรัศมีของโลก)

สำหรับคนจู้จี้จุกจิกในหมู่พวกเราเมื่อฉันพูดว่า "ระยะทางเส้นตรง" ฉันหมายถึง "เส้นตรงบนทรงกลม" ซึ่งจริงๆแล้วก็คือเส้นโค้ง (เช่นระยะทางวงกลมใหญ่) แน่นอน


5
ด้วยความยินดี! มันสนุกมากที่จะตอบ
Ethan Brown

4
เป็นคำตอบที่สวยงาม ฉันบอกว่าสวยงามเพราะรายละเอียดที่ให้มานั้นดีเกินกว่าที่จะเข้าใจความแตกต่างแม้แต่มือใหม่อย่างฉัน
Supreet

78

ฉันเคยเขียนสมการที่คล้ายกันมาก่อน - ทดสอบแล้วและได้ 1.6 กม.

แผนที่ Google ของคุณแสดงระยะการขับขี่

ฟังก์ชันของคุณกำลังคำนวณเมื่ออีกาบิน (ระยะทางเป็นเส้นตรง)

alert(calcCrow(59.3293371,13.4877472,59.3225525,13.4619422).toFixed(1));



    //This function takes in latitude and longitude of two location and returns the distance between them as the crow flies (in km)
    function calcCrow(lat1, lon1, lat2, lon2) 
    {
      var R = 6371; // km
      var dLat = toRad(lat2-lat1);
      var dLon = toRad(lon2-lon1);
      var lat1 = toRad(lat1);
      var lat2 = toRad(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)); 
      var d = R * c;
      return d;
    }

    // Converts numeric degrees to radians
    function toRad(Value) 
    {
        return Value * Math.PI / 180;
    }

5
ฉันคิดว่าชื่อตัวแปรของคุณมีคำอธิบายมากเกินไป :)
pie6k

14

โซลูชันของ Derek ทำงานได้ดีสำหรับฉันและฉันเพิ่งแปลงเป็น PHP หวังว่ามันจะช่วยใครสักคนที่นั่น!

function calcCrow($lat1, $lon1, $lat2, $lon2){
        $R = 6371; // km
        $dLat = toRad($lat2-$lat1);
        $dLon = toRad($lon2-$lon1);
        $lat1 = toRad($lat1);
        $lat2 = toRad($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;
        return $d;
}

// Converts numeric degrees to radians
function toRad($Value) 
{
    return $Value * pi() / 180;
}

5

ลองทำตามนี้ อยู่ใน VB.net และคุณต้องแปลงเป็น Javascript ฟังก์ชันนี้ยอมรับพารามิเตอร์เป็นนาทีทศนิยม

    Private Function calculateDistance(ByVal long1 As String, ByVal lat1 As String, ByVal long2 As String, ByVal lat2 As String) As Double
    long1 = Double.Parse(long1)
    lat1 = Double.Parse(lat1)
    long2 = Double.Parse(long2)
    lat2 = Double.Parse(lat2)

    'conversion to radian
    lat1 = (lat1 * 2.0 * Math.PI) / 60.0 / 360.0
    long1 = (long1 * 2.0 * Math.PI) / 60.0 / 360.0
    lat2 = (lat2 * 2.0 * Math.PI) / 60.0 / 360.0
    long2 = (long2 * 2.0 * Math.PI) / 60.0 / 360.0

    ' use to different earth axis length
    Dim a As Double = 6378137.0        ' Earth Major Axis (WGS84)
    Dim b As Double = 6356752.3142     ' Minor Axis
    Dim f As Double = (a - b) / a        ' "Flattening"
    Dim e As Double = 2.0 * f - f * f      ' "Eccentricity"

    Dim beta As Double = (a / Math.Sqrt(1.0 - e * Math.Sin(lat1) * Math.Sin(lat1)))
    Dim cos As Double = Math.Cos(lat1)
    Dim x As Double = beta * cos * Math.Cos(long1)
    Dim y As Double = beta * cos * Math.Sin(long1)
    Dim z As Double = beta * (1 - e) * Math.Sin(lat1)

    beta = (a / Math.Sqrt(1.0 - e * Math.Sin(lat2) * Math.Sin(lat2)))
    cos = Math.Cos(lat2)
    x -= (beta * cos * Math.Cos(long2))
    y -= (beta * cos * Math.Sin(long2))
    z -= (beta * (1 - e) * Math.Sin(lat2))

    Return Math.Sqrt((x * x) + (y * y) + (z * z))
End Function

แก้ไข ฟังก์ชันที่แปลงแล้วใน javascript

function calculateDistance(lat1, long1, lat2, long2)
  {    

      //radians
      lat1 = (lat1 * 2.0 * Math.PI) / 60.0 / 360.0;      
      long1 = (long1 * 2.0 * Math.PI) / 60.0 / 360.0;    
      lat2 = (lat2 * 2.0 * Math.PI) / 60.0 / 360.0;   
      long2 = (long2 * 2.0 * Math.PI) / 60.0 / 360.0;       


      // use to different earth axis length    
      var a = 6378137.0;        // Earth Major Axis (WGS84)    
      var b = 6356752.3142;     // Minor Axis    
      var f = (a-b) / a;        // "Flattening"    
      var e = 2.0*f - f*f;      // "Eccentricity"      

      var beta = (a / Math.sqrt( 1.0 - e * Math.sin( lat1 ) * Math.sin( lat1 )));    
      var cos = Math.cos( lat1 );    
      var x = beta * cos * Math.cos( long1 );    
      var y = beta * cos * Math.sin( long1 );    
      var z = beta * ( 1 - e ) * Math.sin( lat1 );      

      beta = ( a / Math.sqrt( 1.0 -  e * Math.sin( lat2 ) * Math.sin( lat2 )));    
      cos = Math.cos( lat2 );   
      x -= (beta * cos * Math.cos( long2 ));    
      y -= (beta * cos * Math.sin( long2 ));    
      z -= (beta * (1 - e) * Math.sin( lat2 ));       

      return (Math.sqrt( (x*x) + (y*y) + (z*z) )/1000);  
    }

6
这个问题问了JavaScript的答案.. คุณต้องแปลงเป็นภาษาอังกฤษ :)
VulfCompressor

2
เพิ่มเวอร์ชันจาวาสคริปต์
Noorul

ลองใช้ชื่อที่มีความหมายมากขึ้นสำหรับตัวแปรของคุณ อย่ากลัวที่จะเป็นแบบ verbose เนื่องจากในปัจจุบัน javascript มักจะถูกย่อขนาดและชื่อตัวแปรจะมีประโยชน์สำหรับมนุษย์เท่านั้น ตัวอย่างเช่น: const earthsMajorAccess = 6378137.0; ไม่จำเป็นต้องแสดงความคิดเห็นที่เป็นประโยชน์ (เนื่องจากชื่อตัวแปรมีความหมายว่ามันคืออะไร)
Adriano Michael

ฟังก์ชันนี้เขียนขึ้นเมื่อ 5 ปีก่อน คุณสามารถแก้ไขได้ :)
นูรูล

2

คำนวณระยะห่างระหว่างสองจุดในจาวาสคริปต์

function distance(lat1, lon1, lat2, lon2, unit) {
        var radlat1 = Math.PI * lat1/180
        var radlat2 = Math.PI * lat2/180
        var theta = lon1-lon2
        var radtheta = Math.PI * theta/180
        var dist = Math.sin(radlat1) * Math.sin(radlat2) + Math.cos(radlat1) * Math.cos(radlat2) * Math.cos(radtheta);
        dist = Math.acos(dist)
        dist = dist * 180/Math.PI
        dist = dist * 60 * 1.1515
        if (unit=="K") { dist = dist * 1.609344 }
        if (unit=="N") { dist = dist * 0.8684 }
        return dist
}

สำหรับรายละเอียดเพิ่มเติมโปรดดูที่ลิงค์อ้างอิง


2

ใช้สูตร Haversine ที่มาของรหัส :

//:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
//:::                                                                         :::
//:::  This routine calculates the distance between two points (given the     :::
//:::  latitude/longitude of those points). It is being used to calculate     :::
//:::  the distance between two locations using GeoDataSource (TM) prodducts  :::
//:::                                                                         :::
//:::  Definitions:                                                           :::
//:::    South latitudes are negative, east longitudes are positive           :::
//:::                                                                         :::
//:::  Passed to function:                                                    :::
//:::    lat1, lon1 = Latitude and Longitude of point 1 (in decimal degrees)  :::
//:::    lat2, lon2 = Latitude and Longitude of point 2 (in decimal degrees)  :::
//:::    unit = the unit you desire for results                               :::
//:::           where: 'M' is statute miles (default)                         :::
//:::                  'K' is kilometers                                      :::
//:::                  'N' is nautical miles                                  :::
//:::                                                                         :::
//:::  Worldwide cities and other features databases with latitude longitude  :::
//:::  are available at https://www.geodatasource.com                         :::
//:::                                                                         :::
//:::  For enquiries, please contact sales@geodatasource.com                  :::
//:::                                                                         :::
//:::  Official Web site: https://www.geodatasource.com                       :::
//:::                                                                         :::
//:::               GeoDataSource.com (C) All Rights Reserved 2018            :::
//:::                                                                         :::
//:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

function distance(lat1, lon1, lat2, lon2, unit) {
    if ((lat1 == lat2) && (lon1 == lon2)) {
        return 0;
    }
    else {
        var radlat1 = Math.PI * lat1/180;
        var radlat2 = Math.PI * lat2/180;
        var theta = lon1-lon2;
        var radtheta = Math.PI * theta/180;
        var dist = Math.sin(radlat1) * Math.sin(radlat2) + Math.cos(radlat1) * Math.cos(radlat2) * Math.cos(radtheta);
        if (dist > 1) {
            dist = 1;
        }
        dist = Math.acos(dist);
        dist = dist * 180/Math.PI;
        dist = dist * 60 * 1.1515;
        if (unit=="K") { dist = dist * 1.609344 }
        if (unit=="N") { dist = dist * 0.8684 }
        return dist;
    }
}

โค้ดตัวอย่างได้รับอนุญาตภายใต้ LGPLv3


1

ฉันเขียนฟังก์ชันเพื่อหาระยะห่างระหว่างสองพิกัด มันจะคืนระยะทางเป็นเมตร

 function findDistance() {
   var R = 6371e3; // R is earth’s radius
   var lat1 = 23.18489670753479; // starting point lat
   var lat2 = 32.726601;         // ending point lat
   var lon1 = 72.62524545192719; // starting point lon
   var lon2 = 74.857025;         // ending point lon
   var lat1radians = toRadians(lat1);
   var lat2radians = toRadians(lat2);

   var latRadians = toRadians(lat2-lat1);
   var lonRadians = toRadians(lon2-lon1);

   var a = Math.sin(latRadians/2) * Math.sin(latRadians/2) +
        Math.cos(lat1radians) * Math.cos(lat2radians) *
        Math.sin(lonRadians/2) * Math.sin(lonRadians/2);
   var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));

   var d = R * c;

   console.log(d)
}

function toRadians(val){
    var PI = 3.1415926535;
    return val / 180.0 * PI;
}

1

ระยะทางวงกลมใหญ่ - จากความยาวคอร์ด

นี่คือทางออกที่สวยงามโดยใช้รูปแบบการออกแบบกลยุทธ์ ฉันหวังว่ามันจะอ่านได้เพียงพอ

TwoPointsDistanceCalculatorStrategy.js :

module.exports = () =>

class TwoPointsDistanceCalculatorStrategy {

    constructor() {}

    calculateDistance({ point1Coordinates, point2Coordinates }) {}
};

GreatCircleTwoPointsDistanceCalculatorStrategy.js:

module.exports = ({ TwoPointsDistanceCalculatorStrategy }) =>

class GreatCircleTwoPointsDistanceCalculatorStrategy extends TwoPointsDistanceCalculatorStrategy {

    constructor() {
        super();
    }

    /**
     * Following the algorithm documented here: 
     * https://en.wikipedia.org/wiki/Great-circle_distance#Computational_formulas
     * 
     * @param {object} inputs
     * @param {array} inputs.point1Coordinates
     * @param {array} inputs.point2Coordinates
     * 
     * @returns {decimal} distance in kelometers
     */
    calculateDistance({ point1Coordinates, point2Coordinates }) {

        const convertDegreesToRadians = require('../convert-degrees-to-radians');
        const EARTH_RADIUS = 6371;   // in kelometers

        const [lat1 = 0, lon1 = 0] = point1Coordinates;
        const [lat2 = 0, lon2 = 0] = point2Coordinates;

        const radianLat1 = convertDegreesToRadians({ degrees: lat1 });
        const radianLon1 = convertDegreesToRadians({ degrees: lon1 });
        const radianLat2 = convertDegreesToRadians({ degrees: lat2 });
        const radianLon2 = convertDegreesToRadians({ degrees: lon2 });

        const centralAngle = _computeCentralAngle({ 
            lat1: radianLat1, lon1: radianLon1, 
            lat2: radianLat2, lon2: radianLon2, 
        });

        const distance = EARTH_RADIUS * centralAngle;

        return distance;
    }
};


/**
 * 
 * @param {object} inputs
 * @param {decimal} inputs.lat1
 * @param {decimal} inputs.lon1
 * @param {decimal} inputs.lat2
 * @param {decimal} inputs.lon2
 * 
 * @returns {decimal} centralAngle
 */
function _computeCentralAngle({ lat1, lon1, lat2, lon2 }) {

    const chordLength = _computeChordLength({ lat1, lon1, lat2, lon2 });
    const centralAngle = 2 * Math.asin(chordLength / 2);

    return centralAngle;
}


/**
 * 
 * @param {object} inputs
 * @param {decimal} inputs.lat1
 * @param {decimal} inputs.lon1
 * @param {decimal} inputs.lat2
 * @param {decimal} inputs.lon2
 * 
 * @returns {decimal} chordLength
 */
function _computeChordLength({ lat1, lon1, lat2, lon2 }) {

    const { sin, cos, pow, sqrt } = Math;

    const ΔX = cos(lat2) * cos(lon2) - cos(lat1) * cos(lon1);
    const ΔY = cos(lat2) * sin(lon2) - cos(lat1) * sin(lon1);
    const ΔZ = sin(lat2) - sin(lat1);

    const ΔXSquare = powX, 2);
    const ΔYSquare = powY, 2);
    const ΔZSquare = powZ, 2);

    const chordLength = sqrtXSquare + ΔYSquare + ΔZSquare);

    return chordLength;
}

แปลงองศาเพื่อ radians.js:

module.exports = function convertDegreesToRadians({ degrees }) {

    return degrees * Math.PI / 180;
};

นี้ต่อไประยะทางที่ดีวงกลม - จากความยาวคอร์ดเอกสารที่นี่


0

ไปที่ที่อยู่นี้ https://www.movable-type.co.uk/scripts/latlong.html คุณสามารถใช้รหัสนี้:

JavaScript:     

const R = 6371e3; // metres
const φ1 = lat1 * Math.PI/180; // φ, λ in radians
const φ2 = lat2 * Math.PI/180;
const Δφ = (lat2-lat1) * Math.PI/180;
const Δλ = (lon2-lon1) * Math.PI/180;

const a = Math.sin(Δφ/2) * Math.sin(Δφ/2) +
          Math.cos1) * Math.cos2) *
          Math.sin(Δλ/2) * Math.sin(Δλ/2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));

const d = R * c; // in metres
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.