Merge branch 'j433866-coordinates'
This commit is contained in:
commit
6f8a5ea1be
@ -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
|
||||||
|
5
package-lock.json
generated
5
package-lock.json
generated
@ -5699,6 +5699,11 @@
|
|||||||
"globule": "^1.0.0"
|
"globule": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"geodesy": {
|
||||||
|
"version": "1.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/geodesy/-/geodesy-1.1.3.tgz",
|
||||||
|
"integrity": "sha512-H/0XSd1KjKZGZ2YGZcOYzRyY/foYAawwTEumNSo+YUwf+u5d4CfvBRg2i2Qimrx9yUEjWR8hLvMnhghuVFN0Zg=="
|
||||||
|
},
|
||||||
"get-caller-file": {
|
"get-caller-file": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
|
||||||
|
@ -95,6 +95,7 @@
|
|||||||
"esprima": "^4.0.1",
|
"esprima": "^4.0.1",
|
||||||
"exif-parser": "^0.1.12",
|
"exif-parser": "^0.1.12",
|
||||||
"file-saver": "^2.0.0",
|
"file-saver": "^2.0.0",
|
||||||
|
"geodesy": "^1.1.3",
|
||||||
"highlight.js": "^9.13.1",
|
"highlight.js": "^9.13.1",
|
||||||
"jimp": "^0.6.0",
|
"jimp": "^0.6.0",
|
||||||
"jquery": "^3.3.1",
|
"jquery": "^3.3.1",
|
||||||
|
@ -215,6 +215,7 @@
|
|||||||
"Convert mass",
|
"Convert mass",
|
||||||
"Convert speed",
|
"Convert speed",
|
||||||
"Convert data units",
|
"Convert data units",
|
||||||
|
"Convert co-ordinate format",
|
||||||
"Parse UNIX file permissions",
|
"Parse UNIX file permissions",
|
||||||
"Swap endianness",
|
"Swap endianness",
|
||||||
"Parse colour code",
|
"Parse colour code",
|
||||||
@ -306,9 +307,7 @@
|
|||||||
"Adler-32 Checksum",
|
"Adler-32 Checksum",
|
||||||
"CRC-16 Checksum",
|
"CRC-16 Checksum",
|
||||||
"CRC-32 Checksum",
|
"CRC-32 Checksum",
|
||||||
"TCP/IP Checksum",
|
"TCP/IP Checksum"
|
||||||
"To Geohash",
|
|
||||||
"From Geohash"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
646
src/core/lib/ConvertCoordinates.mjs
Normal file
646
src/core/lib/ConvertCoordinates.mjs
Normal file
@ -0,0 +1,646 @@
|
|||||||
|
/**
|
||||||
|
* Co-ordinate conversion resources.
|
||||||
|
*
|
||||||
|
* @author j433866 [j433866@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2019
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import geohash from "ngeohash";
|
||||||
|
import geodesy from "geodesy";
|
||||||
|
import OperationError from "../errors/OperationError";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Co-ordinate formats
|
||||||
|
*/
|
||||||
|
export const FORMATS = [
|
||||||
|
"Degrees Minutes Seconds",
|
||||||
|
"Degrees Decimal Minutes",
|
||||||
|
"Decimal Degrees",
|
||||||
|
"Geohash",
|
||||||
|
"Military Grid Reference System",
|
||||||
|
"Ordnance Survey National Grid",
|
||||||
|
"Universal Transverse Mercator"
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats that should be passed to the conversion module as-is
|
||||||
|
*/
|
||||||
|
const NO_CHANGE = [
|
||||||
|
"Geohash",
|
||||||
|
"Military Grid Reference System",
|
||||||
|
"Ordnance Survey National Grid",
|
||||||
|
"Universal Transverse Mercator",
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a given latitude and longitude into a different format.
|
||||||
|
*
|
||||||
|
* @param {string} input - Input string to be converted
|
||||||
|
* @param {string} inFormat - Format of the input coordinates
|
||||||
|
* @param {string} inDelim - The delimiter splitting the lat/long of the input
|
||||||
|
* @param {string} outFormat - Format to convert to
|
||||||
|
* @param {string} outDelim - The delimiter to separate the output with
|
||||||
|
* @param {string} includeDir - Whether or not to include the compass direction in the output
|
||||||
|
* @param {number} precision - Precision of the result
|
||||||
|
* @returns {string} A formatted string of the converted co-ordinates
|
||||||
|
*/
|
||||||
|
export function convertCoordinates (input, inFormat, inDelim, outFormat, outDelim, includeDir, precision) {
|
||||||
|
let isPair = false,
|
||||||
|
split,
|
||||||
|
latlon,
|
||||||
|
convLat,
|
||||||
|
convLon,
|
||||||
|
conv,
|
||||||
|
hash,
|
||||||
|
utm,
|
||||||
|
mgrs,
|
||||||
|
osng,
|
||||||
|
splitLat,
|
||||||
|
splitLong,
|
||||||
|
lat,
|
||||||
|
lon;
|
||||||
|
|
||||||
|
// Can't have a precision less than 0!
|
||||||
|
if (precision < 0) {
|
||||||
|
precision = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inDelim === "Auto") {
|
||||||
|
// Try to detect a delimiter in the input.
|
||||||
|
inDelim = findDelim(input);
|
||||||
|
if (inDelim === null) {
|
||||||
|
throw new OperationError("Unable to detect the input delimiter automatically.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Convert the delimiter argument value to the actual character
|
||||||
|
inDelim = realDelim(inDelim);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inFormat === "Auto") {
|
||||||
|
// Try to detect the format of the input data
|
||||||
|
inFormat = findFormat(input, inDelim);
|
||||||
|
if (inFormat === null) {
|
||||||
|
throw new OperationError("Unable to detect the input format automatically.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the output delimiter argument to the real character
|
||||||
|
outDelim = realDelim(outDelim);
|
||||||
|
|
||||||
|
if (!NO_CHANGE.includes(inFormat)) {
|
||||||
|
split = input.split(inDelim);
|
||||||
|
// Replace any co-ordinate symbols with spaces so we can split on them later
|
||||||
|
for (let i = 0; i < split.length; i++) {
|
||||||
|
split[i] = split[i].replace(/[°˝´'"]/g, " ");
|
||||||
|
}
|
||||||
|
if (split.length > 1) {
|
||||||
|
isPair = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Remove any delimiters from the input
|
||||||
|
input = input.replace(inDelim, "");
|
||||||
|
isPair = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Conversions from the input format into a geodesy latlon object
|
||||||
|
switch (inFormat) {
|
||||||
|
case "Geohash":
|
||||||
|
hash = geohash.decode(input.replace(/[^A-Za-z0-9]/g, ""));
|
||||||
|
latlon = new geodesy.LatLonEllipsoidal(hash.latitude, hash.longitude);
|
||||||
|
break;
|
||||||
|
case "Military Grid Reference System":
|
||||||
|
utm = geodesy.Mgrs.parse(input.replace(/[^A-Za-z0-9]/g, "")).toUtm();
|
||||||
|
latlon = utm.toLatLonE();
|
||||||
|
break;
|
||||||
|
case "Ordnance Survey National Grid":
|
||||||
|
osng = geodesy.OsGridRef.parse(input.replace(/[^A-Za-z0-9]/g, ""));
|
||||||
|
latlon = geodesy.OsGridRef.osGridToLatLon(osng);
|
||||||
|
break;
|
||||||
|
case "Universal Transverse Mercator":
|
||||||
|
// Geodesy needs a space between the first 2 digits and the next letter
|
||||||
|
if (/^[\d]{2}[A-Za-z]/.test(input)) {
|
||||||
|
input = input.slice(0, 2) + " " + input.slice(2);
|
||||||
|
}
|
||||||
|
utm = geodesy.Utm.parse(input);
|
||||||
|
latlon = utm.toLatLonE();
|
||||||
|
break;
|
||||||
|
case "Degrees Minutes Seconds":
|
||||||
|
if (isPair) {
|
||||||
|
// Split up the lat/long into degrees / minutes / seconds values
|
||||||
|
splitLat = splitInput(split[0]);
|
||||||
|
splitLong = splitInput(split[1]);
|
||||||
|
|
||||||
|
if (splitLat.length >= 3 && splitLong.length >= 3) {
|
||||||
|
lat = convDMSToDD(splitLat[0], splitLat[1], splitLat[2], 10);
|
||||||
|
lon = convDMSToDD(splitLong[0], splitLong[1], splitLong[2], 10);
|
||||||
|
latlon = new geodesy.LatLonEllipsoidal(lat.degrees, lon.degrees);
|
||||||
|
} else {
|
||||||
|
throw new OperationError("Invalid co-ordinate format for Degrees Minutes Seconds");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Not a pair, so only try to convert one set of co-ordinates
|
||||||
|
splitLat = splitInput(split[0]);
|
||||||
|
if (splitLat.length >= 3) {
|
||||||
|
lat = convDMSToDD(splitLat[0], splitLat[1], splitLat[2]);
|
||||||
|
latlon = new geodesy.LatLonEllipsoidal(lat.degrees, lat.degrees);
|
||||||
|
} else {
|
||||||
|
throw new OperationError("Invalid co-ordinate format for Degrees Minutes Seconds");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "Degrees Decimal Minutes":
|
||||||
|
if (isPair) {
|
||||||
|
splitLat = splitInput(split[0]);
|
||||||
|
splitLong = splitInput(split[1]);
|
||||||
|
if (splitLat.length !== 2 || splitLong.length !== 2) {
|
||||||
|
throw new OperationError("Invalid co-ordinate format for Degrees Decimal Minutes.");
|
||||||
|
}
|
||||||
|
// Convert to decimal degrees, and then convert to a geodesy object
|
||||||
|
lat = convDDMToDD(splitLat[0], splitLat[1], 10);
|
||||||
|
lon = convDDMToDD(splitLong[0], splitLong[1], 10);
|
||||||
|
latlon = new geodesy.LatLonEllipsoidal(lat.degrees, lon.degrees);
|
||||||
|
} else {
|
||||||
|
// Not a pair, so only try to convert one set of co-ordinates
|
||||||
|
splitLat = splitInput(input);
|
||||||
|
if (splitLat.length !== 2) {
|
||||||
|
throw new OperationError("Invalid co-ordinate format for Degrees Decimal Minutes.");
|
||||||
|
}
|
||||||
|
lat = convDDMToDD(splitLat[0], splitLat[1], 10);
|
||||||
|
latlon = new geodesy.LatLonEllipsoidal(lat.degrees, lat.degrees);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "Decimal Degrees":
|
||||||
|
if (isPair) {
|
||||||
|
splitLat = splitInput(split[0]);
|
||||||
|
splitLong = splitInput(split[1]);
|
||||||
|
if (splitLat.length !== 1 || splitLong.length !== 1) {
|
||||||
|
throw new OperationError("Invalid co-ordinate format for Decimal Degrees.");
|
||||||
|
}
|
||||||
|
latlon = new geodesy.LatLonEllipsoidal(splitLat[0], splitLong[0]);
|
||||||
|
} else {
|
||||||
|
// Not a pair, so only try to convert one set of co-ordinates
|
||||||
|
splitLat = splitInput(split[0]);
|
||||||
|
if (splitLat.length !== 1) {
|
||||||
|
throw new OperationError("Invalid co-ordinate format for Decimal Degrees.");
|
||||||
|
}
|
||||||
|
latlon = new geodesy.LatLonEllipsoidal(splitLat[0], splitLat[0]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new OperationError(`Unknown input format '${inFormat}'`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Everything is now a geodesy latlon object
|
||||||
|
// These store the latitude and longitude as decimal
|
||||||
|
if (inFormat.includes("Degrees")) {
|
||||||
|
// If the input string contains directions, we need to check if they're S or W.
|
||||||
|
// If either of the directions are, we should make the decimal value negative
|
||||||
|
const dirs = input.match(/[NnEeSsWw]/g);
|
||||||
|
if (dirs && dirs.length >= 1) {
|
||||||
|
// Make positive lat/lon values with S/W directions into negative values
|
||||||
|
if (dirs[0] === "S" || dirs[0] === "W" && latlon.lat > 0) {
|
||||||
|
latlon.lat = -latlon.lat;
|
||||||
|
}
|
||||||
|
if (dirs.length >= 2) {
|
||||||
|
if (dirs[1] === "S" || dirs[1] === "W" && latlon.lon > 0) {
|
||||||
|
latlon.lon = -latlon.lon;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to find the compass directions of the lat and long
|
||||||
|
const [latDir, longDir] = findDirs(latlon.lat + "," + latlon.lon, ",");
|
||||||
|
|
||||||
|
// Output conversions for each output format
|
||||||
|
switch (outFormat) {
|
||||||
|
case "Decimal Degrees":
|
||||||
|
// We could use the built in latlon.toString(),
|
||||||
|
// but this makes adjusting the output harder
|
||||||
|
lat = convDDToDD(latlon.lat, precision);
|
||||||
|
lon = convDDToDD(latlon.lon, precision);
|
||||||
|
convLat = lat.string;
|
||||||
|
convLon = lon.string;
|
||||||
|
break;
|
||||||
|
case "Degrees Decimal Minutes":
|
||||||
|
lat = convDDToDDM(latlon.lat, precision);
|
||||||
|
lon = convDDToDDM(latlon.lon, precision);
|
||||||
|
convLat = lat.string;
|
||||||
|
convLon = lon.string;
|
||||||
|
break;
|
||||||
|
case "Degrees Minutes Seconds":
|
||||||
|
lat = convDDToDMS(latlon.lat, precision);
|
||||||
|
lon = convDDToDMS(latlon.lon, precision);
|
||||||
|
convLat = lat.string;
|
||||||
|
convLon = lon.string;
|
||||||
|
break;
|
||||||
|
case "Geohash":
|
||||||
|
convLat = geohash.encode(latlon.lat, latlon.lon, precision);
|
||||||
|
break;
|
||||||
|
case "Military Grid Reference System":
|
||||||
|
utm = latlon.toUtm();
|
||||||
|
mgrs = utm.toMgrs();
|
||||||
|
// MGRS wants a precision that's an even number between 2 and 10
|
||||||
|
if (precision % 2 !== 0) {
|
||||||
|
precision = precision + 1;
|
||||||
|
}
|
||||||
|
if (precision > 10) {
|
||||||
|
precision = 10;
|
||||||
|
}
|
||||||
|
convLat = mgrs.toString(precision);
|
||||||
|
break;
|
||||||
|
case "Ordnance Survey National Grid":
|
||||||
|
osng = geodesy.OsGridRef.latLonToOsGrid(latlon);
|
||||||
|
if (osng.toString() === "") {
|
||||||
|
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
|
||||||
|
if (precision % 2 !== 0) {
|
||||||
|
precision = precision + 1;
|
||||||
|
}
|
||||||
|
if (precision > 10) {
|
||||||
|
precision = 10;
|
||||||
|
}
|
||||||
|
convLat = osng.toString(precision);
|
||||||
|
break;
|
||||||
|
case "Universal Transverse Mercator":
|
||||||
|
utm = latlon.toUtm();
|
||||||
|
convLat = utm.toString(precision);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (convLat === undefined) {
|
||||||
|
throw new OperationError("Error converting co-ordinates.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outFormat.includes("Degrees")) {
|
||||||
|
// Format DD/DDM/DMS for output
|
||||||
|
// If we're outputting a compass direction, remove the negative sign
|
||||||
|
if (latDir === "S" && includeDir !== "None") {
|
||||||
|
convLat = convLat.replace("-", "");
|
||||||
|
}
|
||||||
|
if (longDir === "W" && includeDir !== "None") {
|
||||||
|
convLon = convLon.replace("-", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
let outConv = "";
|
||||||
|
if (includeDir === "Before") {
|
||||||
|
outConv += latDir + " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
outConv += convLat;
|
||||||
|
if (includeDir === "After") {
|
||||||
|
outConv += " " + latDir;
|
||||||
|
}
|
||||||
|
outConv += outDelim;
|
||||||
|
if (isPair) {
|
||||||
|
if (includeDir === "Before") {
|
||||||
|
outConv += longDir + " ";
|
||||||
|
}
|
||||||
|
outConv += convLon;
|
||||||
|
if (includeDir === "After") {
|
||||||
|
outConv += " " + longDir;
|
||||||
|
}
|
||||||
|
outConv += outDelim;
|
||||||
|
}
|
||||||
|
conv = outConv;
|
||||||
|
} else {
|
||||||
|
conv = convLat + outDelim;
|
||||||
|
}
|
||||||
|
|
||||||
|
return conv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Split up the input using a space or degrees signs, 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(/\s+/).forEach(item => {
|
||||||
|
// Remove any character that isn't a digit, decimal point or negative sign
|
||||||
|
item = item.replace(/[^0-9.-]/g, "");
|
||||||
|
if (item.length > 0){
|
||||||
|
// Turn the item into a float
|
||||||
|
split.push(parseFloat(item));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
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 absDegrees = Math.abs(degrees);
|
||||||
|
let conv = absDegrees + (minutes / 60) + (seconds / 3600);
|
||||||
|
let outString = round(conv, precision) + "°";
|
||||||
|
if (isNegativeZero(degrees) || degrees < 0) {
|
||||||
|
conv = -conv;
|
||||||
|
outString = "-" + outString;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
"degrees": conv,
|
||||||
|
"string": outString
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 absDegrees = Math.abs(degrees);
|
||||||
|
let conv = absDegrees + minutes / 60;
|
||||||
|
let outString = round(conv, precision) + "°";
|
||||||
|
if (isNegativeZero(degrees) || degrees < 0) {
|
||||||
|
conv = -conv;
|
||||||
|
outString = "-" + outString;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
"degrees": conv,
|
||||||
|
"string": outString
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) {
|
||||||
|
return {
|
||||||
|
"degrees": degrees,
|
||||||
|
"string": round(degrees, precision) + "°"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert Decimal Degrees to Degrees Minutes Seconds
|
||||||
|
*
|
||||||
|
* @param {number} decDegrees - The input data to be converted
|
||||||
|
* @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)
|
||||||
|
*/
|
||||||
|
function convDDToDMS (decDegrees, precision) {
|
||||||
|
const absDegrees = Math.abs(decDegrees);
|
||||||
|
let degrees = Math.floor(absDegrees);
|
||||||
|
const minutes = Math.floor(60 * (absDegrees - degrees)),
|
||||||
|
seconds = round(3600 * (absDegrees - degrees) - 60 * minutes, precision);
|
||||||
|
let outString = degrees + "° " + minutes + "' " + seconds + "\"";
|
||||||
|
if (isNegativeZero(decDegrees) || decDegrees < 0) {
|
||||||
|
degrees = -degrees;
|
||||||
|
outString = "-" + outString;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
"degrees": degrees,
|
||||||
|
"minutes": minutes,
|
||||||
|
"seconds": seconds,
|
||||||
|
"string": outString
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 absDegrees = Math.abs(decDegrees);
|
||||||
|
let degrees = Math.floor(absDegrees);
|
||||||
|
const minutes = absDegrees - degrees,
|
||||||
|
decMinutes = round(minutes * 60, precision);
|
||||||
|
let outString = degrees + "° " + decMinutes + "'";
|
||||||
|
if (decDegrees < 0 || isNegativeZero(decDegrees)) {
|
||||||
|
degrees = -degrees;
|
||||||
|
outString = "-" + outString;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
"degrees": degrees,
|
||||||
|
"minutes": decMinutes,
|
||||||
|
"string": outString,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds and returns the compass directions in an input string
|
||||||
|
*
|
||||||
|
* @param {string} input - The input co-ordinates containing the direction
|
||||||
|
* @param {string} delim - The delimiter separating latitide and longitude
|
||||||
|
* @returns {string[]} String array containing the latitude and longitude directions
|
||||||
|
*/
|
||||||
|
export function findDirs(input, delim) {
|
||||||
|
const upperInput = input.toUpperCase();
|
||||||
|
const dirExp = new RegExp(/[NESW]/g);
|
||||||
|
|
||||||
|
const dirs = upperInput.match(dirExp);
|
||||||
|
|
||||||
|
if (dirs) {
|
||||||
|
// If there's actually compass directions
|
||||||
|
// in the input, use these to work out the direction
|
||||||
|
if (dirs.length <= 2 && dirs.length >= 1) {
|
||||||
|
return dirs.length === 2 ? [dirs[0], dirs[1]] : [dirs[0], ""];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nothing was returned, so guess the directions
|
||||||
|
let lat = upperInput,
|
||||||
|
long,
|
||||||
|
latDir = "",
|
||||||
|
longDir = "";
|
||||||
|
if (!delim.includes("Direction")) {
|
||||||
|
if (upperInput.includes(delim)) {
|
||||||
|
const split = upperInput.split(delim);
|
||||||
|
if (split.length >= 1) {
|
||||||
|
if (split[0] !== "") {
|
||||||
|
lat = split[0];
|
||||||
|
}
|
||||||
|
if (split.length >= 2 && split[1] !== "") {
|
||||||
|
long = split[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const split = upperInput.split(dirExp);
|
||||||
|
if (split.length > 1) {
|
||||||
|
lat = split[0] === "" ? split[1] : split[0];
|
||||||
|
if (split.length > 2 && split[2] !== "") {
|
||||||
|
long = split[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lat) {
|
||||||
|
lat = parseFloat(lat);
|
||||||
|
latDir = lat < 0 ? "S" : "N";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (long) {
|
||||||
|
long = parseFloat(long);
|
||||||
|
longDir = long < 0 ? "W" : "E";
|
||||||
|
}
|
||||||
|
|
||||||
|
return [latDir, longDir];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detects the co-ordinate format of the input data
|
||||||
|
*
|
||||||
|
* @param {string} input - The input data whose format we need to detect
|
||||||
|
* @param {string} delim - The delimiter separating the data in input
|
||||||
|
* @returns {string} The input format
|
||||||
|
*/
|
||||||
|
export function findFormat (input, delim) {
|
||||||
|
let testData;
|
||||||
|
const mgrsPattern = new RegExp(/^[0-9]{2}\s?[C-HJ-NP-X]{1}\s?[A-HJ-NP-Z][A-HJ-NP-V]\s?[0-9\s]+/),
|
||||||
|
osngPattern = new RegExp(/^[A-HJ-Z]{2}\s+[0-9\s]+$/),
|
||||||
|
geohashPattern = new RegExp(/^[0123456789BCDEFGHJKMNPQRSTUVWXYZ]+$/),
|
||||||
|
utmPattern = new RegExp(/^[0-9]{2}\s?[C-HJ-NP-X]\s[0-9.]+\s?[0-9.]+$/),
|
||||||
|
degPattern = new RegExp(/[°'"]/g);
|
||||||
|
|
||||||
|
input = input.trim();
|
||||||
|
|
||||||
|
if (delim !== null && delim.includes("Direction")) {
|
||||||
|
const split = input.split(/[NnEeSsWw]/);
|
||||||
|
if (split.length > 1) {
|
||||||
|
testData = split[0] === "" ? split[1] : split[0];
|
||||||
|
}
|
||||||
|
} else if (delim !== null && delim !== "") {
|
||||||
|
if (input.includes(delim)) {
|
||||||
|
const split = input.split(delim);
|
||||||
|
if (split.length > 1) {
|
||||||
|
testData = split[0] === "" ? split[1] : split[0];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
testData = input;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test non-degrees formats
|
||||||
|
if (!degPattern.test(input)) {
|
||||||
|
const filteredInput = input.toUpperCase().replace(delim, "");
|
||||||
|
|
||||||
|
if (utmPattern.test(filteredInput)) {
|
||||||
|
return "Universal Transverse Mercator";
|
||||||
|
}
|
||||||
|
if (mgrsPattern.test(filteredInput)) {
|
||||||
|
return "Military Grid Reference System";
|
||||||
|
}
|
||||||
|
if (osngPattern.test(filteredInput)) {
|
||||||
|
return "Ordnance Survey National Grid";
|
||||||
|
}
|
||||||
|
if (geohashPattern.test(filteredInput)) {
|
||||||
|
return "Geohash";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test DMS/DDM/DD formats
|
||||||
|
if (testData !== undefined) {
|
||||||
|
const split = splitInput(testData);
|
||||||
|
switch (split.length){
|
||||||
|
case 3:
|
||||||
|
return "Degrees Minutes Seconds";
|
||||||
|
case 2:
|
||||||
|
return "Degrees Decimal Minutes";
|
||||||
|
case 1:
|
||||||
|
return "Decimal Degrees";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Automatically find the delimeter type from the given input
|
||||||
|
*
|
||||||
|
* @param {string} input
|
||||||
|
* @returns {string} Delimiter type
|
||||||
|
*/
|
||||||
|
export function findDelim (input) {
|
||||||
|
input = input.trim();
|
||||||
|
const delims = [",", ";", ":"];
|
||||||
|
const testDir = input.match(/[NnEeSsWw]/g);
|
||||||
|
if (testDir !== null && testDir.length > 0 && testDir.length < 3) {
|
||||||
|
// Possibly contains a direction
|
||||||
|
const splitInput = input.split(/[NnEeSsWw]/);
|
||||||
|
if (splitInput.length <= 3 && splitInput.length > 0) {
|
||||||
|
// If there's 3 splits (one should be empty), then assume we have directions
|
||||||
|
if (splitInput[0] === "") {
|
||||||
|
return "Direction Preceding";
|
||||||
|
} else if (splitInput[splitInput.length - 1] === "") {
|
||||||
|
return "Direction Following";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop through the standard delimiters, and try to find them in the input
|
||||||
|
for (let i = 0; i < delims.length; i++) {
|
||||||
|
const delim = delims[i];
|
||||||
|
if (input.includes(delim)) {
|
||||||
|
const splitInput = input.split(delim);
|
||||||
|
if (splitInput.length <= 3 && splitInput.length > 0) {
|
||||||
|
// Don't want to try and convert more than 2 co-ordinates
|
||||||
|
return delim;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the real string for a delimiter name.
|
||||||
|
*
|
||||||
|
* @param {string} delim The delimiter to be matched
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
export function realDelim (delim) {
|
||||||
|
return {
|
||||||
|
"Auto": "Auto",
|
||||||
|
"Space": " ",
|
||||||
|
"\\n": "\n",
|
||||||
|
"Comma": ",",
|
||||||
|
"Semi-colon": ";",
|
||||||
|
"Colon": ":"
|
||||||
|
}[delim];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if a zero is negative
|
||||||
|
*
|
||||||
|
* @param {number} zero
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
function isNegativeZero(zero) {
|
||||||
|
return zero === 0 && (1/zero < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rounds a number to a specified number of decimal places
|
||||||
|
*
|
||||||
|
* @param {number} input - The number to be rounded
|
||||||
|
* @param {precision} precision - The number of decimal places the number should be rounded to
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
function round(input, precision) {
|
||||||
|
precision = Math.pow(10, precision);
|
||||||
|
return Math.round(input * precision) / precision;
|
||||||
|
}
|
95
src/core/operations/ConvertCoordinateFormat.mjs
Normal file
95
src/core/operations/ConvertCoordinateFormat.mjs
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
/**
|
||||||
|
* @author j433866 [j433866@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2019
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation";
|
||||||
|
import {FORMATS, convertCoordinates} from "../lib/ConvertCoordinates";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert co-ordinate format operation
|
||||||
|
*/
|
||||||
|
class ConvertCoordinateFormat extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ConvertCoordinateFormat constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "Convert co-ordinate format";
|
||||||
|
this.module = "Hashing";
|
||||||
|
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.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
"name": "Input Format",
|
||||||
|
"type": "option",
|
||||||
|
"value": ["Auto"].concat(FORMATS)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Input Delimiter",
|
||||||
|
"type": "option",
|
||||||
|
"value": [
|
||||||
|
"Auto",
|
||||||
|
"Direction Preceding",
|
||||||
|
"Direction Following",
|
||||||
|
"\\n",
|
||||||
|
"Comma",
|
||||||
|
"Semi-colon",
|
||||||
|
"Colon"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Output Format",
|
||||||
|
"type": "option",
|
||||||
|
"value": FORMATS
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Output Delimiter",
|
||||||
|
"type": "option",
|
||||||
|
"value": [
|
||||||
|
"Space",
|
||||||
|
"\\n",
|
||||||
|
"Comma",
|
||||||
|
"Semi-colon",
|
||||||
|
"Colon"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Include Compass Directions",
|
||||||
|
"type": "option",
|
||||||
|
"value": [
|
||||||
|
"None",
|
||||||
|
"Before",
|
||||||
|
"After"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Precision",
|
||||||
|
"type": "number",
|
||||||
|
"value": 3
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
if (input.replace(/[\s+]/g, "") !== "") {
|
||||||
|
const [inFormat, inDelim, outFormat, outDelim, incDirection, precision] = args;
|
||||||
|
const result = convertCoordinates(input, inFormat, inDelim, outFormat, outDelim, incDirection, precision);
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ConvertCoordinateFormat;
|
@ -1,44 +0,0 @@
|
|||||||
/**
|
|
||||||
* @author gchq77703 []
|
|
||||||
* @copyright Crown Copyright 2018
|
|
||||||
* @license Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Operation from "../Operation";
|
|
||||||
import geohash from "ngeohash";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* From Geohash operation
|
|
||||||
*/
|
|
||||||
class FromGeohash extends Operation {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* FromGeohash constructor
|
|
||||||
*/
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this.name = "From Geohash";
|
|
||||||
this.module = "Crypto";
|
|
||||||
this.description = "Converts Geohash strings into Lat/Long coordinates. For example, <code>ww8p1r4t8</code> becomes <code>37.8324,112.5584</code>.";
|
|
||||||
this.infoURL = "https://wikipedia.org/wiki/Geohash";
|
|
||||||
this.inputType = "string";
|
|
||||||
this.outputType = "string";
|
|
||||||
this.args = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} input
|
|
||||||
* @param {Object[]} args
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
run(input, args) {
|
|
||||||
return input.split("\n").map(line => {
|
|
||||||
const coords = geohash.decode(line);
|
|
||||||
return [coords.latitude, coords.longitude].join(",");
|
|
||||||
}).join("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export default FromGeohash;
|
|
@ -1,53 +0,0 @@
|
|||||||
/**
|
|
||||||
* @author gchq77703 []
|
|
||||||
* @copyright Crown Copyright 2018
|
|
||||||
* @license Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Operation from "../Operation";
|
|
||||||
import geohash from "ngeohash";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* To Geohash operation
|
|
||||||
*/
|
|
||||||
class ToGeohash extends Operation {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ToGeohash constructor
|
|
||||||
*/
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this.name = "To Geohash";
|
|
||||||
this.module = "Crypto";
|
|
||||||
this.description = "Converts Lat/Long coordinates into a Geohash string. For example, <code>37.8324,112.5584</code> becomes <code>ww8p1r4t8</code>.";
|
|
||||||
this.infoURL = "https://wikipedia.org/wiki/Geohash";
|
|
||||||
this.inputType = "string";
|
|
||||||
this.outputType = "string";
|
|
||||||
this.args = [
|
|
||||||
{
|
|
||||||
name: "Precision",
|
|
||||||
type: "number",
|
|
||||||
value: 9
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} input
|
|
||||||
* @param {Object[]} args
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
run(input, args) {
|
|
||||||
const [precision] = args;
|
|
||||||
|
|
||||||
return input.split("\n").map(line => {
|
|
||||||
line = line.replace(/ /g, "");
|
|
||||||
if (line === "") return "";
|
|
||||||
return geohash.encode(...line.split(",").map(num => parseFloat(num)), precision);
|
|
||||||
}).join("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ToGeohash;
|
|
@ -45,7 +45,6 @@ import "./tests/DateTime";
|
|||||||
import "./tests/ExtractEmailAddresses";
|
import "./tests/ExtractEmailAddresses";
|
||||||
import "./tests/Fork";
|
import "./tests/Fork";
|
||||||
import "./tests/FromDecimal";
|
import "./tests/FromDecimal";
|
||||||
import "./tests/FromGeohash";
|
|
||||||
import "./tests/Hash";
|
import "./tests/Hash";
|
||||||
import "./tests/HaversineDistance";
|
import "./tests/HaversineDistance";
|
||||||
import "./tests/Hexdump";
|
import "./tests/Hexdump";
|
||||||
@ -77,13 +76,13 @@ import "./tests/SetUnion";
|
|||||||
import "./tests/StrUtils";
|
import "./tests/StrUtils";
|
||||||
import "./tests/SymmetricDifference";
|
import "./tests/SymmetricDifference";
|
||||||
import "./tests/TextEncodingBruteForce";
|
import "./tests/TextEncodingBruteForce";
|
||||||
import "./tests/ToGeohash";
|
|
||||||
import "./tests/TranslateDateTimeFormat";
|
import "./tests/TranslateDateTimeFormat";
|
||||||
import "./tests/Magic";
|
import "./tests/Magic";
|
||||||
import "./tests/ParseTLV";
|
import "./tests/ParseTLV";
|
||||||
import "./tests/Media";
|
import "./tests/Media";
|
||||||
import "./tests/ToFromInsensitiveRegex";
|
import "./tests/ToFromInsensitiveRegex";
|
||||||
import "./tests/YARA.mjs";
|
import "./tests/YARA.mjs";
|
||||||
|
import "./tests/ConvertCoordinateFormat";
|
||||||
|
|
||||||
// Cannot test operations that use the File type yet
|
// Cannot test operations that use the File type yet
|
||||||
//import "./tests/SplitColourChannels";
|
//import "./tests/SplitColourChannels";
|
||||||
|
211
tests/operations/tests/ConvertCoordinateFormat.mjs
Normal file
211
tests/operations/tests/ConvertCoordinateFormat.mjs
Normal file
@ -0,0 +1,211 @@
|
|||||||
|
/**
|
||||||
|
* Convert co-ordinate format tests
|
||||||
|
*
|
||||||
|
* @author j433866
|
||||||
|
*
|
||||||
|
* @copyright Crown Copyright 2019
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TEST CO-ORDINATES
|
||||||
|
* DD: 51.504°,-0.126°,
|
||||||
|
* DDM: 51° 30.24',-0° 7.56',
|
||||||
|
* DMS: 51° 30' 14.4",-0° 7' 33.6",
|
||||||
|
* Geohash: gcpvj0h0x,
|
||||||
|
* MGRS: 30U XC 99455 09790,
|
||||||
|
* OSNG: TQ 30163 80005,
|
||||||
|
* UTM: 30N 699456 5709791,
|
||||||
|
*/
|
||||||
|
|
||||||
|
import TestRegister from "../TestRegister";
|
||||||
|
|
||||||
|
TestRegister.addTests([
|
||||||
|
{
|
||||||
|
name: "Co-ordinates: From Decimal Degrees to Degrees Minutes Seconds",
|
||||||
|
input: "51.504°,-0.126°,",
|
||||||
|
expectedOutput: "51° 30' 14.4\",-0° 7' 33.6\",",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Convert co-ordinate format",
|
||||||
|
args: ["Decimal Degrees", "Comma", "Degrees Minutes Seconds", "Comma", "None", 1]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Co-ordinates: From Degrees Minutes Seconds to Decimal Degrees",
|
||||||
|
input: "51° 30' 14.4\",-0° 7' 33.6\",",
|
||||||
|
expectedOutput: "51.504°,-0.126°,",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Convert co-ordinate format",
|
||||||
|
args: ["Degrees Minutes Seconds", "Comma", "Decimal Degrees", "Comma", "None", 3]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Co-ordinates: From Decimal Degrees to Degrees Decimal Minutes",
|
||||||
|
input: "51.504°,-0.126°,",
|
||||||
|
expectedOutput: "51° 30.24',-0° 7.56',",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Convert co-ordinate format",
|
||||||
|
args: ["Decimal Degrees", "Comma", "Degrees Decimal Minutes", "Comma", "None", 2]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Co-ordinates: From Degrees Decimal Minutes to Decimal Degrees",
|
||||||
|
input: "51° 30.24',-0° 7.56',",
|
||||||
|
expectedOutput: "51.504°,-0.126°,",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Convert co-ordinate format",
|
||||||
|
args: ["Degrees Decimal Minutes", "Comma", "Decimal Degrees", "Comma", "None", 3]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Co-ordinates: From Decimal Degrees to Decimal Degrees",
|
||||||
|
input: "51.504°,-0.126°,",
|
||||||
|
expectedOutput: "51.504°,-0.126°,",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Convert co-ordinate format",
|
||||||
|
args: ["Decimal Degrees", "Comma", "Decimal Degrees", "Comma", "None", 3]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Co-ordinates: From Decimal Degrees to Geohash",
|
||||||
|
input: "51.504°,-0.126°,",
|
||||||
|
expectedOutput: "gcpvj0h0x,",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Convert co-ordinate format",
|
||||||
|
args: ["Decimal Degrees", "Comma", "Geohash", "Comma", "None", 9]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Co-ordinates: From Geohash to Decimal Degrees",
|
||||||
|
input: "gcpvj0h0x,",
|
||||||
|
expectedOutput: "51.504°,-0.126°,",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Convert co-ordinate format",
|
||||||
|
args: ["Geohash", "Comma", "Decimal Degrees", "Comma", "None", 3]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Co-ordinates: From Decimal Degrees to MGRS",
|
||||||
|
input: "51.504°,-0.126°,",
|
||||||
|
expectedOutput: "30U XC 99455 09790,",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Convert co-ordinate format",
|
||||||
|
args: ["Decimal Degrees", "Comma", "Military Grid Reference System", "Comma", "None", 10]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Co-ordinates: From MGRS to Decimal Degrees",
|
||||||
|
input: "30U XC 99455 09790,",
|
||||||
|
expectedOutput: "51.504°,-0.126°,",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Convert co-ordinate format",
|
||||||
|
args: ["Military Grid Reference System", "Comma", "Decimal Degrees", "Comma", "None", 3]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Co-ordinates: From Decimal Degrees to OSNG",
|
||||||
|
input: "51.504°,-0.126°,",
|
||||||
|
expectedOutput: "TQ 30163 80005,",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Convert co-ordinate format",
|
||||||
|
args: ["Decimal Degrees", "Comma", "Ordnance Survey National Grid", "Comma", "None", 10]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Co-ordinates: From OSNG to Decimal Degrees",
|
||||||
|
input: "TQ 30163 80005,",
|
||||||
|
expectedOutput: "51.504°,-0.126°,",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Convert co-ordinate format",
|
||||||
|
args: ["Ordnance Survey National Grid", "Comma", "Decimal Degrees", "Comma", "None", 3]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Co-ordinates: From Decimal Degrees to UTM",
|
||||||
|
input: "51.504°,-0.126°,",
|
||||||
|
expectedOutput: "30 N 699456 5709791,",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Convert co-ordinate format",
|
||||||
|
args: ["Decimal Degrees", "Comma", "Universal Transverse Mercator", "Comma", "None", 0]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Co-ordinates: From UTM to Decimal Degrees",
|
||||||
|
input: "30 N 699456 5709791,",
|
||||||
|
expectedOutput: "51.504°,-0.126°,",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Convert co-ordinate format",
|
||||||
|
args: ["Universal Transverse Mercator", "Comma", "Decimal Degrees", "Comma", "None", 3]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Co-ordinates: Directions in input, not output",
|
||||||
|
input: "N51.504°,W0.126°,",
|
||||||
|
expectedOutput: "51.504°,-0.126°,",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Convert co-ordinate format",
|
||||||
|
args: ["Decimal Degrees", "Comma", "Decimal Degrees", "Comma", "None", 3]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Co-ordinates: Directions in input and output",
|
||||||
|
input: "N51.504°,W0.126°,",
|
||||||
|
expectedOutput: "N 51.504°,W 0.126°,",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Convert co-ordinate format",
|
||||||
|
args: ["Decimal Degrees", "Comma", "Decimal Degrees", "Comma", "Before", 3]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Co-ordinates: Directions not in input, in output",
|
||||||
|
input: "51.504°,-0.126°,",
|
||||||
|
expectedOutput: "N 51.504°,W 0.126°,",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Convert co-ordinate format",
|
||||||
|
args: ["Decimal Degrees", "Comma", "Decimal Degrees", "Comma", "Before", 3]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Co-ordinates: Directions not in input, in converted output",
|
||||||
|
input: "51.504°,-0.126°,",
|
||||||
|
expectedOutput: "N 51° 30' 14.4\",W 0° 7' 33.6\",",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Convert co-ordinate format",
|
||||||
|
args: ["Decimal Degrees", "Comma", "Degrees Minutes Seconds", "Comma", "Before", 3]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
]);
|
@ -1,55 +0,0 @@
|
|||||||
/**
|
|
||||||
* To Geohash tests
|
|
||||||
*
|
|
||||||
* @author gchq77703
|
|
||||||
* @copyright Crown Copyright 2018
|
|
||||||
* @license Apache-2.0
|
|
||||||
*/
|
|
||||||
import TestRegister from "../TestRegister";
|
|
||||||
|
|
||||||
TestRegister.addTests([
|
|
||||||
{
|
|
||||||
name: "From Geohash",
|
|
||||||
input: "ww8p1r4t8",
|
|
||||||
expectedOutput: "37.83238649368286,112.55838632583618",
|
|
||||||
recipeConfig: [
|
|
||||||
{
|
|
||||||
op: "From Geohash",
|
|
||||||
args: [],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "From Geohash",
|
|
||||||
input: "ww8p1r",
|
|
||||||
expectedOutput: "37.83416748046875,112.5604248046875",
|
|
||||||
recipeConfig: [
|
|
||||||
{
|
|
||||||
op: "From Geohash",
|
|
||||||
args: [],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "From Geohash",
|
|
||||||
input: "ww8",
|
|
||||||
expectedOutput: "37.265625,113.203125",
|
|
||||||
recipeConfig: [
|
|
||||||
{
|
|
||||||
op: "From Geohash",
|
|
||||||
args: [],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "From Geohash",
|
|
||||||
input: "w",
|
|
||||||
expectedOutput: "22.5,112.5",
|
|
||||||
recipeConfig: [
|
|
||||||
{
|
|
||||||
op: "From Geohash",
|
|
||||||
args: [],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
]);
|
|
@ -1,55 +0,0 @@
|
|||||||
/**
|
|
||||||
* To Geohash tests
|
|
||||||
*
|
|
||||||
* @author gchq77703
|
|
||||||
* @copyright Crown Copyright 2018
|
|
||||||
* @license Apache-2.0
|
|
||||||
*/
|
|
||||||
import TestRegister from "../TestRegister";
|
|
||||||
|
|
||||||
TestRegister.addTests([
|
|
||||||
{
|
|
||||||
name: "To Geohash",
|
|
||||||
input: "37.8324,112.5584",
|
|
||||||
expectedOutput: "ww8p1r4t8",
|
|
||||||
recipeConfig: [
|
|
||||||
{
|
|
||||||
op: "To Geohash",
|
|
||||||
args: [9],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "To Geohash",
|
|
||||||
input: "37.9324,-112.2584",
|
|
||||||
expectedOutput: "9w8pv3ruj",
|
|
||||||
recipeConfig: [
|
|
||||||
{
|
|
||||||
op: "To Geohash",
|
|
||||||
args: [9],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "To Geohash",
|
|
||||||
input: "37.8324,112.5584",
|
|
||||||
expectedOutput: "ww8",
|
|
||||||
recipeConfig: [
|
|
||||||
{
|
|
||||||
op: "To Geohash",
|
|
||||||
args: [3],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "To Geohash",
|
|
||||||
input: "37.9324,-112.2584",
|
|
||||||
expectedOutput: "9w8pv3rujxy5b99",
|
|
||||||
recipeConfig: [
|
|
||||||
{
|
|
||||||
op: "To Geohash",
|
|
||||||
args: [15],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
]);
|
|
Loading…
Reference in New Issue
Block a user