mirror of
https://github.com/gchq/CyberChef
synced 2024-12-29 05:53:11 +00:00
Tidied up co-ordinate operation
This commit is contained in:
parent
03d8bf2836
commit
69837837b0
3 changed files with 195 additions and 177 deletions
|
@ -2,8 +2,11 @@
|
||||||
All major and minor version changes will be documented in this file. Details of patch-level version changes can be found in [commit messages](https://github.com/gchq/CyberChef/commits/master).
|
All major and minor version changes will be documented in this file. Details of patch-level version changes can be found in [commit messages](https://github.com/gchq/CyberChef/commits/master).
|
||||||
|
|
||||||
|
|
||||||
|
### [8.24.0] - 2019-01-18
|
||||||
|
- 'Convert co-ordinate format' operation added [@j433866] | [#476]
|
||||||
|
|
||||||
### [8.23.0] - 2019-01-18
|
### [8.23.0] - 2019-01-18
|
||||||
- 'YARA Rules' operatio added [@artemisbot] | [#468]
|
- 'YARA Rules' operation added [@artemisbot] | [#468]
|
||||||
|
|
||||||
### [8.22.0] - 2019-01-10
|
### [8.22.0] - 2019-01-10
|
||||||
- 'Subsection' operation added [@j433866] | [#467]
|
- 'Subsection' operation added [@j433866] | [#467]
|
||||||
|
@ -100,6 +103,7 @@ All major and minor version changes will be documented in this file. Details of
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[8.24.0]: https://github.com/gchq/CyberChef/releases/tag/v8.24.0
|
||||||
[8.23.0]: https://github.com/gchq/CyberChef/releases/tag/v8.23.0
|
[8.23.0]: https://github.com/gchq/CyberChef/releases/tag/v8.23.0
|
||||||
[8.22.0]: https://github.com/gchq/CyberChef/releases/tag/v8.22.0
|
[8.22.0]: https://github.com/gchq/CyberChef/releases/tag/v8.22.0
|
||||||
[8.21.0]: https://github.com/gchq/CyberChef/releases/tag/v8.21.0
|
[8.21.0]: https://github.com/gchq/CyberChef/releases/tag/v8.21.0
|
||||||
|
@ -181,3 +185,4 @@ All major and minor version changes will be documented in this file. Details of
|
||||||
[#461]: https://github.com/gchq/CyberChef/pull/461
|
[#461]: https://github.com/gchq/CyberChef/pull/461
|
||||||
[#467]: https://github.com/gchq/CyberChef/pull/467
|
[#467]: https://github.com/gchq/CyberChef/pull/467
|
||||||
[#468]: https://github.com/gchq/CyberChef/pull/468
|
[#468]: https://github.com/gchq/CyberChef/pull/468
|
||||||
|
[#476]: https://github.com/gchq/CyberChef/pull/476
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
import geohash from "ngeohash";
|
import geohash from "ngeohash";
|
||||||
import geodesy from "geodesy";
|
import geodesy from "geodesy";
|
||||||
|
import OperationError from "../errors/OperationError";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Co-ordinate formats
|
* Co-ordinate formats
|
||||||
|
@ -34,6 +35,7 @@ const NO_CHANGE = [
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a given latitude and longitude into a different format.
|
* Convert a given latitude and longitude into a different format.
|
||||||
|
*
|
||||||
* @param {string} input - Input string to be converted
|
* @param {string} input - Input string to be converted
|
||||||
* @param {string} inFormat - Format of the input coordinates
|
* @param {string} inFormat - Format of the input coordinates
|
||||||
* @param {string} inDelim - The delimiter splitting the lat/long of the input
|
* @param {string} inDelim - The delimiter splitting the lat/long of the input
|
||||||
|
@ -49,29 +51,40 @@ export function convertCoordinates (input, inFormat, inDelim, outFormat, outDeli
|
||||||
latlon,
|
latlon,
|
||||||
convLat,
|
convLat,
|
||||||
convLon,
|
convLon,
|
||||||
conv;
|
conv,
|
||||||
|
hash,
|
||||||
|
utm,
|
||||||
|
mgrs,
|
||||||
|
osng,
|
||||||
|
splitLat,
|
||||||
|
splitLong,
|
||||||
|
lat,
|
||||||
|
lon;
|
||||||
|
|
||||||
// Can't have a precision less than 0!
|
// Can't have a precision less than 0!
|
||||||
if (precision < 0) {
|
if (precision < 0) {
|
||||||
precision = 0;
|
precision = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inDelim === "Auto") {
|
if (inDelim === "Auto") {
|
||||||
// Try to detect a delimiter in the input.
|
// Try to detect a delimiter in the input.
|
||||||
inDelim = findDelim(input);
|
inDelim = findDelim(input);
|
||||||
if (inDelim === null) {
|
if (inDelim === null) {
|
||||||
throw "Unable to detect the input delimiter automatically.";
|
throw new OperationError("Unable to detect the input delimiter automatically.");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Convert the delimiter argument value to the actual character
|
// Convert the delimiter argument value to the actual character
|
||||||
inDelim = realDelim(inDelim);
|
inDelim = realDelim(inDelim);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inFormat === "Auto") {
|
if (inFormat === "Auto") {
|
||||||
// Try to detect the format of the input data
|
// Try to detect the format of the input data
|
||||||
inFormat = findFormat(input, inDelim);
|
inFormat = findFormat(input, inDelim);
|
||||||
if (inFormat === null) {
|
if (inFormat === null) {
|
||||||
throw "Unable to detect the input format automatically.";
|
throw new OperationError("Unable to detect the input format automatically.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert the output delimiter argument to the real character
|
// Convert the output delimiter argument to the real character
|
||||||
outDelim = realDelim(outDelim);
|
outDelim = realDelim(outDelim);
|
||||||
|
|
||||||
|
@ -91,83 +104,91 @@ export function convertCoordinates (input, inFormat, inDelim, outFormat, outDeli
|
||||||
}
|
}
|
||||||
|
|
||||||
// Conversions from the input format into a geodesy latlon object
|
// Conversions from the input format into a geodesy latlon object
|
||||||
if (inFormat === "Geohash") {
|
switch (inFormat) {
|
||||||
const hash = geohash.decode(input.replace(/[^A-Za-z0-9]/g, ""));
|
case "Geohash":
|
||||||
|
hash = geohash.decode(input.replace(/[^A-Za-z0-9]/g, ""));
|
||||||
latlon = new geodesy.LatLonEllipsoidal(hash.latitude, hash.longitude);
|
latlon = new geodesy.LatLonEllipsoidal(hash.latitude, hash.longitude);
|
||||||
} else if (inFormat === "Military Grid Reference System") {
|
break;
|
||||||
const utm = geodesy.Mgrs.parse(input.replace(/[^A-Za-z0-9]/g, "")).toUtm();
|
case "Military Grid Reference System":
|
||||||
|
utm = geodesy.Mgrs.parse(input.replace(/[^A-Za-z0-9]/g, "")).toUtm();
|
||||||
latlon = utm.toLatLonE();
|
latlon = utm.toLatLonE();
|
||||||
} else if (inFormat === "Ordnance Survey National Grid") {
|
break;
|
||||||
const osng = geodesy.OsGridRef.parse(input.replace(/[^A-Za-z0-9]/g, ""));
|
case "Ordnance Survey National Grid":
|
||||||
|
osng = geodesy.OsGridRef.parse(input.replace(/[^A-Za-z0-9]/g, ""));
|
||||||
latlon = geodesy.OsGridRef.osGridToLatLon(osng);
|
latlon = geodesy.OsGridRef.osGridToLatLon(osng);
|
||||||
} else if (inFormat === "Universal Transverse Mercator") {
|
break;
|
||||||
|
case "Universal Transverse Mercator":
|
||||||
// Geodesy needs a space between the first 2 digits and the next letter
|
// Geodesy needs a space between the first 2 digits and the next letter
|
||||||
if (/^[\d]{2}[A-Za-z]/.test(input)) {
|
if (/^[\d]{2}[A-Za-z]/.test(input)) {
|
||||||
input = input.slice(0, 2) + " " + input.slice(2);
|
input = input.slice(0, 2) + " " + input.slice(2);
|
||||||
}
|
}
|
||||||
const utm = geodesy.Utm.parse(input);
|
utm = geodesy.Utm.parse(input);
|
||||||
latlon = utm.toLatLonE();
|
latlon = utm.toLatLonE();
|
||||||
} else if (inFormat === "Degrees Minutes Seconds") {
|
break;
|
||||||
|
case "Degrees Minutes Seconds":
|
||||||
if (isPair) {
|
if (isPair) {
|
||||||
// Split up the lat/long into degrees / minutes / seconds values
|
// Split up the lat/long into degrees / minutes / seconds values
|
||||||
const splitLat = splitInput(split[0]),
|
splitLat = splitInput(split[0]);
|
||||||
splitLong = splitInput(split[1]);
|
splitLong = splitInput(split[1]);
|
||||||
|
|
||||||
if (splitLat.length >= 3 && splitLong.length >= 3) {
|
if (splitLat.length >= 3 && splitLong.length >= 3) {
|
||||||
const lat = convDMSToDD(splitLat[0], splitLat[1], splitLat[2], 10);
|
lat = convDMSToDD(splitLat[0], splitLat[1], splitLat[2], 10);
|
||||||
const long = convDMSToDD(splitLong[0], splitLong[1], splitLong[2], 10);
|
lon = convDMSToDD(splitLong[0], splitLong[1], splitLong[2], 10);
|
||||||
latlon = new geodesy.LatLonEllipsoidal(lat.degrees, long.degrees);
|
latlon = new geodesy.LatLonEllipsoidal(lat.degrees, lon.degrees);
|
||||||
} else {
|
} else {
|
||||||
throw "Invalid co-ordinate format for Degrees Minutes Seconds";
|
throw new OperationError("Invalid co-ordinate format for Degrees Minutes Seconds");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Not a pair, so only try to convert one set of co-ordinates
|
// Not a pair, so only try to convert one set of co-ordinates
|
||||||
const splitLat = splitInput(split[0]);
|
splitLat = splitInput(split[0]);
|
||||||
if (splitLat.length >= 3) {
|
if (splitLat.length >= 3) {
|
||||||
const lat = convDMSToDD(splitLat[0], splitLat[1], splitLat[2]);
|
lat = convDMSToDD(splitLat[0], splitLat[1], splitLat[2]);
|
||||||
latlon = new geodesy.LatLonEllipsoidal(lat.degrees, lat.degrees);
|
latlon = new geodesy.LatLonEllipsoidal(lat.degrees, lat.degrees);
|
||||||
} else {
|
} else {
|
||||||
throw "Invalid co-ordinate format for Degrees Minutes Seconds";
|
throw new OperationError("Invalid co-ordinate format for Degrees Minutes Seconds");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (inFormat === "Degrees Decimal Minutes") {
|
break;
|
||||||
|
case "Degrees Decimal Minutes":
|
||||||
if (isPair) {
|
if (isPair) {
|
||||||
const splitLat = splitInput(split[0]);
|
splitLat = splitInput(split[0]);
|
||||||
const splitLong = splitInput(split[1]);
|
splitLong = splitInput(split[1]);
|
||||||
if (splitLat.length !== 2 || splitLong.length !== 2) {
|
if (splitLat.length !== 2 || splitLong.length !== 2) {
|
||||||
throw "Invalid co-ordinate format for Degrees Decimal Minutes.";
|
throw new OperationError("Invalid co-ordinate format for Degrees Decimal Minutes.");
|
||||||
}
|
}
|
||||||
// Convert to decimal degrees, and then convert to a geodesy object
|
// Convert to decimal degrees, and then convert to a geodesy object
|
||||||
const lat = convDDMToDD(splitLat[0], splitLat[1], 10);
|
lat = convDDMToDD(splitLat[0], splitLat[1], 10);
|
||||||
const long = convDDMToDD(splitLong[0], splitLong[1], 10);
|
lon = convDDMToDD(splitLong[0], splitLong[1], 10);
|
||||||
latlon = new geodesy.LatLonEllipsoidal(lat.degrees, long.degrees);
|
latlon = new geodesy.LatLonEllipsoidal(lat.degrees, lon.degrees);
|
||||||
} else {
|
} else {
|
||||||
// Not a pair, so only try to convert one set of co-ordinates
|
// Not a pair, so only try to convert one set of co-ordinates
|
||||||
const splitLat = splitInput(input);
|
splitLat = splitInput(input);
|
||||||
if (splitLat.length !== 2) {
|
if (splitLat.length !== 2) {
|
||||||
throw "Invalid co-ordinate format for Degrees Decimal Minutes.";
|
throw new OperationError("Invalid co-ordinate format for Degrees Decimal Minutes.");
|
||||||
}
|
}
|
||||||
const lat = convDDMToDD(splitLat[0], splitLat[1], 10);
|
lat = convDDMToDD(splitLat[0], splitLat[1], 10);
|
||||||
latlon = new geodesy.LatLonEllipsoidal(lat.degrees, lat.degrees);
|
latlon = new geodesy.LatLonEllipsoidal(lat.degrees, lat.degrees);
|
||||||
}
|
}
|
||||||
} else if (inFormat === "Decimal Degrees") {
|
break;
|
||||||
|
case "Decimal Degrees":
|
||||||
if (isPair) {
|
if (isPair) {
|
||||||
const splitLat = splitInput(split[0]);
|
splitLat = splitInput(split[0]);
|
||||||
const splitLong = splitInput(split[1]);
|
splitLong = splitInput(split[1]);
|
||||||
if (splitLat.length !== 1 || splitLong.length !== 1) {
|
if (splitLat.length !== 1 || splitLong.length !== 1) {
|
||||||
throw "Invalid co-ordinate format for Decimal Degrees.";
|
throw new OperationError("Invalid co-ordinate format for Decimal Degrees.");
|
||||||
}
|
}
|
||||||
latlon = new geodesy.LatLonEllipsoidal(splitLat[0], splitLong[0]);
|
latlon = new geodesy.LatLonEllipsoidal(splitLat[0], splitLong[0]);
|
||||||
} else {
|
} else {
|
||||||
// Not a pair, so only try to convert one set of co-ordinates
|
// Not a pair, so only try to convert one set of co-ordinates
|
||||||
const splitLat = splitInput(split[0]);
|
splitLat = splitInput(split[0]);
|
||||||
if (splitLat.length !== 1) {
|
if (splitLat.length !== 1) {
|
||||||
throw "Invalid co-ordinate format for Decimal Degrees.";
|
throw new OperationError("Invalid co-ordinate format for Decimal Degrees.");
|
||||||
}
|
}
|
||||||
latlon = new geodesy.LatLonEllipsoidal(splitLat[0], splitLat[0]);
|
latlon = new geodesy.LatLonEllipsoidal(splitLat[0], splitLat[0]);
|
||||||
}
|
}
|
||||||
} else {
|
break;
|
||||||
throw `Unknown input format '${inFormat}'`;
|
default:
|
||||||
|
throw new OperationError(`Unknown input format '${inFormat}'`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Everything is now a geodesy latlon object
|
// Everything is now a geodesy latlon object
|
||||||
|
@ -179,40 +200,47 @@ export function convertCoordinates (input, inFormat, inDelim, outFormat, outDeli
|
||||||
if (dirs && dirs.length >= 1) {
|
if (dirs && dirs.length >= 1) {
|
||||||
// Make positive lat/lon values with S/W directions into negative values
|
// Make positive lat/lon values with S/W directions into negative values
|
||||||
if (dirs[0] === "S" || dirs[0] === "W" && latlon.lat > 0) {
|
if (dirs[0] === "S" || dirs[0] === "W" && latlon.lat > 0) {
|
||||||
latlon.lat = 0 - latlon.lat;
|
latlon.lat = -latlon.lat;
|
||||||
}
|
}
|
||||||
if (dirs.length >= 2) {
|
if (dirs.length >= 2) {
|
||||||
if (dirs[1] === "S" || dirs[1] === "W" && latlon.lon > 0) {
|
if (dirs[1] === "S" || dirs[1] === "W" && latlon.lon > 0) {
|
||||||
latlon.lon = 0 - latlon.lon;
|
latlon.lon = -latlon.lon;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to find the compass directions of the lat and long
|
// Try to find the compass directions of the lat and long
|
||||||
const [latDir, longDir] = findDirs(latlon.lat + "," + latlon.lon, ",");
|
const [latDir, longDir] = findDirs(latlon.lat + "," + latlon.lon, ",");
|
||||||
|
|
||||||
// Output conversions for each output format
|
// Output conversions for each output format
|
||||||
if (outFormat === "Decimal Degrees") {
|
switch (outFormat) {
|
||||||
|
case "Decimal Degrees":
|
||||||
// We could use the built in latlon.toString(),
|
// We could use the built in latlon.toString(),
|
||||||
// but this makes adjusting the output harder
|
// but this makes adjusting the output harder
|
||||||
const lat = convDDToDD(latlon.lat, precision);
|
lat = convDDToDD(latlon.lat, precision);
|
||||||
const lon = convDDToDD(latlon.lon, precision);
|
lon = convDDToDD(latlon.lon, precision);
|
||||||
convLat = lat.string;
|
convLat = lat.string;
|
||||||
convLon = lon.string;
|
convLon = lon.string;
|
||||||
} else if (outFormat === "Degrees Decimal Minutes") {
|
break;
|
||||||
const lat = convDDToDDM(latlon.lat, precision);
|
case "Degrees Decimal Minutes":
|
||||||
const lon = convDDToDDM(latlon.lon, precision);
|
lat = convDDToDDM(latlon.lat, precision);
|
||||||
|
lon = convDDToDDM(latlon.lon, precision);
|
||||||
convLat = lat.string;
|
convLat = lat.string;
|
||||||
convLon = lon.string;
|
convLon = lon.string;
|
||||||
} else if (outFormat === "Degrees Minutes Seconds") {
|
break;
|
||||||
const lat = convDDToDMS(latlon.lat, precision);
|
case "Degrees Minutes Seconds":
|
||||||
const lon = convDDToDMS(latlon.lon, precision);
|
lat = convDDToDMS(latlon.lat, precision);
|
||||||
|
lon = convDDToDMS(latlon.lon, precision);
|
||||||
convLat = lat.string;
|
convLat = lat.string;
|
||||||
convLon = lon.string;
|
convLon = lon.string;
|
||||||
} else if (outFormat === "Geohash") {
|
break;
|
||||||
|
case "Geohash":
|
||||||
convLat = geohash.encode(latlon.lat, latlon.lon, precision);
|
convLat = geohash.encode(latlon.lat, latlon.lon, precision);
|
||||||
} else if (outFormat === "Military Grid Reference System") {
|
break;
|
||||||
const utm = latlon.toUtm();
|
case "Military Grid Reference System":
|
||||||
const mgrs = utm.toMgrs();
|
utm = latlon.toUtm();
|
||||||
|
mgrs = utm.toMgrs();
|
||||||
// MGRS wants a precision that's an even number between 2 and 10
|
// MGRS wants a precision that's an even number between 2 and 10
|
||||||
if (precision % 2 !== 0) {
|
if (precision % 2 !== 0) {
|
||||||
precision = precision + 1;
|
precision = precision + 1;
|
||||||
|
@ -221,10 +249,11 @@ export function convertCoordinates (input, inFormat, inDelim, outFormat, outDeli
|
||||||
precision = 10;
|
precision = 10;
|
||||||
}
|
}
|
||||||
convLat = mgrs.toString(precision);
|
convLat = mgrs.toString(precision);
|
||||||
} else if (outFormat === "Ordnance Survey National Grid") {
|
break;
|
||||||
const osng = geodesy.OsGridRef.latLonToOsGrid(latlon);
|
case "Ordnance Survey National Grid":
|
||||||
|
osng = geodesy.OsGridRef.latLonToOsGrid(latlon);
|
||||||
if (osng.toString() === "") {
|
if (osng.toString() === "") {
|
||||||
throw "Could not convert co-ordinates to OS National Grid. Are the co-ordinates in range?";
|
throw new OperationError("Could not convert co-ordinates to OS National Grid. Are the co-ordinates in range?");
|
||||||
}
|
}
|
||||||
// OSNG wants a precision that's an even number between 2 and 10
|
// OSNG wants a precision that's an even number between 2 and 10
|
||||||
if (precision % 2 !== 0) {
|
if (precision % 2 !== 0) {
|
||||||
|
@ -234,13 +263,15 @@ export function convertCoordinates (input, inFormat, inDelim, outFormat, outDeli
|
||||||
precision = 10;
|
precision = 10;
|
||||||
}
|
}
|
||||||
convLat = osng.toString(precision);
|
convLat = osng.toString(precision);
|
||||||
} else if (outFormat === "Universal Transverse Mercator") {
|
break;
|
||||||
const utm = latlon.toUtm();
|
case "Universal Transverse Mercator":
|
||||||
|
utm = latlon.toUtm();
|
||||||
convLat = utm.toString(precision);
|
convLat = utm.toString(precision);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (convLat === undefined) {
|
if (convLat === undefined) {
|
||||||
throw "Error converting co-ordinates.";
|
throw new OperationError("Error converting co-ordinates.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (outFormat.includes("Degrees")) {
|
if (outFormat.includes("Degrees")) {
|
||||||
|
@ -283,6 +314,7 @@ export function convertCoordinates (input, inFormat, inDelim, outFormat, outDeli
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Split up the input using a space or degrees signs, and sanitise the result
|
* Split up the input using a space or degrees signs, and sanitise the result
|
||||||
|
*
|
||||||
* @param {string} input - The input data to be split
|
* @param {string} input - The input data to be split
|
||||||
* @returns {number[]} An array of the different items in the string, stored as floats
|
* @returns {number[]} An array of the different items in the string, stored as floats
|
||||||
*/
|
*/
|
||||||
|
@ -302,6 +334,7 @@ function splitInput (input){
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert Degrees Minutes Seconds to Decimal Degrees
|
* Convert Degrees Minutes Seconds to Decimal Degrees
|
||||||
|
*
|
||||||
* @param {number} degrees - The degrees of the input co-ordinates
|
* @param {number} degrees - The degrees of the input co-ordinates
|
||||||
* @param {number} minutes - The minutes 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} seconds - The seconds of the input co-ordinates
|
||||||
|
@ -324,6 +357,7 @@ function convDMSToDD (degrees, minutes, seconds, precision){
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert Decimal Degrees Minutes to Decimal Degrees
|
* Convert Decimal Degrees Minutes to Decimal Degrees
|
||||||
|
*
|
||||||
* @param {number} degrees - The input degrees to be converted
|
* @param {number} degrees - The input degrees to be converted
|
||||||
* @param {number} minutes - The input minutes to be converted
|
* @param {number} minutes - The input minutes to be converted
|
||||||
* @param {number} precision - The precision which the result should be rounded to
|
* @param {number} precision - The precision which the result should be rounded to
|
||||||
|
@ -345,6 +379,7 @@ function convDDMToDD (degrees, minutes, precision) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert Decimal Degrees to Decimal Degrees
|
* Convert Decimal Degrees to Decimal Degrees
|
||||||
|
*
|
||||||
* Doesn't affect the input, just puts it into an object
|
* Doesn't affect the input, just puts it into an object
|
||||||
* @param {number} degrees - The input degrees to be converted
|
* @param {number} degrees - The input degrees to be converted
|
||||||
* @param {number} precision - The precision which the result should be rounded to
|
* @param {number} precision - The precision which the result should be rounded to
|
||||||
|
@ -359,6 +394,7 @@ function convDDToDD (degrees, precision) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert Decimal Degrees to Degrees Minutes Seconds
|
* Convert Decimal Degrees to Degrees Minutes Seconds
|
||||||
|
*
|
||||||
* @param {number} decDegrees - The input data to be converted
|
* @param {number} decDegrees - The input data to be converted
|
||||||
* @param {number} precision - The precision which the result should be rounded to
|
* @param {number} precision - The precision which the result should be rounded to
|
||||||
* @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)
|
* @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)
|
||||||
|
@ -383,6 +419,7 @@ function convDDToDMS (decDegrees, precision) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert Decimal Degrees to Degrees Decimal Minutes
|
* Convert Decimal Degrees to Degrees Decimal Minutes
|
||||||
|
*
|
||||||
* @param {number} decDegrees - The input degrees to be converted
|
* @param {number} decDegrees - The input degrees to be converted
|
||||||
* @param {number} precision - The precision the input data should be rounded to
|
* @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)
|
* @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)
|
||||||
|
@ -407,6 +444,7 @@ function convDDToDDM (decDegrees, precision) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds and returns the compass directions in an input string
|
* Finds and returns the compass directions in an input string
|
||||||
|
*
|
||||||
* @param {string} input - The input co-ordinates containing the direction
|
* @param {string} input - The input co-ordinates containing the direction
|
||||||
* @param {string} delim - The delimiter separating latitide and longitude
|
* @param {string} delim - The delimiter separating latitide and longitude
|
||||||
* @returns {string[]} String array containing the latitude and longitude directions
|
* @returns {string[]} String array containing the latitude and longitude directions
|
||||||
|
@ -421,13 +459,10 @@ export function findDirs(input, delim) {
|
||||||
// If there's actually compass directions
|
// If there's actually compass directions
|
||||||
// in the input, use these to work out the direction
|
// in the input, use these to work out the direction
|
||||||
if (dirs.length <= 2 && dirs.length >= 1) {
|
if (dirs.length <= 2 && dirs.length >= 1) {
|
||||||
if (dirs.length === 2) {
|
return dirs.length === 2 ? [dirs[0], dirs[1]] : [dirs[0], ""];
|
||||||
return [dirs[0], dirs[1]];
|
|
||||||
} else {
|
|
||||||
return [dirs[0], ""];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nothing was returned, so guess the directions
|
// Nothing was returned, so guess the directions
|
||||||
let lat = upperInput,
|
let lat = upperInput,
|
||||||
long,
|
long,
|
||||||
|
@ -440,43 +475,29 @@ export function findDirs(input, delim) {
|
||||||
if (split[0] !== "") {
|
if (split[0] !== "") {
|
||||||
lat = split[0];
|
lat = split[0];
|
||||||
}
|
}
|
||||||
if (split.length >= 2) {
|
if (split.length >= 2 && split[1] !== "") {
|
||||||
if (split[1] !== "") {
|
|
||||||
long = split[1];
|
long = split[1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
const split = upperInput.split(dirExp);
|
const split = upperInput.split(dirExp);
|
||||||
if (split.length > 1) {
|
if (split.length > 1) {
|
||||||
if (split[0] === "") {
|
lat = split[0] === "" ? split[1] : split[0];
|
||||||
lat = split[1];
|
if (split.length > 2 && split[2] !== "") {
|
||||||
} else {
|
|
||||||
lat = split[0];
|
|
||||||
}
|
|
||||||
if (split.length > 2) {
|
|
||||||
if (split[2] !== "") {
|
|
||||||
long = split[2];
|
long = split[2];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (lat) {
|
if (lat) {
|
||||||
lat = parseFloat(lat);
|
lat = parseFloat(lat);
|
||||||
if (lat < 0) {
|
latDir = lat < 0 ? "S" : "N";
|
||||||
latDir = "S";
|
|
||||||
} else {
|
|
||||||
latDir = "N";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (long) {
|
if (long) {
|
||||||
long = parseFloat(long);
|
long = parseFloat(long);
|
||||||
if (long < 0) {
|
longDir = long < 0 ? "W" : "E";
|
||||||
longDir = "W";
|
|
||||||
} else {
|
|
||||||
longDir = "E";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return [latDir, longDir];
|
return [latDir, longDir];
|
||||||
|
@ -484,6 +505,7 @@ export function findDirs(input, delim) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detects the co-ordinate format of the input data
|
* Detects the co-ordinate format of the input data
|
||||||
|
*
|
||||||
* @param {string} input - The input data whose format we need to detect
|
* @param {string} input - The input data whose format we need to detect
|
||||||
* @param {string} delim - The delimiter separating the data in input
|
* @param {string} delim - The delimiter separating the data in input
|
||||||
* @returns {string} The input format
|
* @returns {string} The input format
|
||||||
|
@ -495,25 +517,19 @@ export function findFormat (input, delim) {
|
||||||
geohashPattern = new RegExp(/^[0123456789BCDEFGHJKMNPQRSTUVWXYZ]+$/),
|
geohashPattern = new RegExp(/^[0123456789BCDEFGHJKMNPQRSTUVWXYZ]+$/),
|
||||||
utmPattern = new RegExp(/^[0-9]{2}\s?[C-HJ-NP-X]\s[0-9.]+\s?[0-9.]+$/),
|
utmPattern = new RegExp(/^[0-9]{2}\s?[C-HJ-NP-X]\s[0-9.]+\s?[0-9.]+$/),
|
||||||
degPattern = new RegExp(/[°'"]/g);
|
degPattern = new RegExp(/[°'"]/g);
|
||||||
|
|
||||||
input = input.trim();
|
input = input.trim();
|
||||||
|
|
||||||
if (delim !== null && delim.includes("Direction")) {
|
if (delim !== null && delim.includes("Direction")) {
|
||||||
const split = input.split(/[NnEeSsWw]/);
|
const split = input.split(/[NnEeSsWw]/);
|
||||||
if (split.length > 1) {
|
if (split.length > 1) {
|
||||||
if (split[0] === "") {
|
testData = split[0] === "" ? split[1] : split[0];
|
||||||
testData = split[1];
|
|
||||||
} else {
|
|
||||||
testData = split[0];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (delim !== null && delim !== "") {
|
} else if (delim !== null && delim !== "") {
|
||||||
if (input.includes(delim)) {
|
if (input.includes(delim)) {
|
||||||
const split = input.split(delim);
|
const split = input.split(delim);
|
||||||
if (split.length > 1) {
|
if (split.length > 1) {
|
||||||
if (split[0] === "") {
|
testData = split[0] === "" ? split[1] : split[0];
|
||||||
testData = split[1];
|
|
||||||
} else {
|
|
||||||
testData = split[0];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
testData = input;
|
testData = input;
|
||||||
|
@ -523,20 +539,17 @@ export function findFormat (input, delim) {
|
||||||
// Test non-degrees formats
|
// Test non-degrees formats
|
||||||
if (!degPattern.test(input)) {
|
if (!degPattern.test(input)) {
|
||||||
const filteredInput = input.toUpperCase().replace(delim, "");
|
const filteredInput = input.toUpperCase().replace(delim, "");
|
||||||
const isMgrs = mgrsPattern.test(filteredInput);
|
|
||||||
const isOsng = osngPattern.test(filteredInput);
|
if (utmPattern.test(filteredInput)) {
|
||||||
const isGeohash = geohashPattern.test(filteredInput);
|
|
||||||
const isUtm = utmPattern.test(filteredInput);
|
|
||||||
if (isUtm) {
|
|
||||||
return "Universal Transverse Mercator";
|
return "Universal Transverse Mercator";
|
||||||
}
|
}
|
||||||
if (isMgrs) {
|
if (mgrsPattern.test(filteredInput)) {
|
||||||
return "Military Grid Reference System";
|
return "Military Grid Reference System";
|
||||||
}
|
}
|
||||||
if (isOsng) {
|
if (osngPattern.test(filteredInput)) {
|
||||||
return "Ordnance Survey National Grid";
|
return "Ordnance Survey National Grid";
|
||||||
}
|
}
|
||||||
if (isGeohash) {
|
if (geohashPattern.test(filteredInput)) {
|
||||||
return "Geohash";
|
return "Geohash";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -558,6 +571,7 @@ export function findFormat (input, delim) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Automatically find the delimeter type from the given input
|
* Automatically find the delimeter type from the given input
|
||||||
|
*
|
||||||
* @param {string} input
|
* @param {string} input
|
||||||
* @returns {string} Delimiter type
|
* @returns {string} Delimiter type
|
||||||
*/
|
*/
|
||||||
|
@ -594,6 +608,7 @@ export function findDelim (input) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the real string for a delimiter name.
|
* Gets the real string for a delimiter name.
|
||||||
|
*
|
||||||
* @param {string} delim The delimiter to be matched
|
* @param {string} delim The delimiter to be matched
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
|
@ -610,7 +625,9 @@ export function realDelim (delim) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if a zero is negative
|
* Returns true if a zero is negative
|
||||||
|
*
|
||||||
* @param {number} zero
|
* @param {number} zero
|
||||||
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
function isNegativeZero(zero) {
|
function isNegativeZero(zero) {
|
||||||
return zero === 0 && (1/zero < 0);
|
return zero === 0 && (1/zero < 0);
|
||||||
|
@ -618,6 +635,7 @@ function isNegativeZero(zero) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rounds a number to a specified number of decimal places
|
* Rounds a number to a specified number of decimal places
|
||||||
|
*
|
||||||
* @param {number} input - The number to be rounded
|
* @param {number} input - The number to be rounded
|
||||||
* @param {precision} precision - The number of decimal places the number should be rounded to
|
* @param {precision} precision - The number of decimal places the number should be rounded to
|
||||||
* @returns {number}
|
* @returns {number}
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import Operation from "../Operation";
|
import Operation from "../Operation";
|
||||||
import OperationError from "../errors/OperationError";
|
|
||||||
import {FORMATS, convertCoordinates} from "../lib/ConvertCoordinates";
|
import {FORMATS, convertCoordinates} from "../lib/ConvertCoordinates";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,7 +20,7 @@ class ConvertCoordinateFormat extends Operation {
|
||||||
|
|
||||||
this.name = "Convert co-ordinate format";
|
this.name = "Convert co-ordinate format";
|
||||||
this.module = "Hashing";
|
this.module = "Hashing";
|
||||||
this.description = "Convert geographical coordinates between different formats.<br><br>Supported formats:<ul><li>Degrees Minutes Seconds (DMS)</li><li>Degrees Decimal Minutes (DDM)</li><li>Decimal Degrees (DD)</li><li>Geohash</li><li>Military Grid Reference System (MGRS)</li><li>Ordnance Survey National Grid (OSNG)</li><li>Universal Transverse Mercator (UTM)</li></ul><br>The operation can try to detect the input co-ordinate format and delimiter automatically, but this may not always work correctly.";
|
this.description = "Converts geographical coordinates between different formats.<br><br>Supported formats:<ul><li>Degrees Minutes Seconds (DMS)</li><li>Degrees Decimal Minutes (DDM)</li><li>Decimal Degrees (DD)</li><li>Geohash</li><li>Military Grid Reference System (MGRS)</li><li>Ordnance Survey National Grid (OSNG)</li><li>Universal Transverse Mercator (UTM)</li></ul><br>The operation can try to detect the input co-ordinate format and delimiter automatically, but this may not always work correctly.";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/Geographic_coordinate_conversion";
|
this.infoURL = "https://wikipedia.org/wiki/Geographic_coordinate_conversion";
|
||||||
this.inputType = "string";
|
this.inputType = "string";
|
||||||
this.outputType = "string";
|
this.outputType = "string";
|
||||||
|
@ -85,12 +84,8 @@ class ConvertCoordinateFormat extends Operation {
|
||||||
run(input, args) {
|
run(input, args) {
|
||||||
if (input.replace(/[\s+]/g, "") !== "") {
|
if (input.replace(/[\s+]/g, "") !== "") {
|
||||||
const [inFormat, inDelim, outFormat, outDelim, incDirection, precision] = args;
|
const [inFormat, inDelim, outFormat, outDelim, incDirection, precision] = args;
|
||||||
try {
|
|
||||||
const result = convertCoordinates(input, inFormat, inDelim, outFormat, outDelim, incDirection, precision);
|
const result = convertCoordinates(input, inFormat, inDelim, outFormat, outDelim, incDirection, precision);
|
||||||
return result;
|
return result;
|
||||||
} catch (error) {
|
|
||||||
throw new OperationError(error);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue