如何计算由经纬度指定的两点之间的距离?

为了澄清,我想用千米来表示距离;这些点使用WGS84系统,我想了解可用方法的相对准确性。


当前回答

我已经创建了这个小Javascript LatLng对象,可能对某人有用。

var latLng1 = new LatLng(5, 3);
var latLng2 = new LatLng(6, 7);
var distance = latLng1.distanceTo(latLng2); 

代码:

/**
 * latLng point
 * @param {Number} lat
 * @param {Number} lng
 * @returns {LatLng}
 * @constructor
 */
function LatLng(lat,lng) {
    this.lat = parseFloat(lat);
    this.lng = parseFloat(lng);

    this.__cache = {};
}

LatLng.prototype = {
    toString: function() {
        return [this.lat, this.lng].join(",");
    },

    /**
     * calculate distance in km to another latLng, with caching
     * @param {LatLng} latLng
     * @returns {Number} distance in km
     */
    distanceTo: function(latLng) {
        var cacheKey = latLng.toString();
        if(cacheKey in this.__cache) {
            return this.__cache[cacheKey];
        }

        // the fastest way to calculate the distance, according to this jsperf test;
        // http://jsperf.com/haversine-salvador/8
        // http://stackoverflow.com/questions/27928
        var deg2rad = 0.017453292519943295; // === Math.PI / 180
        var lat1 = this.lat * deg2rad;
        var lng1 = this.lng * deg2rad;
        var lat2 = latLng.lat * deg2rad;
        var lng2 = latLng.lng * deg2rad;
        var a = (
            (1 - Math.cos(lat2 - lat1)) +
            (1 - Math.cos(lng2 - lng1)) * Math.cos(lat1) * Math.cos(lat2)
            ) / 2;
        var distance = 12742 * Math.asin(Math.sqrt(a)); // Diameter of the earth in km (2 * 6371)

        // cache the distance
        this.__cache[cacheKey] = distance;

        return distance;
    }
};

其他回答

我不喜欢添加另一个答案,但谷歌地图API v.3具有球形几何(以及更多)。在将你的WGS84转换为十进制度后,你可以这样做:

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

关于谷歌的计算有多精确,甚至使用了什么模型都没有任何消息(尽管它说的是“球面”而不是“大地水准面”。顺便说一下,“直线”距离显然不同于一个人在地球表面旅行的距离,而这似乎是每个人都在假设的。

下面是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。

数学有问题,LUA的学位…如果有人知道修复,请清理这段代码!

与此同时,这里有一个Haversine在LUA中的实现(与Redis一起使用!)

function calcDist(lat1, lon1, lat2, lon2)
    lat1= lat1*0.0174532925
    lat2= lat2*0.0174532925
    lon1= lon1*0.0174532925
    lon2= lon2*0.0174532925

    dlon = lon2-lon1
    dlat = lat2-lat1

    a = math.pow(math.sin(dlat/2),2) + math.cos(lat1) * math.cos(lat2) * math.pow(math.sin(dlon/2),2)
    c = 2 * math.asin(math.sqrt(a))
    dist = 6371 * c      -- multiply by 0.621371 to convert to miles
    return dist
end

干杯!

我已经创建了这个小Javascript LatLng对象,可能对某人有用。

var latLng1 = new LatLng(5, 3);
var latLng2 = new LatLng(6, 7);
var distance = latLng1.distanceTo(latLng2); 

代码:

/**
 * latLng point
 * @param {Number} lat
 * @param {Number} lng
 * @returns {LatLng}
 * @constructor
 */
function LatLng(lat,lng) {
    this.lat = parseFloat(lat);
    this.lng = parseFloat(lng);

    this.__cache = {};
}

LatLng.prototype = {
    toString: function() {
        return [this.lat, this.lng].join(",");
    },

    /**
     * calculate distance in km to another latLng, with caching
     * @param {LatLng} latLng
     * @returns {Number} distance in km
     */
    distanceTo: function(latLng) {
        var cacheKey = latLng.toString();
        if(cacheKey in this.__cache) {
            return this.__cache[cacheKey];
        }

        // the fastest way to calculate the distance, according to this jsperf test;
        // http://jsperf.com/haversine-salvador/8
        // http://stackoverflow.com/questions/27928
        var deg2rad = 0.017453292519943295; // === Math.PI / 180
        var lat1 = this.lat * deg2rad;
        var lng1 = this.lng * deg2rad;
        var lat2 = latLng.lat * deg2rad;
        var lng2 = latLng.lng * deg2rad;
        var a = (
            (1 - Math.cos(lat2 - lat1)) +
            (1 - Math.cos(lng2 - lng1)) * Math.cos(lat1) * Math.cos(lat2)
            ) / 2;
        var distance = 12742 * Math.asin(Math.sqrt(a)); // Diameter of the earth in km (2 * 6371)

        // cache the distance
        this.__cache[cacheKey] = distance;

        return distance;
    }
};

下面是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;
}