From 61f9f91e9ee54c71f4f604451642df03263de334 Mon Sep 17 00:00:00 2001 From: Mathieu Albrespy Date: Mon, 4 May 2015 23:10:04 -0400 Subject: [PATCH 1/3] Proposal fix for distance computation. Hi, I already sent a response to an issue with turf-buffer with a JSFiddle to show the issue. I modified this JSFiddle to show the distance computation error while using turf-distance. http://jsfiddle.net/Themacprod/r2fp5t66/1/ This proposal can be improve by using the latitude of the middle of the two coodinates. --- index.js | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index 773425d..1a26475 100644 --- a/index.js +++ b/index.js @@ -61,11 +61,11 @@ module.exports = function(point1, point2, units) { var R; switch(units) { case 'miles': - R = 3960; + R = toMiles(getEarthRadius(coordinates1[1])); break; case 'kilometers': case 'kilometres': - R = 6373; + R = getEarthRadius(coordinates1[1]) / 1000; break; case 'degrees': R = 57.2957795; @@ -73,6 +73,8 @@ module.exports = function(point1, point2, units) { case 'radians': R = 1; break; + case 'meters': + R = getEarthRadius(coordinates1[1]); case undefined: R = 6373; break; @@ -80,10 +82,25 @@ module.exports = function(point1, point2, units) { throw new Error('unknown option given to "units"'); } - var distance = R * c; + var distance = getEarthRadius(coordinates1[1], units) * c; return distance; }; function toRad(degree) { return degree * Math.PI / 180; } + +function toMiles(km) { + return km * 0.6214; +} + +function getEarthRadius = function(latdeg) { + + // http://en.wikipedia.org/wiki/Earth_radius + var An = 6378137.0 * 6378137.0 * Math.cos(latdeg); + var Bn = 6356752.3 * 6356752.3 * Math.sin(latdeg); + var Ad = 6378137.0 * Math.cos(latdeg); + var Bd = 6356752.3 * Math.sin(latdeg); + + return Math.sqrt((An * An + Bn * Bn) / (Ad * Ad + Bd * Bd)); +} From 7b84b846151151d79161a7b0cf89e1192b09cc95 Mon Sep 17 00:00:00 2001 From: Mathieu Albrespy Date: Tue, 5 May 2015 09:44:59 -0400 Subject: [PATCH 2/3] Fixed distance computation issue. The "R" value was not used. --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 1a26475..6c101b8 100644 --- a/index.js +++ b/index.js @@ -82,7 +82,7 @@ module.exports = function(point1, point2, units) { throw new Error('unknown option given to "units"'); } - var distance = getEarthRadius(coordinates1[1], units) * c; + var distance = R * c; return distance; }; From 70da2ca24a31c000050626b22131d980576d1da9 Mon Sep 17 00:00:00 2001 From: Mathieu Albrespy Date: Wed, 6 May 2015 22:51:20 -0400 Subject: [PATCH 3/3] New version for getRadius function. --- index.js | 88 +++++++++++++++++++++++++++++++++++++++++--------------- test.js | 68 +++++++++++++++++++++++++++++++++++++------ 2 files changed, 125 insertions(+), 31 deletions(-) diff --git a/index.js b/index.js index 6c101b8..7da21ad 100644 --- a/index.js +++ b/index.js @@ -54,18 +54,19 @@ module.exports = function(point1, point2, units) { var dLon = toRad(coordinates2[0] - coordinates1[0]); var lat1 = toRad(coordinates1[1]); var lat2 = toRad(coordinates2[1]); - 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 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 R; - switch(units) { + switch (units) { case 'miles': - R = toMiles(getEarthRadius(coordinates1[1])); - break; case 'kilometers': case 'kilometres': - R = getEarthRadius(coordinates1[1]) / 1000; + case 'meters': + case undefined: + R = getEarthRadius(lat1, units); break; case 'degrees': R = 57.2957795; @@ -73,34 +74,75 @@ module.exports = function(point1, point2, units) { case 'radians': R = 1; break; - case 'meters': - R = getEarthRadius(coordinates1[1]); - case undefined: - R = 6373; - break; default: throw new Error('unknown option given to "units"'); } + // Round result. var distance = R * c; - return distance; + + switch (units) { + case 'miles': + case 'kilometers': + case 'kilometres': + case undefined: + distance = Math.floor(distance * 1000) / 1000; + break; + + case 'meters': + distance = Math.floor(distance); + break; + + default: + break; + } + + return Number(distance); }; function toRad(degree) { return degree * Math.PI / 180; } -function toMiles(km) { - return km * 0.6214; +function kmToMiles(kilometers) { + return kilometers * 0.621371192; } -function getEarthRadius = function(latdeg) { - - // http://en.wikipedia.org/wiki/Earth_radius - var An = 6378137.0 * 6378137.0 * Math.cos(latdeg); - var Bn = 6356752.3 * 6356752.3 * Math.sin(latdeg); - var Ad = 6378137.0 * Math.cos(latdeg); - var Bd = 6356752.3 * Math.sin(latdeg); +function metersToMiles(meters) { + return meters * 0.000621371192; +} + +function getEarthRadius(latdeg, units) { + + var radiusMajorInMeters = 6378137.0; + var radiusMinorInMeters = 6356752.3142; + var radiusMajor = 0; + var radiusMinor = 0; + + switch (units) { + case 'miles': + radiusMajor = metersToMiles(radiusMajorInMeters); + radiusMinor = metersToMiles(radiusMinorInMeters); + break; + case 'kilometers': + case 'kilometres': + case undefined: + radiusMajor = radiusMajorInMeters / 1000; + radiusMinor = radiusMinorInMeters / 1000; + break; + case 'meters': + radiusMajor = radiusMajorInMeters; + radiusMinor = radiusMinorInMeters; + break; + default: + throw new Error('unknown option given to "units"'); + } + + // http://en.wikipedia.org/wiki/Earth_radius + var An = radiusMajor * radiusMajor * Math.cos(latdeg); + var Bn = radiusMinor * radiusMinor * Math.sin(latdeg); + var Ad = radiusMajor * Math.cos(latdeg); + var Bd = radiusMinor * Math.sin(latdeg); - return Math.sqrt((An * An + Bn * Bn) / (Ad * Ad + Bd * Bd)); + return Math.sqrt((An * An + Bn * Bn) / (Ad * Ad + Bd * Bd)); } diff --git a/test.js b/test.js index f759fc5..c7a593c 100644 --- a/test.js +++ b/test.js @@ -1,25 +1,77 @@ var test = require('tape'); var distance = require('./'); -test('distance', function(t){ +test('distance', function(t) { var pt1 = { "type": "Feature", - "geometry": {"type": "Point", "coordinates": [-75.343, 39.984]} + "geometry": { + "type": "Point", + "coordinates": [-75.343, 39.984] + } }; var pt2 = { "type": "Feature", - "geometry": {"type": "Point", "coordinates": [-75.534, 39.123]} + "geometry": { + "type": "Point", + "coordinates": [-75.534, 39.123] + } }; - t.equal(distance(pt1, pt2, 'miles'), 60.37218405837491, 'miles'); - t.equal(distance(pt1, pt2, 'kilometers'), 97.15957803131901, 'kilometers'); - t.equal(distance(pt1, pt2, 'kilometres'), 97.15957803131901, 'kilometres'); + // Center point + var pt3 = { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-73.5719678, 45.5260794] + } + }; + + // On the circle radius (center + 400 meters + 0 degres) + var pt4 = { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-73.57196780000001, 45.52968474026626] + + } + }; + + // On the circle radius too (center + 400 meters + 270 degres) + var pt5 = { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-73.57711398872225, 45.52607928446446] + } + }; + + /* Test # 01 */ + t.equal(distance(pt1, pt2, 'miles'), 60.337, 'miles'); + /* Test # 02 */ + t.equal(distance(pt1, pt2, 'kilometers'), 97.103, 'kilometers'); + /* Test # 03 */ + t.equal(distance(pt1, pt2, 'kilometres'), 97.103, 'kilometres'); + /* Test # 04 */ t.equal(distance(pt1, pt2, 'radians'), 0.015245501024842149, 'radians'); + /* Test # 05 */ t.equal(distance(pt1, pt2, 'degrees'), 0.8735028650863799, 'degrees'); - t.equal(distance(pt1, pt2), 97.15957803131901, 'default=kilometers'); + /* Test # 06 */ + t.equal(distance(pt1, pt2), 97.103, 'default=kilometers'); + /* Test # 07 */ + t.equal(distance(pt3, pt4, 'meters'), 400, 'meters'); + /* Test # 08 */ + t.equal(distance(pt3, pt4, 'kilometers'), 0.400, 'kilometers'); + /* Test # 09 */ + t.equal(distance(pt3, pt5, 'meters'), 400, 'meters'); + /* Test # 10 */ + t.equal(distance(pt3, pt5, 'kilometers'), 0.400, 'kilometers'); + /* Test # 11 */ + t.equal(distance(pt3, pt4, 'meters'), distance(pt3, pt5, 'meters')); + /* Test # 12 */ + t.equal(distance(pt3, pt4, 'kilometers'), distance(pt3, pt5, 'kilometers')); t.throws(function() { - distance(pt1, pt2, 'blah'); + distance(pt1, pt2, 'blah'); }, 'unknown option given to units'); t.end();