Add ConvertCoordinates to lib folder

master
j433866 2019-01-11 11:59:13 +00:00
parent 9e63e40dab
commit abdd70c6fa
1 changed files with 210 additions and 0 deletions

View File

@ -0,0 +1,210 @@
/**
* Co-ordinate conversion resources.
*
* @author j433866 [j433866@gmail.com]
* @copyright Crown Copyright 2019
* @license Apache-2.0
*/
import geohash from "ngeohash";
import mgrs from "mgrs";
/**
* Co-ordinate formats
*/
export const FORMATS = [
"Degrees Minutes Seconds",
"Degrees Decimal Minutes",
"Decimal Degrees",
"Geohash",
"Military Grid Reference System"
];
/**
* Convert a given latitude and longitude into a different format.
* @param {string} inLat - Input latitude to be converted. Use this for supplying single values for conversion (e.g. geohash)
* @param {string} inLong - Input longitude to be converted
* @param {string} inFormat - Format of the input coordinates
* @param {string} outFormat - Format to convert to
* @param {number} precision - Precision of the result
* @returns {string[]} Array containing the converted latitude and longitude
*/
export function convertCoordinates (inLat, inLong, inFormat, outFormat, precision) {
let convLat = inLat;
let convLong = inLong;
if (inFormat === "Geohash") {
const hash = geohash.decode(inLat);
convLat = hash.latitude.toString();
convLong = hash.longitude.toString();
} else if (inFormat === "Military Grid Reference System") {
const result = mgrs.toPoint(inLat.replace(" ", ""));
convLat = result[1];
convLong = result[0];
} else {
convLat = convertSingleCoordinate(inLat, inFormat, "Decimal Degrees", 15).split("°");
convLong = convertSingleCoordinate(inLong, inFormat, "Decimal Degrees", 15).split("°");
}
if (outFormat === "Geohash") {
convLat = geohash.encode(parseFloat(convLat), parseFloat(convLong), precision);
} else if (outFormat === "Military Grid Reference System") {
convLat = mgrs.forward([parseFloat(convLong), parseFloat(convLat)], precision);
} else {
convLat = convertSingleCoordinate(convLat.toString(), "Decimal Degrees", outFormat, precision);
convLong = convertSingleCoordinate(convLong.toString(), "Decimal Degrees", outFormat, precision);
}
return [convLat, convLong];
}
/**
* @param {string} input - The input co-ordinate to be converted
* @param {string} inFormat - The format of the input co-ordinates
* @param {string} outFormat - The format which input should be converted to
* @param {boolean} returnRaw - When true, returns the raw float instead of a String
* @returns {string|{Object}} The converted co-ordinate result, as either the raw object or a formatted string
*/
export function convertSingleCoordinate (input, inFormat, outFormat, precision, returnRaw = false){
let converted;
precision = Math.pow(10, precision);
const convData = splitInput(input);
// Convert everything to decimal degrees first
switch (inFormat) {
case "Degrees Minutes Seconds":
if (convData.length < 3) {
throw "Invalid co-ordinates format.";
}
converted = convDMSToDD(convData[0], convData[1], convData[2], precision);
break;
case "Degrees Decimal Minutes":
if (convData.length < 2) {
throw "Invalid co-ordinates format.";
}
converted = convDDMToDD(convData[0], convData[1], precision);
break;
case "Decimal Degrees":
if (convData.length < 1) {
throw "Invalid co-ordinates format.";
}
converted = convDDToDD(convData[0], precision);
break;
default:
throw "Unknown input format selection.";
}
// Convert from decimal degrees to the output format
switch (outFormat) {
case "Decimal Degrees":
break;
case "Degrees Minutes Seconds":
converted = convDDToDMS(converted.degrees);
break;
case "Degrees Decimal Minutes":
converted = convDDToDDM(converted.degrees, precision);
break;
default:
throw "Unknown output format selection.";
}
if (returnRaw) {
return converted;
} else {
return converted.string;
}
}
/**
* Split up the input using a space, and sanitise the result
* @param {string} input - The input data to be split
* @returns {number[]} An array of the different items in the string, stored as floats
*/
function splitInput (input){
const split = [];
input.split(" ").forEach(item => {
// Remove any character that isn't a digit
item = item.replace(/[^0-9.-]/g, "");
if (item.length > 0){
split.push(parseFloat(item, 10));
}
});
return split;
}
/**
* Convert Degrees Minutes Seconds to Decimal Degrees
* @param {number} degrees - The degrees of the input co-ordinates
* @param {number} minutes - The minutes of the input co-ordinates
* @param {number} seconds - The seconds of the input co-ordinates
* @param {number} precision - The precision the result should be rounded to
* @returns {{string: string, degrees: number}} An object containing the raw converted value (obj.degrees), and a formatted string version (obj.string)
*/
function convDMSToDD (degrees, minutes, seconds, precision){
const converted = new Object();
converted.degrees = degrees + (minutes / 60) + (seconds / 3600);
converted.string = (Math.round(converted.degrees * precision) / precision) + "°";
return converted;
}
/**
* Convert Decimal Degrees Minutes to Decimal Degrees
* @param {number} degrees - The input degrees to be converted
* @param {number} minutes - The input minutes to be converted
* @param {number} precision - The precision which the result should be rounded to
* @returns {{string: string, degrees: number}} An object containing the raw converted value (obj.degrees), and a formatted string version (obj.string)
*/
function convDDMToDD (degrees, minutes, precision) {
const converted = new Object();
converted.degrees = degrees + minutes / 60;
converted.string = ((Math.round(converted.degrees * precision) / precision) + "°");
return converted;
}
/**
* Convert Decimal Degrees to Decimal Degrees
* Doesn't affect the input, just puts it into an object
* @param {number} degrees - The input degrees to be converted
* @param {number} precision - The precision which the result should be rounded to
* @returns {{string: string, degrees: number}} An object containing the raw converted value (obj.degrees), and a formatted string version (obj.string)
*/
function convDDToDD (degrees, precision) {
const converted = new Object();
converted.degrees = degrees;
converted.string = Math.round(converted.degrees * precision) / precision + "°";
return converted;
}
/**
* Convert Decimal Degrees to Degrees Minutes Seconds
* @param {number} decDegrees - The input data to be converted
* @returns {{string: string, degrees: number, minutes: number, seconds: number}} An object containing the raw converted value as separate numbers (.degrees, .minutes, .seconds), and a formatted string version (obj.string)
*/
function convDDToDMS (decDegrees) {
const degrees = Math.floor(decDegrees);
const minutes = Math.floor(60 * (decDegrees - degrees));
const seconds = Math.round(3600 * (decDegrees - degrees) - 60 * minutes);
const converted = new Object();
converted.degrees = degrees;
converted.minutes = minutes;
converted.seconds = seconds;
converted.string = degrees + "° " + minutes + "' " + seconds + "\"";
return converted;
}
/**
* Convert Decimal Degrees to Degrees Decimal Minutes
* @param {number} decDegrees - The input degrees to be converted
* @param {number} precision - The precision the input data should be rounded to
* @returns {{string: string, degrees: number, minutes: number}} An object containing the raw converted value as separate numbers (.degrees, .minutes), and a formatted string version (obj.string)
*/
function convDDToDDM (decDegrees, precision) {
const degrees = Math.floor(decDegrees);
const minutes = decDegrees - degrees;
const decMinutes = Math.round((minutes * 60) * precision) / precision;
const converted = new Object();
converted.degrees = degrees;
converted.minutes = decMinutes;
converted.string = degrees + "° " + decMinutes + "'";
return converted;
}