|
@@ -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;
|
|
|
+}
|