OpenLayers 3: How to calculate distance between 2 points?
Asked Answered
I

5

14

Using OpenLayers 3, how can I determine the distance between two points in the Spherical Mercator (SRID: 3857) projection?

I know that distanceTo was used in OpenLayers 2

point1.distanceTo(point2)

I looked through the OpenLayers 3 docs, but I'm not finding anything similar...

Incandescence answered 27/9, 2014 at 5:4 Comment(0)
C
19

You can use the Sphere object to calculate the distance between two coordinates like this:

var distance = ol.sphere.WGS84.haversineDistance([0,0],[180,0]); 
//20037508.34 meters 

Sphere provides also various algorithms to calculate the distance like cosine,equirectangular etc. You can also create the Sphere object with the radius of a different ellipsoid.

I don't know why the docs are not online, but you can check the methods available from the source code of the sphere object: https://github.com/openlayers/ol3/blob/master/src/ol/sphere.js

I personally think that looking at the source code is the best way to find answers about OpenLayers3 ;)

Cladding answered 28/10, 2014 at 16:44 Comment(7)
The function works with the world geodesic system (wgs84 or epsg4326). If needed, use ol.proj.transform(coordinates, 'EPSG:3857', 'EPSG:4326').Urceolate
It is important to note that ol.sphere.WGS84.haversineDistance is not available in ol3 production code (current is 3.2.0). Indeed the method is not tagged as stable, hence it will only be available in ol-debug.js. This is also why it is not present in documentation.Shellishellie
With #3222 ol.Sphere.haversineDistance is now flagged as API method: openlayers.org/en/master/apidoc/… Also take a look at the updated example: openlayers.org/en/master/examples/measure.htmlMarcellemarcellina
Note the case: ol.sphere should be ol.SphereHypogeous
haversineDistance needs to be called on an instance of ol.Sphere (it is not static). I did like this: var wgs84Sphere = new ol.Sphere(6378137); var distance = wgs84Sphere.haversineDistance([lon1, lat1], [lon2, lat2]); // in metersAntechamber
@Antechamber yes sure, my code use already created object ol.sphere.WGS84 that is defined here: github.com/openlayers/ol3/blob/master/src/ol/sphere/… as ol.sphere.WGS84 = new ol.Sphere(6378137);Cladding
ol.sphere.WGS84 does not seem to be available in ol.js but only in ol-debug.js (v. 3.15.0). Relevant discussion is going on here: github.com/openlayers/ol3/issues/4954Antechamber
H
5

I'm using a fairly simple solution. I instanciate a ol.geom.LineString object between the two points and calculate the length of the line:

        this.distanceBetweenPoints = function(latlng1, latlng2){
            var line = new ol.geom.LineString([latlng1, latlng2]);
            return Math.round(line.getLength() * 100) / 100;
        };

You can then get a readable value using some formating:

        this.formatDistance = function(length) {
            if (length >= 1000) {
                length = (Math.round(length / 1000 * 100) / 100) +
                ' ' + 'km';
            } else {
                length = Math.round(length) +
                ' ' + 'm';
            }
            return length;
        }

EDIT: New method of calcul

Actualy, the distance can be false regarding the projection that you use. We had a fairly long discussion about this on ol3's github, you can see it there: https://github.com/openlayers/ol3/issues/3533

To summarize, you need to use that function in order to get exact calcul:

/**
 * format length output
 * @param {ol.geom.LineString} line
 * @return {string}
 */
export default function mapFormatLength(projection, line) {
  var length;
  var coordinates = line.getCoordinates();
  length = 0;
  for (var i = 0, ii = coordinates.length - 1; i < ii; ++i) {
    var c1 = ol.proj.transform(coordinates[i], projection, 'EPSG:4326');
    var c2 = ol.proj.transform(coordinates[i + 1], projection, 'EPSG:4326');
    length += mapConst.wgs84Sphere.haversineDistance(c1, c2);
  }
  var output;
  if (length > 1000) {
    output = (Math.round(length / 1000 * 100) / 100) +
    ' ' + 'km';
  } else {
    output = (Math.round(length * 100) / 100) +
    ' ' + 'm';
  }
  return output;
}
Housetop answered 11/2, 2015 at 12:27 Comment(2)
Is there any way to avoid using mapConst.wgs84Sphere.haversineDistance? It's not available in production build.Morley
I guess in the new version of openlayer, they introduced a way to get the correct length in the apiTallulah
S
3

Just to add one more option. This is not ol3 dependent.

function toRad(x) {return x * Math.PI / 180;}

function SphericalCosinus(lat1, lon1, lat2, lon2) {

    var R = 6371; // km
    var dLon = toRad(lon2 - lon1),
        lat1 = toRad(lat1),
        lat2 = toRad(lat2),
        d = Math.acos(Math.sin(lat1)*Math.sin(lat2) + Math.cos(lat1)*Math.cos(lat2) * Math.cos(dLon)) * R;


    return d;
}
Scoundrel answered 16/5, 2015 at 10:30 Comment(4)
I've just come across this and it seems to be nice and simple but the results I'm getting appear to be way too high for the distances I'm measuring. I don't want to raise a new question but wondered if you might be able to assist me in debugging it please @JonatasWalker ?Theoretics
At your service @dvmac01. Are you using EPSG:4326?Scoundrel
Not until you mentioned it ;) That seems to have done the trick. It's still returning measurements that are a little higher than reported elsewhere (Google Maps/Wikipedia) but if anything maybe it's too accurate? A colleague directed me towards this article: en.wikipedia.org/wiki/Coastline_paradox which explains the problem so I'm considering some kind of smoothing method and don't know if you could suggest something but thanks for the hint!Theoretics
Probably worth noting that this returns a value in km!Monney
M
2

I wrote this one for myself I hop it'll be useful, It return distance in metters:

function getCoordsDistance(firstPoint, secondPoint, projection) {
    projection = projection || 'EPSG:4326';

    length = 0;
    var sourceProj = mapObj.getView().getProjection();
    var c1 = ol.proj.transform(firstPoint, sourceProj, projection);
    var c2 = ol.proj.transform(secondPoint, sourceProj, projection);

    var wgs84Sphere = new ol.Sphere(6378137);
    length += wgs84Sphere.haversineDistance(c1, c2);

    return length;
}
Medicaid answered 31/12, 2016 at 5:39 Comment(0)
P
0
function getCoordsDistance(latlng1, latlng2) {

    var markers = [];

    markers.push(ol.proj.transform(latlng1, 'EPSG:4326', map.getView().getProjection()));
    markers.push(ol.proj.transform(latlng2, 'EPSG:4326', map.getView().getProjection()));

    var line = new ol.geom.LineString(markers, 'XY');
    var length = Math.round(line.getLength() * 100) / 100;

    if (length >= 1000) {
        length = (Math.round(length / 1000 * 100) / 100) +
            ' ' + 'km';
    } else {
        length = Math.round(length) +
            ' ' + 'm';
    }
    return length;
}
Purposely answered 13/6, 2019 at 14:38 Comment(1)
Your result will be in projection units, not true meters or km. Depending on the projection used a line across Greenland would give the a similar result to a line across Africa, but in reality Greenland is much smaller than Africa so the true distance will be shorter. ol.Sphere.getLength() or .haversineDistance() give the shortest true distances on a round planet.Forzando

© 2022 - 2024 — McMap. All rights reserved.