浏览代码

Rewrite MGRS to use new Geodesy module.
Added Ordnance Survey grid reference support

j433866 6 年之前
父节点
当前提交
ad4451a757
共有 3 个文件被更改,包括 51 次插入18 次删除
  1. 1 0
      package.json
  2. 37 6
      src/core/lib/ConvertCoordinates.mjs
  3. 13 12
      src/core/operations/ConvertCoordinateFormat.mjs

+ 1 - 0
package.json

@@ -91,6 +91,7 @@
     "esprima": "^4.0.1",
     "exif-parser": "^0.1.12",
     "file-saver": "^2.0.0-rc.4",
+    "geodesy": "^1.1.3",
     "highlight.js": "^9.13.1",
     "jquery": "^3.3.1",
     "js-crc": "^0.2.0",

+ 37 - 6
src/core/lib/ConvertCoordinates.mjs

@@ -7,7 +7,7 @@
  */
 
 import geohash from "ngeohash";
-import mgrs from "mgrs";
+import geodesy from "geodesy";
 
 /**
  * Co-ordinate formats
@@ -17,7 +17,19 @@ export const FORMATS = [
     "Degrees Decimal Minutes",
     "Decimal Degrees",
     "Geohash",
-    "Military Grid Reference System"
+    "Military Grid Reference System",
+    "Ordnance Survey National Grid"
+];
+
+/**
+ * Formats that are made up of one string
+ * These formats skip bits like filtering delimiters and
+ * are outputted differently (only one output)
+ */
+export const STRING_FORMATS = [
+    "Geohash",
+    "Military Grid Reference System",
+    "Ordnance Survey National Grid"
 ];
 
 /**
@@ -37,9 +49,22 @@ export function convertCoordinates (inLat, inLong, inFormat, outFormat, precisio
         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];
+        const utm = geodesy.Mgrs.parse(inLat).toUtm();
+        const result = utm.toLatLonE().toString("d", 4).replace(/[^0-9.,]/g, "");
+        const splitResult = result.split(",");
+        if (splitResult.length === 2) {
+            convLat = splitResult[0];
+            convLong = splitResult[1];
+        }
+    } else if (inFormat === "Ordnance Survey National Grid") {
+        const osng = geodesy.OsGridRef.parse(inLat);
+        const latlon = geodesy.OsGridRef.osGridToLatLon(osng, geodesy.LatLonEllipsoidal.datum.WGS84);
+        const result = latlon.toString("d", 4).replace(/[^0-9.,]/g, "");
+        const splitResult = result.split(",");
+        if (splitResult.length === 2) {
+            convLat = splitResult[0];
+            convLong = splitResult[1];
+        }
     } else {
         convLat = convertSingleCoordinate(inLat, inFormat, "Decimal Degrees", 15).split("°");
         convLong = convertSingleCoordinate(inLong, inFormat, "Decimal Degrees", 15).split("°");
@@ -49,7 +74,13 @@ export function convertCoordinates (inLat, inLong, inFormat, outFormat, precisio
     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);
+        const utm = new geodesy.LatLonEllipsoidal(parseFloat(convLat), parseFloat(convLong)).toUtm();
+        const mgrs = utm.toMgrs();
+        convLat = mgrs.toString();
+    } else if (outFormat === "Ordnance Survey National Grid") {
+        const latlon = new geodesy.LatLonEllipsoidal(parseFloat(convLat), parseFloat(convLong));
+        const osng = geodesy.OsGridRef.latLonToOsGrid(latlon);
+        convLat = osng.toString();
     } else {
         convLat = convertSingleCoordinate(convLat.toString(), "Decimal Degrees", outFormat, precision);
         convLong = convertSingleCoordinate(convLong.toString(), "Decimal Degrees", outFormat, precision);

+ 13 - 12
src/core/operations/ConvertCoordinateFormat.mjs

@@ -6,7 +6,7 @@
 
 import Operation from "../Operation";
 import OperationError from "../errors/OperationError";
-import {FORMATS, convertCoordinates, convertSingleCoordinate, findDelim, findFormat} from "../lib/ConvertCoordinates";
+import {FORMATS, STRING_FORMATS, convertCoordinates, convertSingleCoordinate, findDelim, findFormat} from "../lib/ConvertCoordinates";
 import Utils from "../Utils";
 
 /**
@@ -22,7 +22,7 @@ class ConvertCoordinateFormat extends Operation {
 
         this.name = "Convert co-ordinate format";
         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></ul>";
+        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></ul>";
         this.infoURL = "https://wikipedia.org/wiki/Geographic_coordinate_conversion";
         this.inputType = "string";
         this.outputType = "string";
@@ -107,14 +107,14 @@ class ConvertCoordinateFormat extends Operation {
             }
         }
 
-        if (inDelim === "" && (inFormat !== "Geohash" && inFormat !== "Military Grid Reference System")) {
+        if (inDelim === "" && (!STRING_FORMATS.includes(inFormat))) {
             throw new OperationError("Could not automatically detect the input delimiter.");
         }
 
         // Prepare input data
-        if (inFormat === "Geohash" || inFormat === "Military Grid Reference System") {
+        if (STRING_FORMATS.includes(inFormat)) {
             // Geohash only has one value, so just use the input
-            // Replace anything that isn't a valid character in Geohash / MGRS
+            // Replace anything that isn't a valid character in Geohash / MGRS / OSNG
             inLat = input.replace(/[^A-Za-z0-9]/, "");
         } else if (inDelim === "Direction Preceding") {
             // Split on the compass directions
@@ -152,7 +152,7 @@ class ConvertCoordinateFormat extends Operation {
             }
         }
 
-        if (inFormat !== "Geohash" && inFormat !== "Military Grid Reference System" && outDelim.includes("Direction")) {
+        if (!STRING_FORMATS.includes(inFormat) && outDelim.includes("Direction")) {
             // Match on compass directions, and store the first 2 matches for the output
             const dir = input.match(/[NnEeSsWw]/g);
             if (dir !== null) {
@@ -173,14 +173,15 @@ class ConvertCoordinateFormat extends Operation {
         // Convert the co-ordinates
         if (inLat !== undefined) {
             if (inLong === undefined) {
-                if (inFormat !== "Geohash" && inFormat !== "Military Grid Reference System") {
-                    if (outFormat === "Geohash" || outFormat === "Military Grid Reference System"){
+                if (!STRING_FORMATS.includes(inFormat)) {
+                    if (STRING_FORMATS.includes(outFormat)){
                         throw new OperationError(`${outFormat} needs both a latitude and a longitude to be calculated`);
                     }
                 }
-                if (inFormat === "Geohash" || inFormat === "Military Grid Reference System") {
+                if (STRING_FORMATS.includes(inFormat)) {
                     // Geohash conversion is in convertCoordinates despite needing
                     // only one input as it needs to output two values
+                    inLat = inLat.replace(/[^A-Za-z0-9]/g, "");
                     [outLat, outLong] = convertCoordinates(inLat, inLat, inFormat, outFormat, precision);
                 } else {
                     outLat = convertSingleCoordinate(inLat, inFormat, outFormat, precision);
@@ -195,16 +196,16 @@ class ConvertCoordinateFormat extends Operation {
         // Output conversion results if successful
         if (outLat !== undefined) {
             let output = "";
-            if (outDelim === "Direction Preceding" && outFormat !== "Geohash" && outFormat !== "Military Grid Reference System") {
+            if (outDelim === "Direction Preceding" && !STRING_FORMATS.includes(outFormat)) {
                 output += latDir += " ";
             }
             output += outLat;
-            if (outDelim === "Direction Following" && outFormat !== "Geohash" && outFormat !== "Military Grid Reference System") {
+            if (outDelim === "Direction Following" && !STRING_FORMATS.includes(outFormat)) {
                 output += " " + latDir;
             }
             output += outSeparator;
 
-            if (outLong !== undefined && outFormat !== "Geohash" && outFormat !== "Military Grid Reference System") {
+            if (outLong !== undefined && !STRING_FORMATS.includes(outFormat)) {
                 if (outDelim === "Direction Preceding") {
                     output += longDir + " ";
                 }