Use cheap-ruler rather than Haversine formula

This commit is contained in:
Lucas Verney 2018-11-21 12:02:59 +01:00
parent ff1b987463
commit ce58f5f601
2 changed files with 18 additions and 16 deletions

View File

@ -31,10 +31,8 @@ export const UPDATE_REPORTS_DISTANCE_THRESHOLD = 500; // in meters
// Minimal number of downvotes needed for a report to be masked
export const REPORT_DOWNVOTES_THRESHOLD = 1;
// Earth radius as recommended by the International Union of Geodesy and
// Geophysics
// https://rosettacode.org/wiki/Haversine_formula
export const EARTH_RADIUS = 6371000; // in meters
// Earth radius at equator
export const EARTH_RADIUS = 6378137; // in meters
// Keep reports only in a given radius around map center.
export const KEEP_REPORTS_METERS_AROUND = 10000; // in meters

View File

@ -1,6 +1,5 @@
import {
EARTH_RADIUS,
MOCK_LOCATION_GPX_PLAYBACK_SPEED,
MOCK_LOCATION_UPDATE_INTERVAL,
MOCK_LOCATION_USE_GPX,
@ -15,20 +14,25 @@ if (process.env.NODE_ENV !== 'production') {
mockGPX = require('mock_gpx.json'); // eslint-disable-line global-require
}
/**
* Cheap distance computation based on
* https://blog.mapbox.com/fast-geodesic-approximations-with-cheap-ruler-106f229ad016.
*/
export function distance(latLng1, latLng2) {
const lat1 = (latLng1[0] * Math.PI) / 180;
const lng1 = (latLng1[1] * Math.PI) / 180;
const cos = Math.cos((latLng1[0] + latLng2[0]) / 2 * Math.PI / 180);
const cos2 = 2 * cos * cos - 1;
const cos3 = 2 * cos * cos2 - cos;
const cos4 = 2 * cos * cos3 - cos2;
const cos5 = 2 * cos * cos4 - cos3;
const lat2 = (latLng2[0] * Math.PI) / 180;
const lng2 = (latLng2[1] * Math.PI) / 180;
// Multipliers for converting longitude and latitude degrees into distance
// (http://1.usa.gov/1Wb1bv7)
kx = 1000 * (111.41513 * cos - 0.09455 * cos3 + 0.00012 * cos5);
ky = 1000 * (111.13209 - 0.56605 * cos2 + 0.0012 * cos4);
const a = (
(Math.sin((lat2 - lat1) / 2.0) ** 2)
+ (Math.cos(lat1) * Math.cos(lat2) * (Math.sin((lng2 - lng1) / 2.0) ** 2))
);
const c = 2.0 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return EARTH_RADIUS * c;
const dx = (latLng1[1] - latLng2[1]) * kx;
const dy = (latLng1[0] - latLng2[0]) * ky;
return Math.sqrt(dx * dx + dy * dy);
}
export function mockLocationRandom() {