Skip to content

Instantly share code, notes, and snippets.

@bdchauvette
Last active November 14, 2021 15:29
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save bdchauvette/b115347142b0dd033d89 to your computer and use it in GitHub Desktop.
Save bdchauvette/b115347142b0dd033d89 to your computer and use it in GitHub Desktop.
Code Sample
/** Converts degrees to radians */
function toRadians(degrees) {
return degrees * Math.PI / 180;
}
/** Converts DMS coordinate to decimal coordinate */
function toDecimalDegrees(coord) {
/** Extracts the digits from an arc unit containing punctuation */
function getDigits(unit) {
var digits = /^\d+/;
return +unit.match(digits)[0];
}
/** Determines whether a coordinate is south of the Equator or west of the Prime Meridian */
function isNegHemisphere(hemisphere) {
return (hemisphere === 'S' || hemisphere === 'W');
}
var coord = coord.split(' ');
var degrees = getDigits(coord[0]);
var minutes = getDigits(coord[1]) / 60;
var seconds = getDigits(coord[2]) / 60 / 60;
var hemisphere = isNegHemisphere(coord[3]) ? -1 : 1;
var decimal = (degrees + minutes + seconds) * hemisphere;
return decimal;
}
/** Converts a DMS lat/lng string to a more useful object */
function parseCoords(coord) {
var coord = coord.split(', ');
return {
lat: toDecimalDegrees(coord[0]),
lng: toDecimalDegrees(coord[1])
};
}
/** Finds the distance in km between two coordinates in DMS */
function distance(coord1, coord2) {
var coord1 = parseCoords(coord1);
var coord2 = parseCoords(coord2);
// Haversine formula
// http://www.movable-type.co.uk/scripts/latlong.html
var EARTH_RADIUS = 6371;
var lat1 = toRadians(coord1.lat);
var lat2 = toRadians(coord2.lat);
var Δlat = toRadians(coord2.lat - coord1.lat);
var Δlng = toRadians(coord2.lng - coord1.lng);
var a = Math.sin(Δlat / 2) * Math.sin(Δlat / 2) +
Math.cos(lat1) * Math.cos(lat2) *
Math.sin(Δlng / 2) * Math.sin(Δlng / 2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
var d = EARTH_RADIUS * c;
// Round the distance to the lower 10km
var distance = Math.floor(d / 10) * 10;
return distance;
}
if (process.env.NODE_ENV === 'test') {
module.exports = {
distance: distance,
toRadians: toRadians,
toDecimalDegrees: toDecimalDegrees,
parseCoords: parseCoords
};
} else {
module.exports = distance;
}
var assert = require('assert');
var distance = require('./distance').distance;
var toRadians = require('./distance').toRadians;
var toDecimalDegrees = require('./distance').toDecimalDegrees;
var parseCoords = require('./distance').parseCoords;
describe('toRadians()', function() {
it('Converts degrees to radians', function() {
assert.equal(toRadians(90), Math.PI / 2);
assert.equal(toRadians(180), Math.PI);
});
});
describe('toDecimalDegrees()', function() {
it('Converts DMS to Decimal', function() {
var coords = [
{ dms: '48° 12′ 30″ N', dec: 48.208333333333336 },
{ dms: '16° 22′ 23″ E', dec: 16.373055555555556 },
{ dms: '23° 33′ 0″ S', dec: -23.55 },
{ dms: '46° 38′ 0″ W', dec: -46.63333333333333 },
{ dms: '58° 18′ 0″ N', dec: 58.3 },
{ dms: '134° 25′ 0″ W', dec: -134.41666666666666 },
{ dms: '33° 51′ 35″ S', dec: -33.859722222222224 },
{ dms: '151° 12′ 40″ E', dec: 151.2111111111111 }
];
coords.forEach(function(coord) {
assert.equal(toDecimalDegrees(coord.dms), coord.dec);
});
});
});
describe('parseCoords()', function() {
it('Converts a coordinate string to an object', function() {
var coords = '47° 48′ 00″ N, 13° 02′ 00″ E';
var expected = { lat: 47.8, lng: 13.033333333333333 };
assert.deepEqual(parseCoords(coords), expected);
});
});
describe('distance()', function() {
it('Outputs correct distance', function() {
var c0 = '47° 48′ 00″ N, 13° 02′ 00″ E';
var c1 = '38° 53′ 42″ N, 77° 02′ 12″ W';
var c2 = '18° 56′ 00″ S, 47° 31′ 00″ E';
var c3 = '22° 54′ 30″ S, 43° 11′ 47″ W';
var c4 = '48° 12′ 30″ N, 16° 22′ 23″ E';
var c5 = '23° 33′ 0″ S, 46° 38′ 0″ W';
var c6 = '48° 12′ 30″ N, 16° 22′ 23″ E';
var c7 = '58° 18′ 0″ N, 134° 25′ 0″ W';
assert.equal(distance(c0, c0), 0);
assert.equal(distance(c0, c1), 6920);
assert.equal(distance(c1, c3), 7720);
assert.equal(distance(c3, c2), 9270);
assert.equal(distance(c2, c0), 8170);
assert.equal(distance(c2, c1), 14270);
assert.equal(distance(c0, c3), 9650);
assert.equal(distance(c4, c5), 10130);
assert.equal(distance(c6, c7), 7870);
});
});
@bdchauvette
Copy link
Author

About

This code was written for the Captain's Distance Request problem at Code Wars.

Description

Complete the function so it returns the distance between two given coordinates. Examples of given coordinates are:

48° 12′ 30″ N, 16° 22′ 23″ E
23° 33′ 0″ S, 46° 38′ 0″ W
58° 18′ 0″ N, 134° 25′ 0″ W
33° 51′ 35″ S, 151° 12′ 40″ E
  • The returned distance should be in kilometers.
  • We think about the earth as a sphere with radius 6371 km.
  • Round to the lower 10 km. So 6387 becomes 6380, 643 becomes 640 and 18299 becomes 18290.
  • You can expect the delivered coordinates to be valid.
  • The characters for minutes (′) and seconds (″) are not standard quotation marks.

Expected Output

Examples of inputs and the expected outputs:

distance("48° 12′ 30″ N, 16° 22′ 23″ E", "23° 33′ 0″ S, 46° 38′ 0″ W");
// > 10130

distance("48° 12′ 30″ N, 16° 22′ 23″ E", "58° 18′ 0″ N, 134° 25′ 0″ W");
// > 7870

distance("48° 12′ 30″ N, 16° 22′ 23″ E", "48° 12′ 30″ N, 16° 22′ 23″ E");
// > 0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment