From 64e0474a691d0311e99d61028124e5f7a920aab8 Mon Sep 17 00:00:00 2001 From: DanielJDufour Date: Sun, 25 Sep 2022 18:16:57 -0400 Subject: [PATCH] rebuilt and added files property to package.json, to avoid accidental publishing of files --- dist/mgrs.esm.js | 2 + dist/mgrs.esm.js.map | 1 + dist/mgrs.js | 1376 +++++++++++++++++++++--------------------- dist/mgrs.min.js | 2 + dist/mgrs.min.js.map | 1 + package.json | 9 + 6 files changed, 703 insertions(+), 688 deletions(-) create mode 100644 dist/mgrs.esm.js create mode 100644 dist/mgrs.esm.js.map create mode 100644 dist/mgrs.min.js create mode 100644 dist/mgrs.min.js.map diff --git a/dist/mgrs.esm.js b/dist/mgrs.esm.js new file mode 100644 index 0000000..9bfd7d1 --- /dev/null +++ b/dist/mgrs.esm.js @@ -0,0 +1,2 @@ +const t=65,e=73,r=79;function n(n,o){if(o="number"==typeof o?o:5,!Array.isArray(n))throw new TypeError("forward did not receive an array");if("string"==typeof n[0]||"string"==typeof n[1])throw new TypeError("forward received an array of strings, but it only accepts an array of numbers.");const[a,s]=n;if(a<-180||a>180)throw new TypeError("forward received an invalid longitude of "+a);if(s<-90||s>90)throw new TypeError("forward received an invalid latitude of "+s);if(s<-80||s>84)throw new TypeError(`forward received a latitude of ${s}, but this library does not support conversions of points in polar regions below 80°S and above 84°N`);return function(n,o){const a="00000"+n.easting,i="00000"+n.northing;return n.zoneNumber+n.zoneLetter+function(n,o,a){const i=f(a),s=Math.floor(n/1e5),c=Math.floor(o/1e5)%20;return function(n,o,a){const i=a-1,s="AJSAJS".charCodeAt(i),c="AFAFAF".charCodeAt(i);let h=s+n-1,f=c+o,l=!1;h>90&&(h=h-90+t-1,l=!0);(h===e||se||(h>e||sr||(h>r||s90&&(h=h-90+t-1);f>86?(f=f-86+t-1,l=!0):l=!1;(f===e||ce||(f>e||cr||(f>r||c86&&(f=f-86+t-1);return String.fromCharCode(h)+String.fromCharCode(f)}(s,c,i)}(n.easting,n.northing,n.zoneNumber)+a.substr(a.length-5,o)+i.substr(i.length-5,o)}(function(t){const e=t.lat,r=t.lon,n=6378137,o=i(e),a=i(r);let s;s=Math.floor((r+180)/6)+1,180===r&&(s=60);e>=56&&e<64&&r>=3&&r<12&&(s=32);e>=72&&e<84&&(r>=0&&r<9?s=31:r>=9&&r<21?s=33:r>=21&&r<33?s=35:r>=33&&r<42&&(s=37));const c=i(6*(s-1)-180+3),f=n/Math.sqrt(1-.00669438*Math.sin(o)*Math.sin(o)),l=Math.tan(o)*Math.tan(o),u=.006739496752268451*Math.cos(o)*Math.cos(o),b=Math.cos(o)*(a-c),M=n*(.9983242984503243*o-.002514607064228144*Math.sin(2*o)+2639046602129982e-21*Math.sin(4*o)-3.418046101696858e-9*Math.sin(6*o)),d=.9996*f*(b+(1-l+u)*b*b*b/6+(5-18*l+l*l+72*u-.39089081163157013)*b*b*b*b*b/120)+5e5;let g=.9996*(M+f*Math.tan(o)*(b*b/2+(5-l+9*u+4*u*u)*b*b*b*b/24+(61-58*l+l*l+600*u-2.2240339282485886)*b*b*b*b*b*b/720));e<0&&(g+=1e7);return{northing:Math.trunc(g),easting:Math.trunc(d),zoneNumber:s,zoneLetter:h(e)}}({lat:s,lon:a}),o)}function o(t){const e=c(l(t.toUpperCase()));return e.lat&&e.lon?[e.lon,e.lat,e.lon,e.lat]:[e.left,e.bottom,e.right,e.top]}function a(t){if(""===t)throw new TypeError("toPoint received a blank string");const e=c(l(t.toUpperCase()));return e.lat&&e.lon?[e.lon,e.lat]:[(e.left+e.right)/2,(e.top+e.bottom)/2]}function i(t){return t*(Math.PI/180)}function s(t){return t/Math.PI*180}function c(t){const e=t.northing,r=t.easting,{zoneLetter:n,zoneNumber:o}=t;if(o<0||o>60)return null;const a=6378137,i=(1-Math.sqrt(.99330562))/(1+Math.sqrt(.99330562)),h=r-5e5;let f=e;n<"N"&&(f-=1e7);const l=6*(o-1)-180+3,u=f/.9996/6367449.145945056,b=u+(3*i/2-27*i*i*i/32)*Math.sin(2*u)+(21*i*i/16-55*i*i*i*i/32)*Math.sin(4*u)+151*i*i*i/96*Math.sin(6*u),M=a/Math.sqrt(1-.00669438*Math.sin(b)*Math.sin(b)),d=Math.tan(b)*Math.tan(b),g=.006739496752268451*Math.cos(b)*Math.cos(b),w=.99330562*a/Math.pow(1-.00669438*Math.sin(b)*Math.sin(b),1.5),p=h/(.9996*M);let y=b-M*Math.tan(b)/w*(p*p/2-(5+3*d+10*g-4*g*g-.06065547077041606)*p*p*p*p/24+(61+90*d+298*g+45*d*d-1.6983531815716497-3*g*g)*p*p*p*p*p*p/720);y=s(y);let A,k=(p-(1+2*d+g)*p*p*p/6+(5-2*g+28*d-3*g*g+.05391597401814761+24*d*d)*p*p*p*p*p/120)/Math.cos(b);if(k=l+s(k),"number"==typeof t.accuracy){const e=c({northing:t.northing+t.accuracy,easting:t.easting+t.accuracy,zoneLetter:t.zoneLetter,zoneNumber:t.zoneNumber});A={top:e.lat,right:e.lon,bottom:y,left:k}}else A={lat:y,lon:k};return A}function h(t){if(t<=84&&t>=72)return"X";if(t<72&&t>=-80){const e=8,r=-80;return"CDEFGHJKLMNPQRSTUVWX"[Math.floor((t-r)/e)]}return t>84||t<-80?"Z":void 0}function f(t){let e=t%6;return 0===e&&(e=6),e}function l(n){if(n&&0===n.length)throw new TypeError("MGRSPoint coverting from nothing");n=n.replace(/ /g,"");const{length:o}=n;let a,i=null,s="",c=0;for(;!/[A-Z]/.test(a=n.charAt(c));){if(c>=2)throw new Error("MGRSPoint bad conversion from: "+n);s+=a,c++}const h=parseInt(s,10);if(0===c||c+3>o)throw new Error("MGRSPoint bad conversion from "+n);const l=n.charAt(c++);if(l<="A"||"B"===l||"Y"===l||l>="Z"||"I"===l||"O"===l)throw new Error(`MGRSPoint zone letter ${l} not handled: ${n}`);i=n.substring(c,c+=2);const b=f(h),M=function(n,o){let a="AJSAJS".charCodeAt(o-1),i=1e5,s=!1;for(;a!==n.charCodeAt(0);){if(a++,a===e&&a++,a===r&&a++,a>90){if(s)throw new Error("Bad character: "+n);a=t,s=!0}i+=1e5}return i}(i.charAt(0),b);let d=function(n,o){if(n>"V")throw new TypeError("MGRSPoint given invalid Northing "+n);let a="AFAFAF".charCodeAt(o-1),i=0,s=!1;for(;a!==n.charCodeAt(0);){if(a++,a===e&&a++,a===r&&a++,a>86){if(s)throw new Error("Bad character: "+n);a=t,s=!0}i+=1e5}return i}(i.charAt(1),b);for(;d0&&(p=1e5/Math.pow(10,w),y=n.substring(c,c+w),k=parseFloat(y)*p,A=n.substring(c+w),m=parseFloat(A)*p);return{easting:k+M,northing:m+d,zoneLetter:l,zoneNumber:h,accuracy:p}}function u(t){let e;switch(t){case"C":e=11e5;break;case"D":e=2e6;break;case"E":e=28e5;break;case"F":e=37e5;break;case"G":e=46e5;break;case"H":e=55e5;break;case"J":e=64e5;break;case"K":e=73e5;break;case"L":e=82e5;break;case"M":e=91e5;break;case"N":e=0;break;case"P":e=8e5;break;case"Q":e=17e5;break;case"R":e=26e5;break;case"S":e=35e5;break;case"T":e=44e5;break;case"U":e=53e5;break;case"V":e=62e5;break;case"W":e=7e6;break;case"X":e=79e5;break;default:e=-1}if(e>=0)return e;throw new TypeError("Invalid zone letter: "+t)}export{n as forward,h as getLetterDesignator,o as inverse,a as toPoint}; +//# sourceMappingURL=mgrs.esm.js.map diff --git a/dist/mgrs.esm.js.map b/dist/mgrs.esm.js.map new file mode 100644 index 0000000..1aa9ac4 --- /dev/null +++ b/dist/mgrs.esm.js.map @@ -0,0 +1 @@ +{"version":3,"file":"mgrs.esm.js","sources":["../mgrs.js"],"sourcesContent":["/**\n * UTM zones are grouped, and assigned to one of a group of 6\n * sets.\n *\n * {int} @private\n */\nconst NUM_100K_SETS = 6;\n\n/**\n * The column letters (for easting) of the lower left value, per\n * set.\n *\n * {string} @private\n */\nconst SET_ORIGIN_COLUMN_LETTERS = 'AJSAJS';\n\n/**\n * The row letters (for northing) of the lower left value, per\n * set.\n *\n * {string} @private\n */\nconst SET_ORIGIN_ROW_LETTERS = 'AFAFAF';\n\nconst A = 65; // A\nconst I = 73; // I\nconst O = 79; // O\nconst V = 86; // V\nconst Z = 90; // Z\n\n/**\n * First eccentricity squared\n * {number} @private\n */\nconst ECC_SQUARED = 0.00669438;\n\n/**\n * Scale factor along the central meridian\n * {number} @private\n */\nconst SCALE_FACTOR = 0.9996;\n\n/**\n * Semimajor axis (half the width of the earth) in meters\n * {number} @private\n */\nconst SEMI_MAJOR_AXIS = 6378137;\n\n/**\n * The easting of the central meridian of each UTM zone\n * {number} @private\n */\nconst EASTING_OFFSET = 500000;\n\n/**\n * The northing of the equator for southern hemisphere locations (in UTM)\n * {number} @private\n */\nconst NORTHING_OFFFSET = 10000000;\n\n/**\n * UTM zone width in degrees\n * {number} private\n */\nconst UTM_ZONE_WIDTH = 6;\n\n/**\n * Half the width of a UTM zone in degrees\n * {number} private\n */\nconst HALF_UTM_ZONE_WIDTH = UTM_ZONE_WIDTH / 2;\n\n/**\n * Convert lat/lon to MGRS.\n *\n * @param {[number, number]} ll Array with longitude and latitude on a\n * WGS84 ellipsoid.\n * @param {number} [accuracy=5] Accuracy in digits (5 for 1 m, 4 for 10 m, 3 for\n * 100 m, 2 for 1 km, 1 for 10 km or 0 for 100 km). Optional, default is 5.\n * @return {string} the MGRS string for the given location and accuracy.\n */\nexport function forward(ll, accuracy) {\n accuracy = typeof accuracy === 'number' ? accuracy : 5; // default accuracy 1m\n\n if (!Array.isArray(ll)) {\n throw new TypeError('forward did not receive an array');\n }\n\n if (typeof ll[0] === 'string' || typeof ll[1] === 'string') {\n throw new TypeError('forward received an array of strings, but it only accepts an array of numbers.');\n }\n\n const [ lon, lat ] = ll;\n if (lon < -180 || lon > 180) {\n throw new TypeError(`forward received an invalid longitude of ${lon}`);\n }\n if (lat < -90 || lat > 90) {\n throw new TypeError(`forward received an invalid latitude of ${lat}`);\n }\n\n if (lat < -80 || lat > 84) {\n throw new TypeError(`forward received a latitude of ${lat}, but this library does not support conversions of points in polar regions below 80°S and above 84°N`);\n }\n\n return encode(LLtoUTM({ lat, lon }), accuracy);\n}\n\n/**\n * Convert MGRS to lat/lon bounding box.\n *\n * @param {string} mgrs MGRS string.\n * @return {[number,number,number,number]} An array with left (longitude),\n * bottom (latitude), right\n * (longitude) and top (latitude) values in WGS84, representing the\n * bounding box for the provided MGRS reference.\n */\nexport function inverse(mgrs) {\n const bbox = UTMtoLL(decode(mgrs.toUpperCase()));\n if (bbox.lat && bbox.lon) {\n return [bbox.lon, bbox.lat, bbox.lon, bbox.lat];\n }\n return [bbox.left, bbox.bottom, bbox.right, bbox.top];\n}\n\nexport function toPoint(mgrs) {\n if (mgrs === '') {\n throw new TypeError('toPoint received a blank string');\n }\n const bbox = UTMtoLL(decode(mgrs.toUpperCase()));\n if (bbox.lat && bbox.lon) {\n return [bbox.lon, bbox.lat];\n }\n return [(bbox.left + bbox.right) / 2, (bbox.top + bbox.bottom) / 2];\n}\n\n/**\n * Conversion from degrees to radians.\n *\n * @private\n * @param {number} deg the angle in degrees.\n * @return {number} the angle in radians.\n */\nfunction degToRad(deg) {\n return (deg * (Math.PI / 180));\n}\n\n/**\n * Conversion from radians to degrees.\n *\n * @private\n * @param {number} rad the angle in radians.\n * @return {number} the angle in degrees.\n */\nfunction radToDeg(rad) {\n return (180 * (rad / Math.PI));\n}\n\n/**\n * Converts a set of Longitude and Latitude co-ordinates to UTM\n * using the WGS84 ellipsoid.\n *\n * @private\n * @param {object} ll Object literal with lat and lon properties\n * representing the WGS84 coordinate to be converted.\n * @return {object} Object literal containing the UTM value with easting,\n * northing, zoneNumber and zoneLetter properties, and an optional\n * accuracy property in digits. Returns null if the conversion failed.\n */\nfunction LLtoUTM(ll) {\n const Lat = ll.lat;\n const Long = ll.lon;\n const a = SEMI_MAJOR_AXIS;\n const LatRad = degToRad(Lat);\n const LongRad = degToRad(Long);\n let ZoneNumber;\n // (int)\n ZoneNumber = Math.floor((Long + 180) / 6) + 1;\n\n //Make sure the longitude 180 is in Zone 60\n if (Long === 180) {\n ZoneNumber = 60;\n }\n\n // Special zone for Norway\n if (Lat >= 56 && Lat < 64 && Long >= 3 && Long < 12) {\n ZoneNumber = 32;\n }\n\n // Special zones for Svalbard\n if (Lat >= 72 && Lat < 84) {\n if (Long >= 0 && Long < 9) {\n ZoneNumber = 31;\n }\n else if (Long >= 9 && Long < 21) {\n ZoneNumber = 33;\n }\n else if (Long >= 21 && Long < 33) {\n ZoneNumber = 35;\n }\n else if (Long >= 33 && Long < 42) {\n ZoneNumber = 37;\n }\n }\n\n // +HALF_UTM_ZONE_WIDTH puts origin in middle of zone\n const LongOrigin = (ZoneNumber - 1) * UTM_ZONE_WIDTH - 180 + HALF_UTM_ZONE_WIDTH;\n\n const LongOriginRad = degToRad(LongOrigin);\n\n const eccPrimeSquared = (ECC_SQUARED) / (1 - ECC_SQUARED);\n\n const N = a / Math.sqrt(1 - ECC_SQUARED * Math.sin(LatRad) * Math.sin(LatRad));\n const T = Math.tan(LatRad) * Math.tan(LatRad);\n const C = eccPrimeSquared * Math.cos(LatRad) * Math.cos(LatRad);\n const A = Math.cos(LatRad) * (LongRad - LongOriginRad);\n\n const M = a * ((1 - ECC_SQUARED / 4 - 3 * ECC_SQUARED * ECC_SQUARED / 64 - 5 * ECC_SQUARED * ECC_SQUARED * ECC_SQUARED / 256) * LatRad - (3 * ECC_SQUARED / 8 + 3 * ECC_SQUARED * ECC_SQUARED / 32 + 45 * ECC_SQUARED * ECC_SQUARED * ECC_SQUARED / 1024) * Math.sin(2 * LatRad) + (15 * ECC_SQUARED * ECC_SQUARED / 256 + 45 * ECC_SQUARED * ECC_SQUARED * ECC_SQUARED / 1024) * Math.sin(4 * LatRad) - (35 * ECC_SQUARED * ECC_SQUARED * ECC_SQUARED / 3072) * Math.sin(6 * LatRad));\n\n const UTMEasting = (SCALE_FACTOR * N * (A + (1 - T + C) * A * A * A / 6 + (5 - 18 * T + T * T + 72 * C - 58 * eccPrimeSquared) * A * A * A * A * A / 120) + EASTING_OFFSET);\n\n let UTMNorthing = (SCALE_FACTOR * (M + N * Math.tan(LatRad) * (A * A / 2 + (5 - T + 9 * C + 4 * C * C) * A * A * A * A / 24 + (61 - 58 * T + T * T + 600 * C - 330 * eccPrimeSquared) * A * A * A * A * A * A / 720)));\n if (Lat < 0) {\n UTMNorthing += NORTHING_OFFFSET;\n }\n\n return {\n northing: Math.trunc(UTMNorthing),\n easting: Math.trunc(UTMEasting),\n zoneNumber: ZoneNumber,\n zoneLetter: getLetterDesignator(Lat)\n };\n}\n\n/**\n * Converts UTM coords to lat/long, using the WGS84 ellipsoid. This is a convenience\n * class where the Zone can be specified as a single string eg.\"60N\" which\n * is then broken down into the ZoneNumber and ZoneLetter.\n *\n * @private\n * @param {object} utm An object literal with northing, easting, zoneNumber\n * and zoneLetter properties. If an optional accuracy property is\n * provided (in meters), a bounding box will be returned instead of\n * latitude and longitude.\n * @return {object} An object literal containing either lat and lon values\n * (if no accuracy was provided), or top, right, bottom and left values\n * for the bounding box calculated according to the provided accuracy.\n * Returns null if the conversion failed.\n */\nfunction UTMtoLL(utm) {\n\n const UTMNorthing = utm.northing;\n const UTMEasting = utm.easting;\n const { zoneLetter, zoneNumber } = utm;\n // check the ZoneNummber is valid\n if (zoneNumber < 0 || zoneNumber > 60) {\n return null;\n }\n\n const a = SEMI_MAJOR_AXIS;\n const e1 = (1 - Math.sqrt(1 - ECC_SQUARED)) / (1 + Math.sqrt(1 - ECC_SQUARED));\n\n // remove 500,000 meter offset for longitude\n const x = UTMEasting - EASTING_OFFSET;\n let y = UTMNorthing;\n\n // We must know somehow if we are in the Northern or Southern\n // hemisphere, this is the only time we use the letter So even\n // if the Zone letter isn't exactly correct it should indicate\n // the hemisphere correctly\n if (zoneLetter < 'N') {\n y -= NORTHING_OFFFSET; // remove offset used for southern hemisphere\n }\n\n // +HALF_UTM_ZONE_WIDTH puts origin in middle of zone\n const LongOrigin = (zoneNumber - 1) * UTM_ZONE_WIDTH - 180 + HALF_UTM_ZONE_WIDTH;\n\n const eccPrimeSquared = (ECC_SQUARED) / (1 - ECC_SQUARED);\n\n const M = y / SCALE_FACTOR;\n const mu = M / (a * (1 - ECC_SQUARED / 4 - 3 * ECC_SQUARED * ECC_SQUARED / 64 - 5 * ECC_SQUARED * ECC_SQUARED * ECC_SQUARED / 256));\n\n const phi1Rad = mu + (3 * e1 / 2 - 27 * e1 * e1 * e1 / 32) * Math.sin(2 * mu) + (21 * e1 * e1 / 16 - 55 * e1 * e1 * e1 * e1 / 32) * Math.sin(4 * mu) + (151 * e1 * e1 * e1 / 96) * Math.sin(6 * mu);\n // double phi1 = ProjMath.radToDeg(phi1Rad);\n\n const N1 = a / Math.sqrt(1 - ECC_SQUARED * Math.sin(phi1Rad) * Math.sin(phi1Rad));\n const T1 = Math.tan(phi1Rad) * Math.tan(phi1Rad);\n const C1 = eccPrimeSquared * Math.cos(phi1Rad) * Math.cos(phi1Rad);\n const R1 = a * (1 - ECC_SQUARED) / Math.pow(1 - ECC_SQUARED * Math.sin(phi1Rad) * Math.sin(phi1Rad), 1.5);\n const D = x / (N1 * SCALE_FACTOR);\n\n let lat = phi1Rad - (N1 * Math.tan(phi1Rad) / R1) * (D * D / 2 - (5 + 3 * T1 + 10 * C1 - 4 * C1 * C1 - 9 * eccPrimeSquared) * D * D * D * D / 24 + (61 + 90 * T1 + 298 * C1 + 45 * T1 * T1 - 252 * eccPrimeSquared - 3 * C1 * C1) * D * D * D * D * D * D / 720);\n lat = radToDeg(lat);\n\n let lon = (D - (1 + 2 * T1 + C1) * D * D * D / 6 + (5 - 2 * C1 + 28 * T1 - 3 * C1 * C1 + 8 * eccPrimeSquared + 24 * T1 * T1) * D * D * D * D * D / 120) / Math.cos(phi1Rad);\n lon = LongOrigin + radToDeg(lon);\n\n let result;\n if (typeof utm.accuracy === 'number') {\n const topRight = UTMtoLL({\n northing: utm.northing + utm.accuracy,\n easting: utm.easting + utm.accuracy,\n zoneLetter: utm.zoneLetter,\n zoneNumber: utm.zoneNumber\n });\n result = {\n top: topRight.lat,\n right: topRight.lon,\n bottom: lat,\n left: lon\n };\n }\n else {\n result = {\n lat,\n lon\n };\n }\n return result;\n}\n\n/**\n * Calculates the MGRS letter designator for the given latitude.\n *\n * @private (Not intended for public API, only exported for testing.)\n * @param {number} latitude The latitude in WGS84 to get the letter designator\n * for.\n * @return {string} The letter designator.\n */\nexport function getLetterDesignator(latitude) {\n if (latitude <= 84 && latitude >= 72) {\n // the X band is 12 degrees high\n return 'X';\n } else if (latitude < 72 && latitude >= -80) {\n // Latitude bands are lettered C through X, excluding I and O\n const bandLetters = 'CDEFGHJKLMNPQRSTUVWX';\n const bandHeight = 8;\n const minLatitude = -80;\n const index = Math.floor((latitude - minLatitude) / bandHeight);\n return bandLetters[index];\n } else if (latitude > 84 || latitude < -80) {\n //This is here as an error flag to show that the Latitude is\n //outside MGRS limits\n return 'Z';\n }\n}\n\n/**\n * Encodes a UTM location as MGRS string.\n *\n * @private\n * @param {object} utm An object literal with easting, northing,\n * zoneLetter, zoneNumber\n * @param {number} accuracy Accuracy in digits (0-5).\n * @return {string} MGRS string for the given UTM location.\n */\nfunction encode(utm, accuracy) {\n // prepend with leading zeroes\n const seasting = '00000' + utm.easting,\n snorthing = '00000' + utm.northing;\n\n return utm.zoneNumber + utm.zoneLetter + get100kID(utm.easting, utm.northing, utm.zoneNumber) + seasting.substr(seasting.length - 5, accuracy) + snorthing.substr(snorthing.length - 5, accuracy);\n}\n\n/**\n * Get the two letter 100k designator for a given UTM easting,\n * northing and zone number value.\n *\n * @private\n * @param {number} easting\n * @param {number} northing\n * @param {number} zoneNumber\n * @return {string} the two letter 100k designator for the given UTM location.\n */\nfunction get100kID(easting, northing, zoneNumber) {\n const setParm = get100kSetForZone(zoneNumber);\n const setColumn = Math.floor(easting / 100000);\n const setRow = Math.floor(northing / 100000) % 20;\n return getLetter100kID(setColumn, setRow, setParm);\n}\n\n/**\n * Given a UTM zone number, figure out the MGRS 100K set it is in.\n *\n * @private\n * @param {number} i An UTM zone number.\n * @return {number} the 100k set the UTM zone is in.\n */\nfunction get100kSetForZone(i) {\n let setParm = i % NUM_100K_SETS;\n if (setParm === 0) {\n setParm = NUM_100K_SETS;\n }\n\n return setParm;\n}\n\n/**\n * Get the two-letter MGRS 100k designator given information\n * translated from the UTM northing, easting and zone number.\n *\n * @private\n * @param {number} column the column index as it relates to the MGRS\n * 100k set spreadsheet, created from the UTM easting.\n * Values are 1-8.\n * @param {number} row the row index as it relates to the MGRS 100k set\n * spreadsheet, created from the UTM northing value. Values\n * are from 0-19.\n * @param {number} parm the set block, as it relates to the MGRS 100k set\n * spreadsheet, created from the UTM zone. Values are from\n * 1-60.\n * @return {string} two letter MGRS 100k code.\n */\nfunction getLetter100kID(column, row, parm) {\n // colOrigin and rowOrigin are the letters at the origin of the set\n const index = parm - 1;\n const colOrigin = SET_ORIGIN_COLUMN_LETTERS.charCodeAt(index);\n const rowOrigin = SET_ORIGIN_ROW_LETTERS.charCodeAt(index);\n\n // colInt and rowInt are the letters to build to return\n let colInt = colOrigin + column - 1;\n let rowInt = rowOrigin + row;\n let rollover = false;\n\n if (colInt > Z) {\n colInt = colInt - Z + A - 1;\n rollover = true;\n }\n\n if (colInt === I || (colOrigin < I && colInt > I) || ((colInt > I || colOrigin < I) && rollover)) {\n colInt++;\n }\n\n if (colInt === O || (colOrigin < O && colInt > O) || ((colInt > O || colOrigin < O) && rollover)) {\n colInt++;\n\n if (colInt === I) {\n colInt++;\n }\n }\n\n if (colInt > Z) {\n colInt = colInt - Z + A - 1;\n }\n\n if (rowInt > V) {\n rowInt = rowInt - V + A - 1;\n rollover = true;\n }\n else {\n rollover = false;\n }\n\n if (((rowInt === I) || ((rowOrigin < I) && (rowInt > I))) || (((rowInt > I) || (rowOrigin < I)) && rollover)) {\n rowInt++;\n }\n\n if (((rowInt === O) || ((rowOrigin < O) && (rowInt > O))) || (((rowInt > O) || (rowOrigin < O)) && rollover)) {\n rowInt++;\n\n if (rowInt === I) {\n rowInt++;\n }\n }\n\n if (rowInt > V) {\n rowInt = rowInt - V + A - 1;\n }\n\n const twoLetter = String.fromCharCode(colInt) + String.fromCharCode(rowInt);\n return twoLetter;\n}\n\n/**\n * Decode the UTM parameters from a MGRS string.\n *\n * @private\n * @param {string} mgrsString an UPPERCASE coordinate string is expected.\n * @return {object} An object literal with easting, northing, zoneLetter,\n * zoneNumber and accuracy (in meters) properties.\n */\nfunction decode(mgrsString) {\n\n if (mgrsString && mgrsString.length === 0) {\n throw new TypeError('MGRSPoint coverting from nothing');\n }\n\n //remove any spaces in MGRS String\n mgrsString = mgrsString.replace(/ /g, '');\n\n const { length } = mgrsString;\n\n let hunK = null;\n let sb = '';\n let testChar;\n let i = 0;\n\n // get Zone number\n while (!(/[A-Z]/).test(testChar = mgrsString.charAt(i))) {\n if (i >= 2) {\n throw new Error(`MGRSPoint bad conversion from: ${mgrsString}`);\n }\n sb += testChar;\n i++;\n }\n\n const zoneNumber = parseInt(sb, 10);\n\n if (i === 0 || i + 3 > length) {\n // A good MGRS string has to be 4-5 digits long,\n // ##AAA/#AAA at least.\n throw new Error(`MGRSPoint bad conversion from ${mgrsString}`);\n }\n\n const zoneLetter = mgrsString.charAt(i++);\n\n // Should we check the zone letter here? Why not.\n if (zoneLetter <= 'A' || zoneLetter === 'B' || zoneLetter === 'Y' || zoneLetter >= 'Z' || zoneLetter === 'I' || zoneLetter === 'O') {\n throw new Error(`MGRSPoint zone letter ${zoneLetter} not handled: ${mgrsString}`);\n }\n\n hunK = mgrsString.substring(i, i += 2);\n\n const set = get100kSetForZone(zoneNumber);\n\n const east100k = getEastingFromChar(hunK.charAt(0), set);\n let north100k = getNorthingFromChar(hunK.charAt(1), set);\n\n // We have a bug where the northing may be 2000000 too low.\n // How\n // do we know when to roll over?\n\n while (north100k < getMinNorthing(zoneLetter)) {\n north100k += 2000000;\n }\n\n // calculate the char index for easting/northing separator\n const remainder = length - i;\n\n if (remainder % 2 !== 0) {\n throw new Error(`MGRSPoint has to have an even number\nof digits after the zone letter and two 100km letters - front\nhalf for easting meters, second half for\nnorthing meters ${mgrsString}`);\n }\n\n const sep = remainder / 2;\n\n let sepEasting = 0;\n let sepNorthing = 0;\n let accuracyBonus, sepEastingString, sepNorthingString;\n if (sep > 0) {\n accuracyBonus = 100000 / Math.pow(10, sep);\n sepEastingString = mgrsString.substring(i, i + sep);\n sepEasting = parseFloat(sepEastingString) * accuracyBonus;\n sepNorthingString = mgrsString.substring(i + sep);\n sepNorthing = parseFloat(sepNorthingString) * accuracyBonus;\n }\n\n const easting = sepEasting + east100k;\n const northing = sepNorthing + north100k;\n\n return {\n easting,\n northing,\n zoneLetter,\n zoneNumber,\n accuracy: accuracyBonus\n };\n}\n\n/**\n * Given the first letter from a two-letter MGRS 100k zone, and given the\n * MGRS table set for the zone number, figure out the easting value that\n * should be added to the other, secondary easting value.\n *\n * @private\n * @param {string} e The first letter from a two-letter MGRS 100´k zone.\n * @param {number} set The MGRS table set for the zone number.\n * @return {number} The easting value for the given letter and set.\n */\nfunction getEastingFromChar(e, set) {\n // colOrigin is the letter at the origin of the set for the\n // column\n let curCol = SET_ORIGIN_COLUMN_LETTERS.charCodeAt(set - 1);\n let eastingValue = 100000;\n let rewindMarker = false;\n\n while (curCol !== e.charCodeAt(0)) {\n curCol++;\n if (curCol === I) {\n curCol++;\n }\n if (curCol === O) {\n curCol++;\n }\n if (curCol > Z) {\n if (rewindMarker) {\n throw new Error(`Bad character: ${e}`);\n }\n curCol = A;\n rewindMarker = true;\n }\n eastingValue += 100000;\n }\n\n return eastingValue;\n}\n\n/**\n * Given the second letter from a two-letter MGRS 100k zone, and given the\n * MGRS table set for the zone number, figure out the northing value that\n * should be added to the other, secondary northing value. You have to\n * remember that Northings are determined from the equator, and the vertical\n * cycle of letters mean a 2000000 additional northing meters. This happens\n * approx. every 18 degrees of latitude. This method does *NOT* count any\n * additional northings. You have to figure out how many 2000000 meters need\n * to be added for the zone letter of the MGRS coordinate.\n *\n * @private\n * @param {string} n Second letter of the MGRS 100k zone\n * @param {number} set The MGRS table set number, which is dependent on the\n * UTM zone number.\n * @return {number} The northing value for the given letter and set.\n */\nfunction getNorthingFromChar(n, set) {\n\n if (n > 'V') {\n throw new TypeError(`MGRSPoint given invalid Northing ${n}`);\n }\n\n // rowOrigin is the letter at the origin of the set for the\n // column\n let curRow = SET_ORIGIN_ROW_LETTERS.charCodeAt(set - 1);\n let northingValue = 0;\n let rewindMarker = false;\n\n while (curRow !== n.charCodeAt(0)) {\n curRow++;\n if (curRow === I) {\n curRow++;\n }\n if (curRow === O) {\n curRow++;\n }\n // fixing a bug making whole application hang in this loop\n // when 'n' is a wrong character\n if (curRow > V) {\n if (rewindMarker) { // making sure that this loop ends\n throw new Error(`Bad character: ${n}`);\n }\n curRow = A;\n rewindMarker = true;\n }\n northingValue += 100000;\n }\n\n return northingValue;\n}\n\n/**\n * The function getMinNorthing returns the minimum northing value of a MGRS\n * zone.\n *\n * Ported from Geotrans' c Lattitude_Band_Value structure table.\n *\n * @private\n * @param {string} zoneLetter The MGRS zone to get the min northing for.\n * @return {number}\n */\nfunction getMinNorthing(zoneLetter) {\n let northing;\n switch (zoneLetter) {\n case 'C':\n northing = 1100000;\n break;\n case 'D':\n northing = 2000000;\n break;\n case 'E':\n northing = 2800000;\n break;\n case 'F':\n northing = 3700000;\n break;\n case 'G':\n northing = 4600000;\n break;\n case 'H':\n northing = 5500000;\n break;\n case 'J':\n northing = 6400000;\n break;\n case 'K':\n northing = 7300000;\n break;\n case 'L':\n northing = 8200000;\n break;\n case 'M':\n northing = 9100000;\n break;\n case 'N':\n northing = 0;\n break;\n case 'P':\n northing = 800000;\n break;\n case 'Q':\n northing = 1700000;\n break;\n case 'R':\n northing = 2600000;\n break;\n case 'S':\n northing = 3500000;\n break;\n case 'T':\n northing = 4400000;\n break;\n case 'U':\n northing = 5300000;\n break;\n case 'V':\n northing = 6200000;\n break;\n case 'W':\n northing = 7000000;\n break;\n case 'X':\n northing = 7900000;\n break;\n default:\n northing = -1;\n }\n if (northing >= 0) {\n return northing;\n }\n else {\n throw new TypeError(`Invalid zone letter: ${zoneLetter}`);\n }\n\n}\n"],"names":["A","I","O","forward","ll","accuracy","Array","isArray","TypeError","lon","lat","utm","seasting","easting","snorthing","northing","zoneNumber","zoneLetter","setParm","get100kSetForZone","setColumn","Math","floor","setRow","column","row","parm","index","colOrigin","charCodeAt","rowOrigin","colInt","rowInt","rollover","String","fromCharCode","getLetter100kID","get100kID","substr","length","encode","Lat","Long","a","LatRad","degToRad","LongRad","ZoneNumber","LongOriginRad","UTM_ZONE_WIDTH","N","sqrt","sin","T","tan","C","cos","M","UTMEasting","UTMNorthing","trunc","getLetterDesignator","LLtoUTM","inverse","mgrs","bbox","UTMtoLL","decode","toUpperCase","left","bottom","right","top","toPoint","deg","PI","radToDeg","rad","e1","x","y","LongOrigin","mu","phi1Rad","N1","T1","C1","R1","pow","D","result","topRight","latitude","bandHeight","minLatitude","i","mgrsString","replace","testChar","hunK","sb","test","charAt","Error","parseInt","substring","set","east100k","e","curCol","eastingValue","rewindMarker","getEastingFromChar","north100k","n","curRow","northingValue","getNorthingFromChar","getMinNorthing","remainder","sep","accuracyBonus","sepEastingString","sepNorthingString","sepEasting","sepNorthing","parseFloat"],"mappings":"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EAAerG,GACtB,IAAIF,EACJ,OAAQE,GACR,IAAK,IACHF,EAAW,KACX,MACF,IAAK,IACHA,EAAW,IACX,MACF,IAAK,IACHA,EAAW,KACX,MACF,IAAK,IACHA,EAAW,KACX,MACF,IAAK,IACHA,EAAW,KACX,MACF,IAAK,IACHA,EAAW,KACX,MACF,IAAK,IACHA,EAAW,KACX,MACF,IAAK,IACHA,EAAW,KACX,MACF,IAAK,IACHA,EAAW,KACX,MACF,IAAK,IACHA,EAAW,KACX,MACF,IAAK,IACHA,EAAW,EACX,MACF,IAAK,IACHA,EAAW,IACX,MACF,IAAK,IACHA,EAAW,KACX,MACF,IAAK,IACHA,EAAW,KACX,MACF,IAAK,IACHA,EAAW,KACX,MACF,IAAK,IACHA,EAAW,KACX,MACF,IAAK,IACHA,EAAW,KACX,MACF,IAAK,IACHA,EAAW,KACX,MACF,IAAK,IACHA,EAAW,IACX,MACF,IAAK,IACHA,EAAW,KACX,MACF,QACEA,GAAY,EAEd,GAAIA,GAAY,EACd,OAAOA,EAGP,MAAM,IAAIP,UAAU,wBAAwBS"} \ No newline at end of file diff --git a/dist/mgrs.js b/dist/mgrs.js index 48f8d63..4994500 100644 --- a/dist/mgrs.js +++ b/dist/mgrs.js @@ -1,758 +1,758 @@ (function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : - typeof define === 'function' && define.amd ? define(['exports'], factory) : - (factory((global.mgrs = global.mgrs || {}))); -}(this, (function (exports) { 'use strict'; - -/** - * UTM zones are grouped, and assigned to one of a group of 6 - * sets. - * - * {int} @private - */ -var NUM_100K_SETS = 6; - -/** - * The column letters (for easting) of the lower left value, per - * set. - * - * {string} @private - */ -var SET_ORIGIN_COLUMN_LETTERS = 'AJSAJS'; - -/** - * The row letters (for northing) of the lower left value, per - * set. - * - * {string} @private - */ -var SET_ORIGIN_ROW_LETTERS = 'AFAFAF'; - -var A = 65; // A -var I = 73; // I -var O = 79; // O -var V = 86; // V -var Z = 90; // Z -var mgrs = { - forward: forward, - inverse: inverse, - toPoint: toPoint -}; -/** - * Conversion of lat/lon to MGRS. - * - * @param {object} ll Object literal with lat and lon properties on a - * WGS84 ellipsoid. - * @param {int} accuracy Accuracy in digits (5 for 1 m, 4 for 10 m, 3 for - * 100 m, 2 for 1000 m or 1 for 10000 m). Optional, default is 5. - * @return {string} the MGRS string for the given location and accuracy. - */ -function forward(ll, accuracy) { - accuracy = accuracy || 5; // default accuracy 1m - return encode(LLtoUTM({ - lat: ll[1], - lon: ll[0] - }), accuracy); -} - -/** - * Conversion of MGRS to lat/lon. - * - * @param {string} mgrs MGRS string. - * @return {array} An array with left (longitude), bottom (latitude), right - * (longitude) and top (latitude) values in WGS84, representing the - * bounding box for the provided MGRS reference. - */ -function inverse(mgrs) { - var bbox = UTMtoLL(decode(mgrs.toUpperCase())); - if (bbox.lat && bbox.lon) { - return [bbox.lon, bbox.lat, bbox.lon, bbox.lat]; - } - return [bbox.left, bbox.bottom, bbox.right, bbox.top]; -} + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : + typeof define === 'function' && define.amd ? define(['exports'], factory) : + (global = global || self, factory(global.mgrs = {})); +}(this, function (exports) { 'use strict'; + + /** + * UTM zones are grouped, and assigned to one of a group of 6 + * sets. + * + * {int} @private + */ + const NUM_100K_SETS = 6; + + /** + * The column letters (for easting) of the lower left value, per + * set. + * + * {string} @private + */ + const SET_ORIGIN_COLUMN_LETTERS = 'AJSAJS'; + + /** + * The row letters (for northing) of the lower left value, per + * set. + * + * {string} @private + */ + const SET_ORIGIN_ROW_LETTERS = 'AFAFAF'; + + const A = 65; // A + const I = 73; // I + const O = 79; // O + const V = 86; // V + const Z = 90; // Z + + /** + * First eccentricity squared + * {number} @private + */ + const ECC_SQUARED = 0.00669438; + + /** + * Scale factor along the central meridian + * {number} @private + */ + const SCALE_FACTOR = 0.9996; + + /** + * Semimajor axis (half the width of the earth) in meters + * {number} @private + */ + const SEMI_MAJOR_AXIS = 6378137; + + /** + * The easting of the central meridian of each UTM zone + * {number} @private + */ + const EASTING_OFFSET = 500000; + + /** + * The northing of the equator for southern hemisphere locations (in UTM) + * {number} @private + */ + const NORTHING_OFFFSET = 10000000; + + /** + * UTM zone width in degrees + * {number} private + */ + const UTM_ZONE_WIDTH = 6; + + /** + * Half the width of a UTM zone in degrees + * {number} private + */ + const HALF_UTM_ZONE_WIDTH = UTM_ZONE_WIDTH / 2; + + /** + * Convert lat/lon to MGRS. + * + * @param {[number, number]} ll Array with longitude and latitude on a + * WGS84 ellipsoid. + * @param {number} [accuracy=5] Accuracy in digits (5 for 1 m, 4 for 10 m, 3 for + * 100 m, 2 for 1 km, 1 for 10 km or 0 for 100 km). Optional, default is 5. + * @return {string} the MGRS string for the given location and accuracy. + */ + function forward(ll, accuracy) { + accuracy = typeof accuracy === 'number' ? accuracy : 5; // default accuracy 1m + + if (!Array.isArray(ll)) { + throw new TypeError('forward did not receive an array'); + } -function toPoint(mgrs) { - var bbox = UTMtoLL(decode(mgrs.toUpperCase())); - if (bbox.lat && bbox.lon) { - return [bbox.lon, bbox.lat]; - } - return [(bbox.left + bbox.right) / 2, (bbox.top + bbox.bottom) / 2]; -} -/** - * Conversion from degrees to radians. - * - * @private - * @param {number} deg the angle in degrees. - * @return {number} the angle in radians. - */ -function degToRad(deg) { - return (deg * (Math.PI / 180.0)); -} - -/** - * Conversion from radians to degrees. - * - * @private - * @param {number} rad the angle in radians. - * @return {number} the angle in degrees. - */ -function radToDeg(rad) { - return (180.0 * (rad / Math.PI)); -} - -/** - * Converts a set of Longitude and Latitude co-ordinates to UTM - * using the WGS84 ellipsoid. - * - * @private - * @param {object} ll Object literal with lat and lon properties - * representing the WGS84 coordinate to be converted. - * @return {object} Object literal containing the UTM value with easting, - * northing, zoneNumber and zoneLetter properties, and an optional - * accuracy property in digits. Returns null if the conversion failed. - */ -function LLtoUTM(ll) { - var Lat = ll.lat; - var Long = ll.lon; - var a = 6378137.0; //ellip.radius; - var eccSquared = 0.00669438; //ellip.eccsq; - var k0 = 0.9996; - var LongOrigin; - var eccPrimeSquared; - var N, T, C, A, M; - var LatRad = degToRad(Lat); - var LongRad = degToRad(Long); - var LongOriginRad; - var ZoneNumber; - // (int) - ZoneNumber = Math.floor((Long + 180) / 6) + 1; - - //Make sure the longitude 180.00 is in Zone 60 - if (Long === 180) { - ZoneNumber = 60; - } + if (typeof ll[0] === 'string' || typeof ll[1] === 'string') { + throw new TypeError('forward received an array of strings, but it only accepts an array of numbers.'); + } + + const [ lon, lat ] = ll; + if (lon < -180 || lon > 180) { + throw new TypeError(`forward received an invalid longitude of ${lon}`); + } + if (lat < -90 || lat > 90) { + throw new TypeError(`forward received an invalid latitude of ${lat}`); + } - // Special zone for Norway - if (Lat >= 56.0 && Lat < 64.0 && Long >= 3.0 && Long < 12.0) { - ZoneNumber = 32; + if (lat < -80 || lat > 84) { + throw new TypeError(`forward received a latitude of ${lat}, but this library does not support conversions of points in polar regions below 80°S and above 84°N`); + } + + return encode(LLtoUTM({ lat, lon }), accuracy); + } + + /** + * Convert MGRS to lat/lon bounding box. + * + * @param {string} mgrs MGRS string. + * @return {[number,number,number,number]} An array with left (longitude), + * bottom (latitude), right + * (longitude) and top (latitude) values in WGS84, representing the + * bounding box for the provided MGRS reference. + */ + function inverse(mgrs) { + const bbox = UTMtoLL(decode(mgrs.toUpperCase())); + if (bbox.lat && bbox.lon) { + return [bbox.lon, bbox.lat, bbox.lon, bbox.lat]; + } + return [bbox.left, bbox.bottom, bbox.right, bbox.top]; } - // Special zones for Svalbard - if (Lat >= 72.0 && Lat < 84.0) { - if (Long >= 0.0 && Long < 9.0) { - ZoneNumber = 31; + function toPoint(mgrs) { + if (mgrs === '') { + throw new TypeError('toPoint received a blank string'); } - else if (Long >= 9.0 && Long < 21.0) { - ZoneNumber = 33; + const bbox = UTMtoLL(decode(mgrs.toUpperCase())); + if (bbox.lat && bbox.lon) { + return [bbox.lon, bbox.lat]; } - else if (Long >= 21.0 && Long < 33.0) { - ZoneNumber = 35; + return [(bbox.left + bbox.right) / 2, (bbox.top + bbox.bottom) / 2]; + } + + /** + * Conversion from degrees to radians. + * + * @private + * @param {number} deg the angle in degrees. + * @return {number} the angle in radians. + */ + function degToRad(deg) { + return (deg * (Math.PI / 180)); + } + + /** + * Conversion from radians to degrees. + * + * @private + * @param {number} rad the angle in radians. + * @return {number} the angle in degrees. + */ + function radToDeg(rad) { + return (180 * (rad / Math.PI)); + } + + /** + * Converts a set of Longitude and Latitude co-ordinates to UTM + * using the WGS84 ellipsoid. + * + * @private + * @param {object} ll Object literal with lat and lon properties + * representing the WGS84 coordinate to be converted. + * @return {object} Object literal containing the UTM value with easting, + * northing, zoneNumber and zoneLetter properties, and an optional + * accuracy property in digits. Returns null if the conversion failed. + */ + function LLtoUTM(ll) { + const Lat = ll.lat; + const Long = ll.lon; + const a = SEMI_MAJOR_AXIS; + const LatRad = degToRad(Lat); + const LongRad = degToRad(Long); + let ZoneNumber; + // (int) + ZoneNumber = Math.floor((Long + 180) / 6) + 1; + + //Make sure the longitude 180 is in Zone 60 + if (Long === 180) { + ZoneNumber = 60; } - else if (Long >= 33.0 && Long < 42.0) { - ZoneNumber = 37; + + // Special zone for Norway + if (Lat >= 56 && Lat < 64 && Long >= 3 && Long < 12) { + ZoneNumber = 32; } - } - LongOrigin = (ZoneNumber - 1) * 6 - 180 + 3; //+3 puts origin - // in middle of - // zone - LongOriginRad = degToRad(LongOrigin); + // Special zones for Svalbard + if (Lat >= 72 && Lat < 84) { + if (Long >= 0 && Long < 9) { + ZoneNumber = 31; + } + else if (Long >= 9 && Long < 21) { + ZoneNumber = 33; + } + else if (Long >= 21 && Long < 33) { + ZoneNumber = 35; + } + else if (Long >= 33 && Long < 42) { + ZoneNumber = 37; + } + } - eccPrimeSquared = (eccSquared) / (1 - eccSquared); + // +HALF_UTM_ZONE_WIDTH puts origin in middle of zone + const LongOrigin = (ZoneNumber - 1) * UTM_ZONE_WIDTH - 180 + HALF_UTM_ZONE_WIDTH; - N = a / Math.sqrt(1 - eccSquared * Math.sin(LatRad) * Math.sin(LatRad)); - T = Math.tan(LatRad) * Math.tan(LatRad); - C = eccPrimeSquared * Math.cos(LatRad) * Math.cos(LatRad); - A = Math.cos(LatRad) * (LongRad - LongOriginRad); + const LongOriginRad = degToRad(LongOrigin); - M = a * ((1 - eccSquared / 4 - 3 * eccSquared * eccSquared / 64 - 5 * eccSquared * eccSquared * eccSquared / 256) * LatRad - (3 * eccSquared / 8 + 3 * eccSquared * eccSquared / 32 + 45 * eccSquared * eccSquared * eccSquared / 1024) * Math.sin(2 * LatRad) + (15 * eccSquared * eccSquared / 256 + 45 * eccSquared * eccSquared * eccSquared / 1024) * Math.sin(4 * LatRad) - (35 * eccSquared * eccSquared * eccSquared / 3072) * Math.sin(6 * LatRad)); + const eccPrimeSquared = (ECC_SQUARED) / (1 - ECC_SQUARED); - var UTMEasting = (k0 * N * (A + (1 - T + C) * A * A * A / 6.0 + (5 - 18 * T + T * T + 72 * C - 58 * eccPrimeSquared) * A * A * A * A * A / 120.0) + 500000.0); + const N = a / Math.sqrt(1 - ECC_SQUARED * Math.sin(LatRad) * Math.sin(LatRad)); + const T = Math.tan(LatRad) * Math.tan(LatRad); + const C = eccPrimeSquared * Math.cos(LatRad) * Math.cos(LatRad); + const A = Math.cos(LatRad) * (LongRad - LongOriginRad); - var UTMNorthing = (k0 * (M + N * Math.tan(LatRad) * (A * A / 2 + (5 - T + 9 * C + 4 * C * C) * A * A * A * A / 24.0 + (61 - 58 * T + T * T + 600 * C - 330 * eccPrimeSquared) * A * A * A * A * A * A / 720.0))); - if (Lat < 0.0) { - UTMNorthing += 10000000.0; //10000000 meter offset for - // southern hemisphere - } + const M = a * ((1 - ECC_SQUARED / 4 - 3 * ECC_SQUARED * ECC_SQUARED / 64 - 5 * ECC_SQUARED * ECC_SQUARED * ECC_SQUARED / 256) * LatRad - (3 * ECC_SQUARED / 8 + 3 * ECC_SQUARED * ECC_SQUARED / 32 + 45 * ECC_SQUARED * ECC_SQUARED * ECC_SQUARED / 1024) * Math.sin(2 * LatRad) + (15 * ECC_SQUARED * ECC_SQUARED / 256 + 45 * ECC_SQUARED * ECC_SQUARED * ECC_SQUARED / 1024) * Math.sin(4 * LatRad) - (35 * ECC_SQUARED * ECC_SQUARED * ECC_SQUARED / 3072) * Math.sin(6 * LatRad)); - return { - northing: Math.trunc(UTMNorthing), - easting: Math.trunc(UTMEasting), - zoneNumber: ZoneNumber, - zoneLetter: getLetterDesignator(Lat) - }; -} - -/** - * Converts UTM coords to lat/long, using the WGS84 ellipsoid. This is a convenience - * class where the Zone can be specified as a single string eg."60N" which - * is then broken down into the ZoneNumber and ZoneLetter. - * - * @private - * @param {object} utm An object literal with northing, easting, zoneNumber - * and zoneLetter properties. If an optional accuracy property is - * provided (in meters), a bounding box will be returned instead of - * latitude and longitude. - * @return {object} An object literal containing either lat and lon values - * (if no accuracy was provided), or top, right, bottom and left values - * for the bounding box calculated according to the provided accuracy. - * Returns null if the conversion failed. - */ -function UTMtoLL(utm) { - - var UTMNorthing = utm.northing; - var UTMEasting = utm.easting; - var zoneLetter = utm.zoneLetter; - var zoneNumber = utm.zoneNumber; - // check the ZoneNummber is valid - if (zoneNumber < 0 || zoneNumber > 60) { - return null; - } + const UTMEasting = (SCALE_FACTOR * N * (A + (1 - T + C) * A * A * A / 6 + (5 - 18 * T + T * T + 72 * C - 58 * eccPrimeSquared) * A * A * A * A * A / 120) + EASTING_OFFSET); - var k0 = 0.9996; - var a = 6378137.0; //ellip.radius; - var eccSquared = 0.00669438; //ellip.eccsq; - var eccPrimeSquared; - var e1 = (1 - Math.sqrt(1 - eccSquared)) / (1 + Math.sqrt(1 - eccSquared)); - var N1, T1, C1, R1, D, M; - var LongOrigin; - var mu, phi1Rad; - - // remove 500,000 meter offset for longitude - var x = UTMEasting - 500000.0; - var y = UTMNorthing; - - // We must know somehow if we are in the Northern or Southern - // hemisphere, this is the only time we use the letter So even - // if the Zone letter isn't exactly correct it should indicate - // the hemisphere correctly - if (zoneLetter < 'N') { - y -= 10000000.0; // remove 10,000,000 meter offset used - // for southern hemisphere - } + let UTMNorthing = (SCALE_FACTOR * (M + N * Math.tan(LatRad) * (A * A / 2 + (5 - T + 9 * C + 4 * C * C) * A * A * A * A / 24 + (61 - 58 * T + T * T + 600 * C - 330 * eccPrimeSquared) * A * A * A * A * A * A / 720))); + if (Lat < 0) { + UTMNorthing += NORTHING_OFFFSET; + } - // There are 60 zones with zone 1 being at West -180 to -174 - LongOrigin = (zoneNumber - 1) * 6 - 180 + 3; // +3 puts origin - // in middle of - // zone - - eccPrimeSquared = (eccSquared) / (1 - eccSquared); - - M = y / k0; - mu = M / (a * (1 - eccSquared / 4 - 3 * eccSquared * eccSquared / 64 - 5 * eccSquared * eccSquared * eccSquared / 256)); - - phi1Rad = mu + (3 * e1 / 2 - 27 * e1 * e1 * e1 / 32) * Math.sin(2 * mu) + (21 * e1 * e1 / 16 - 55 * e1 * e1 * e1 * e1 / 32) * Math.sin(4 * mu) + (151 * e1 * e1 * e1 / 96) * Math.sin(6 * mu); - // double phi1 = ProjMath.radToDeg(phi1Rad); - - N1 = a / Math.sqrt(1 - eccSquared * Math.sin(phi1Rad) * Math.sin(phi1Rad)); - T1 = Math.tan(phi1Rad) * Math.tan(phi1Rad); - C1 = eccPrimeSquared * Math.cos(phi1Rad) * Math.cos(phi1Rad); - R1 = a * (1 - eccSquared) / Math.pow(1 - eccSquared * Math.sin(phi1Rad) * Math.sin(phi1Rad), 1.5); - D = x / (N1 * k0); - - var lat = phi1Rad - (N1 * Math.tan(phi1Rad) / R1) * (D * D / 2 - (5 + 3 * T1 + 10 * C1 - 4 * C1 * C1 - 9 * eccPrimeSquared) * D * D * D * D / 24 + (61 + 90 * T1 + 298 * C1 + 45 * T1 * T1 - 252 * eccPrimeSquared - 3 * C1 * C1) * D * D * D * D * D * D / 720); - lat = radToDeg(lat); - - var lon = (D - (1 + 2 * T1 + C1) * D * D * D / 6 + (5 - 2 * C1 + 28 * T1 - 3 * C1 * C1 + 8 * eccPrimeSquared + 24 * T1 * T1) * D * D * D * D * D / 120) / Math.cos(phi1Rad); - lon = LongOrigin + radToDeg(lon); - - var result; - if (utm.accuracy) { - var topRight = UTMtoLL({ - northing: utm.northing + utm.accuracy, - easting: utm.easting + utm.accuracy, - zoneLetter: utm.zoneLetter, - zoneNumber: utm.zoneNumber - }); - result = { - top: topRight.lat, - right: topRight.lon, - bottom: lat, - left: lon + return { + northing: Math.trunc(UTMNorthing), + easting: Math.trunc(UTMEasting), + zoneNumber: ZoneNumber, + zoneLetter: getLetterDesignator(Lat) }; } - else { - result = { - lat: lat, - lon: lon - }; - } - return result; -} - -/** - * Calculates the MGRS letter designator for the given latitude. - * - * @private - * @param {number} lat The latitude in WGS84 to get the letter designator - * for. - * @return {char} The letter designator. - */ -function getLetterDesignator(lat) { - //This is here as an error flag to show that the Latitude is - //outside MGRS limits - var LetterDesignator = 'Z'; - - if ((84 >= lat) && (lat >= 72)) { - LetterDesignator = 'X'; - } - else if ((72 > lat) && (lat >= 64)) { - LetterDesignator = 'W'; - } - else if ((64 > lat) && (lat >= 56)) { - LetterDesignator = 'V'; - } - else if ((56 > lat) && (lat >= 48)) { - LetterDesignator = 'U'; - } - else if ((48 > lat) && (lat >= 40)) { - LetterDesignator = 'T'; - } - else if ((40 > lat) && (lat >= 32)) { - LetterDesignator = 'S'; - } - else if ((32 > lat) && (lat >= 24)) { - LetterDesignator = 'R'; - } - else if ((24 > lat) && (lat >= 16)) { - LetterDesignator = 'Q'; - } - else if ((16 > lat) && (lat >= 8)) { - LetterDesignator = 'P'; - } - else if ((8 > lat) && (lat >= 0)) { - LetterDesignator = 'N'; - } - else if ((0 > lat) && (lat >= -8)) { - LetterDesignator = 'M'; - } - else if ((-8 > lat) && (lat >= -16)) { - LetterDesignator = 'L'; - } - else if ((-16 > lat) && (lat >= -24)) { - LetterDesignator = 'K'; - } - else if ((-24 > lat) && (lat >= -32)) { - LetterDesignator = 'J'; - } - else if ((-32 > lat) && (lat >= -40)) { - LetterDesignator = 'H'; - } - else if ((-40 > lat) && (lat >= -48)) { - LetterDesignator = 'G'; - } - else if ((-48 > lat) && (lat >= -56)) { - LetterDesignator = 'F'; - } - else if ((-56 > lat) && (lat >= -64)) { - LetterDesignator = 'E'; - } - else if ((-64 > lat) && (lat >= -72)) { - LetterDesignator = 'D'; - } - else if ((-72 > lat) && (lat >= -80)) { - LetterDesignator = 'C'; - } - return LetterDesignator; -} - -/** - * Encodes a UTM location as MGRS string. - * - * @private - * @param {object} utm An object literal with easting, northing, - * zoneLetter, zoneNumber - * @param {number} accuracy Accuracy in digits (1-5). - * @return {string} MGRS string for the given UTM location. - */ -function encode(utm, accuracy) { - // prepend with leading zeroes - var seasting = "00000" + utm.easting, - snorthing = "00000" + utm.northing; - - return utm.zoneNumber + utm.zoneLetter + get100kID(utm.easting, utm.northing, utm.zoneNumber) + seasting.substr(seasting.length - 5, accuracy) + snorthing.substr(snorthing.length - 5, accuracy); -} - -/** - * Get the two letter 100k designator for a given UTM easting, - * northing and zone number value. - * - * @private - * @param {number} easting - * @param {number} northing - * @param {number} zoneNumber - * @return {string} the two letter 100k designator for the given UTM location. - */ -function get100kID(easting, northing, zoneNumber) { - var setParm = get100kSetForZone(zoneNumber); - var setColumn = Math.floor(easting / 100000); - var setRow = Math.floor(northing / 100000) % 20; - return getLetter100kID(setColumn, setRow, setParm); -} - -/** - * Given a UTM zone number, figure out the MGRS 100K set it is in. - * - * @private - * @param {number} i An UTM zone number. - * @return {number} the 100k set the UTM zone is in. - */ -function get100kSetForZone(i) { - var setParm = i % NUM_100K_SETS; - if (setParm === 0) { - setParm = NUM_100K_SETS; - } - return setParm; -} - -/** - * Get the two-letter MGRS 100k designator given information - * translated from the UTM northing, easting and zone number. - * - * @private - * @param {number} column the column index as it relates to the MGRS - * 100k set spreadsheet, created from the UTM easting. - * Values are 1-8. - * @param {number} row the row index as it relates to the MGRS 100k set - * spreadsheet, created from the UTM northing value. Values - * are from 0-19. - * @param {number} parm the set block, as it relates to the MGRS 100k set - * spreadsheet, created from the UTM zone. Values are from - * 1-60. - * @return {string} two letter MGRS 100k code. - */ -function getLetter100kID(column, row, parm) { - // colOrigin and rowOrigin are the letters at the origin of the set - var index = parm - 1; - var colOrigin = SET_ORIGIN_COLUMN_LETTERS.charCodeAt(index); - var rowOrigin = SET_ORIGIN_ROW_LETTERS.charCodeAt(index); - - // colInt and rowInt are the letters to build to return - var colInt = colOrigin + column - 1; - var rowInt = rowOrigin + row; - var rollover = false; - - if (colInt > Z) { - colInt = colInt - Z + A - 1; - rollover = true; - } + /** + * Converts UTM coords to lat/long, using the WGS84 ellipsoid. This is a convenience + * class where the Zone can be specified as a single string eg."60N" which + * is then broken down into the ZoneNumber and ZoneLetter. + * + * @private + * @param {object} utm An object literal with northing, easting, zoneNumber + * and zoneLetter properties. If an optional accuracy property is + * provided (in meters), a bounding box will be returned instead of + * latitude and longitude. + * @return {object} An object literal containing either lat and lon values + * (if no accuracy was provided), or top, right, bottom and left values + * for the bounding box calculated according to the provided accuracy. + * Returns null if the conversion failed. + */ + function UTMtoLL(utm) { + + const UTMNorthing = utm.northing; + const UTMEasting = utm.easting; + const { zoneLetter, zoneNumber } = utm; + // check the ZoneNummber is valid + if (zoneNumber < 0 || zoneNumber > 60) { + return null; + } + + const a = SEMI_MAJOR_AXIS; + const e1 = (1 - Math.sqrt(1 - ECC_SQUARED)) / (1 + Math.sqrt(1 - ECC_SQUARED)); + + // remove 500,000 meter offset for longitude + const x = UTMEasting - EASTING_OFFSET; + let y = UTMNorthing; + + // We must know somehow if we are in the Northern or Southern + // hemisphere, this is the only time we use the letter So even + // if the Zone letter isn't exactly correct it should indicate + // the hemisphere correctly + if (zoneLetter < 'N') { + y -= NORTHING_OFFFSET; // remove offset used for southern hemisphere + } - if (colInt === I || (colOrigin < I && colInt > I) || ((colInt > I || colOrigin < I) && rollover)) { - colInt++; + // +HALF_UTM_ZONE_WIDTH puts origin in middle of zone + const LongOrigin = (zoneNumber - 1) * UTM_ZONE_WIDTH - 180 + HALF_UTM_ZONE_WIDTH; + + const eccPrimeSquared = (ECC_SQUARED) / (1 - ECC_SQUARED); + + const M = y / SCALE_FACTOR; + const mu = M / (a * (1 - ECC_SQUARED / 4 - 3 * ECC_SQUARED * ECC_SQUARED / 64 - 5 * ECC_SQUARED * ECC_SQUARED * ECC_SQUARED / 256)); + + const phi1Rad = mu + (3 * e1 / 2 - 27 * e1 * e1 * e1 / 32) * Math.sin(2 * mu) + (21 * e1 * e1 / 16 - 55 * e1 * e1 * e1 * e1 / 32) * Math.sin(4 * mu) + (151 * e1 * e1 * e1 / 96) * Math.sin(6 * mu); + // double phi1 = ProjMath.radToDeg(phi1Rad); + + const N1 = a / Math.sqrt(1 - ECC_SQUARED * Math.sin(phi1Rad) * Math.sin(phi1Rad)); + const T1 = Math.tan(phi1Rad) * Math.tan(phi1Rad); + const C1 = eccPrimeSquared * Math.cos(phi1Rad) * Math.cos(phi1Rad); + const R1 = a * (1 - ECC_SQUARED) / Math.pow(1 - ECC_SQUARED * Math.sin(phi1Rad) * Math.sin(phi1Rad), 1.5); + const D = x / (N1 * SCALE_FACTOR); + + let lat = phi1Rad - (N1 * Math.tan(phi1Rad) / R1) * (D * D / 2 - (5 + 3 * T1 + 10 * C1 - 4 * C1 * C1 - 9 * eccPrimeSquared) * D * D * D * D / 24 + (61 + 90 * T1 + 298 * C1 + 45 * T1 * T1 - 252 * eccPrimeSquared - 3 * C1 * C1) * D * D * D * D * D * D / 720); + lat = radToDeg(lat); + + let lon = (D - (1 + 2 * T1 + C1) * D * D * D / 6 + (5 - 2 * C1 + 28 * T1 - 3 * C1 * C1 + 8 * eccPrimeSquared + 24 * T1 * T1) * D * D * D * D * D / 120) / Math.cos(phi1Rad); + lon = LongOrigin + radToDeg(lon); + + let result; + if (typeof utm.accuracy === 'number') { + const topRight = UTMtoLL({ + northing: utm.northing + utm.accuracy, + easting: utm.easting + utm.accuracy, + zoneLetter: utm.zoneLetter, + zoneNumber: utm.zoneNumber + }); + result = { + top: topRight.lat, + right: topRight.lon, + bottom: lat, + left: lon + }; + } + else { + result = { + lat, + lon + }; + } + return result; + } + + /** + * Calculates the MGRS letter designator for the given latitude. + * + * @private (Not intended for public API, only exported for testing.) + * @param {number} latitude The latitude in WGS84 to get the letter designator + * for. + * @return {string} The letter designator. + */ + function getLetterDesignator(latitude) { + if (latitude <= 84 && latitude >= 72) { + // the X band is 12 degrees high + return 'X'; + } else if (latitude < 72 && latitude >= -80) { + // Latitude bands are lettered C through X, excluding I and O + const bandLetters = 'CDEFGHJKLMNPQRSTUVWX'; + const bandHeight = 8; + const minLatitude = -80; + const index = Math.floor((latitude - minLatitude) / bandHeight); + return bandLetters[index]; + } else if (latitude > 84 || latitude < -80) { + //This is here as an error flag to show that the Latitude is + //outside MGRS limits + return 'Z'; + } } - if (colInt === O || (colOrigin < O && colInt > O) || ((colInt > O || colOrigin < O) && rollover)) { - colInt++; + /** + * Encodes a UTM location as MGRS string. + * + * @private + * @param {object} utm An object literal with easting, northing, + * zoneLetter, zoneNumber + * @param {number} accuracy Accuracy in digits (0-5). + * @return {string} MGRS string for the given UTM location. + */ + function encode(utm, accuracy) { + // prepend with leading zeroes + const seasting = '00000' + utm.easting, + snorthing = '00000' + utm.northing; + + return utm.zoneNumber + utm.zoneLetter + get100kID(utm.easting, utm.northing, utm.zoneNumber) + seasting.substr(seasting.length - 5, accuracy) + snorthing.substr(snorthing.length - 5, accuracy); + } + + /** + * Get the two letter 100k designator for a given UTM easting, + * northing and zone number value. + * + * @private + * @param {number} easting + * @param {number} northing + * @param {number} zoneNumber + * @return {string} the two letter 100k designator for the given UTM location. + */ + function get100kID(easting, northing, zoneNumber) { + const setParm = get100kSetForZone(zoneNumber); + const setColumn = Math.floor(easting / 100000); + const setRow = Math.floor(northing / 100000) % 20; + return getLetter100kID(setColumn, setRow, setParm); + } + + /** + * Given a UTM zone number, figure out the MGRS 100K set it is in. + * + * @private + * @param {number} i An UTM zone number. + * @return {number} the 100k set the UTM zone is in. + */ + function get100kSetForZone(i) { + let setParm = i % NUM_100K_SETS; + if (setParm === 0) { + setParm = NUM_100K_SETS; + } + + return setParm; + } + + /** + * Get the two-letter MGRS 100k designator given information + * translated from the UTM northing, easting and zone number. + * + * @private + * @param {number} column the column index as it relates to the MGRS + * 100k set spreadsheet, created from the UTM easting. + * Values are 1-8. + * @param {number} row the row index as it relates to the MGRS 100k set + * spreadsheet, created from the UTM northing value. Values + * are from 0-19. + * @param {number} parm the set block, as it relates to the MGRS 100k set + * spreadsheet, created from the UTM zone. Values are from + * 1-60. + * @return {string} two letter MGRS 100k code. + */ + function getLetter100kID(column, row, parm) { + // colOrigin and rowOrigin are the letters at the origin of the set + const index = parm - 1; + const colOrigin = SET_ORIGIN_COLUMN_LETTERS.charCodeAt(index); + const rowOrigin = SET_ORIGIN_ROW_LETTERS.charCodeAt(index); + + // colInt and rowInt are the letters to build to return + let colInt = colOrigin + column - 1; + let rowInt = rowOrigin + row; + let rollover = false; + + if (colInt > Z) { + colInt = colInt - Z + A - 1; + rollover = true; + } - if (colInt === I) { + if (colInt === I || (colOrigin < I && colInt > I) || ((colInt > I || colOrigin < I) && rollover)) { colInt++; } - } - if (colInt > Z) { - colInt = colInt - Z + A - 1; - } + if (colInt === O || (colOrigin < O && colInt > O) || ((colInt > O || colOrigin < O) && rollover)) { + colInt++; - if (rowInt > V) { - rowInt = rowInt - V + A - 1; - rollover = true; - } - else { - rollover = false; - } + if (colInt === I) { + colInt++; + } + } - if (((rowInt === I) || ((rowOrigin < I) && (rowInt > I))) || (((rowInt > I) || (rowOrigin < I)) && rollover)) { - rowInt++; - } + if (colInt > Z) { + colInt = colInt - Z + A - 1; + } - if (((rowInt === O) || ((rowOrigin < O) && (rowInt > O))) || (((rowInt > O) || (rowOrigin < O)) && rollover)) { - rowInt++; + if (rowInt > V) { + rowInt = rowInt - V + A - 1; + rollover = true; + } + else { + rollover = false; + } - if (rowInt === I) { + if (((rowInt === I) || ((rowOrigin < I) && (rowInt > I))) || (((rowInt > I) || (rowOrigin < I)) && rollover)) { rowInt++; } - } - if (rowInt > V) { - rowInt = rowInt - V + A - 1; - } + if (((rowInt === O) || ((rowOrigin < O) && (rowInt > O))) || (((rowInt > O) || (rowOrigin < O)) && rollover)) { + rowInt++; - var twoLetter = String.fromCharCode(colInt) + String.fromCharCode(rowInt); - return twoLetter; -} - -/** - * Decode the UTM parameters from a MGRS string. - * - * @private - * @param {string} mgrsString an UPPERCASE coordinate string is expected. - * @return {object} An object literal with easting, northing, zoneLetter, - * zoneNumber and accuracy (in meters) properties. - */ -function decode(mgrsString) { - - if (mgrsString && mgrsString.length === 0) { - throw ("MGRSPoint coverting from nothing"); + if (rowInt === I) { + rowInt++; + } + } + + if (rowInt > V) { + rowInt = rowInt - V + A - 1; + } + + const twoLetter = String.fromCharCode(colInt) + String.fromCharCode(rowInt); + return twoLetter; } - var length = mgrsString.length; + /** + * Decode the UTM parameters from a MGRS string. + * + * @private + * @param {string} mgrsString an UPPERCASE coordinate string is expected. + * @return {object} An object literal with easting, northing, zoneLetter, + * zoneNumber and accuracy (in meters) properties. + */ + function decode(mgrsString) { + + if (mgrsString && mgrsString.length === 0) { + throw new TypeError('MGRSPoint coverting from nothing'); + } + + //remove any spaces in MGRS String + mgrsString = mgrsString.replace(/ /g, ''); + + const { length } = mgrsString; - var hunK = null; - var sb = ""; - var testChar; - var i = 0; + let hunK = null; + let sb = ''; + let testChar; + let i = 0; - // get Zone number - while (!(/[A-Z]/).test(testChar = mgrsString.charAt(i))) { - if (i >= 2) { - throw ("MGRSPoint bad conversion from: " + mgrsString); + // get Zone number + while (!(/[A-Z]/).test(testChar = mgrsString.charAt(i))) { + if (i >= 2) { + throw new Error(`MGRSPoint bad conversion from: ${mgrsString}`); + } + sb += testChar; + i++; } - sb += testChar; - i++; - } - var zoneNumber = parseInt(sb, 10); + const zoneNumber = parseInt(sb, 10); - if (i === 0 || i + 3 > length) { - // A good MGRS string has to be 4-5 digits long, - // ##AAA/#AAA at least. - throw ("MGRSPoint bad conversion from: " + mgrsString); - } + if (i === 0 || i + 3 > length) { + // A good MGRS string has to be 4-5 digits long, + // ##AAA/#AAA at least. + throw new Error(`MGRSPoint bad conversion from ${mgrsString}`); + } - var zoneLetter = mgrsString.charAt(i++); + const zoneLetter = mgrsString.charAt(i++); - // Should we check the zone letter here? Why not. - if (zoneLetter <= 'A' || zoneLetter === 'B' || zoneLetter === 'Y' || zoneLetter >= 'Z' || zoneLetter === 'I' || zoneLetter === 'O') { - throw ("MGRSPoint zone letter " + zoneLetter + " not handled: " + mgrsString); - } + // Should we check the zone letter here? Why not. + if (zoneLetter <= 'A' || zoneLetter === 'B' || zoneLetter === 'Y' || zoneLetter >= 'Z' || zoneLetter === 'I' || zoneLetter === 'O') { + throw new Error(`MGRSPoint zone letter ${zoneLetter} not handled: ${mgrsString}`); + } - hunK = mgrsString.substring(i, i += 2); + hunK = mgrsString.substring(i, i += 2); - var set = get100kSetForZone(zoneNumber); + const set = get100kSetForZone(zoneNumber); - var east100k = getEastingFromChar(hunK.charAt(0), set); - var north100k = getNorthingFromChar(hunK.charAt(1), set); + const east100k = getEastingFromChar(hunK.charAt(0), set); + let north100k = getNorthingFromChar(hunK.charAt(1), set); - // We have a bug where the northing may be 2000000 too low. - // How - // do we know when to roll over? + // We have a bug where the northing may be 2000000 too low. + // How + // do we know when to roll over? - while (north100k < getMinNorthing(zoneLetter)) { - north100k += 2000000; - } + while (north100k < getMinNorthing(zoneLetter)) { + north100k += 2000000; + } - // calculate the char index for easting/northing separator - var remainder = length - i; + // calculate the char index for easting/northing separator + const remainder = length - i; - if (remainder % 2 !== 0) { - throw ("MGRSPoint has to have an even number \nof digits after the zone letter and two 100km letters - front \nhalf for easting meters, second half for \nnorthing meters" + mgrsString); - } + if (remainder % 2 !== 0) { + throw new Error(`MGRSPoint has to have an even number +of digits after the zone letter and two 100km letters - front +half for easting meters, second half for +northing meters ${mgrsString}`); + } + + const sep = remainder / 2; + + let sepEasting = 0; + let sepNorthing = 0; + let accuracyBonus, sepEastingString, sepNorthingString; + if (sep > 0) { + accuracyBonus = 100000 / Math.pow(10, sep); + sepEastingString = mgrsString.substring(i, i + sep); + sepEasting = parseFloat(sepEastingString) * accuracyBonus; + sepNorthingString = mgrsString.substring(i + sep); + sepNorthing = parseFloat(sepNorthingString) * accuracyBonus; + } - var sep = remainder / 2; - - var sepEasting = 0.0; - var sepNorthing = 0.0; - var accuracyBonus, sepEastingString, sepNorthingString, easting, northing; - if (sep > 0) { - accuracyBonus = 100000.0 / Math.pow(10, sep); - sepEastingString = mgrsString.substring(i, i + sep); - sepEasting = parseFloat(sepEastingString) * accuracyBonus; - sepNorthingString = mgrsString.substring(i + sep); - sepNorthing = parseFloat(sepNorthingString) * accuracyBonus; + const easting = sepEasting + east100k; + const northing = sepNorthing + north100k; + + return { + easting, + northing, + zoneLetter, + zoneNumber, + accuracy: accuracyBonus + }; } - easting = sepEasting + east100k; - northing = sepNorthing + north100k; - - return { - easting: easting, - northing: northing, - zoneLetter: zoneLetter, - zoneNumber: zoneNumber, - accuracy: accuracyBonus - }; -} - -/** - * Given the first letter from a two-letter MGRS 100k zone, and given the - * MGRS table set for the zone number, figure out the easting value that - * should be added to the other, secondary easting value. - * - * @private - * @param {char} e The first letter from a two-letter MGRS 100´k zone. - * @param {number} set The MGRS table set for the zone number. - * @return {number} The easting value for the given letter and set. - */ -function getEastingFromChar(e, set) { - // colOrigin is the letter at the origin of the set for the - // column - var curCol = SET_ORIGIN_COLUMN_LETTERS.charCodeAt(set - 1); - var eastingValue = 100000.0; - var rewindMarker = false; - - while (curCol !== e.charCodeAt(0)) { - curCol++; - if (curCol === I) { - curCol++; - } - if (curCol === O) { + /** + * Given the first letter from a two-letter MGRS 100k zone, and given the + * MGRS table set for the zone number, figure out the easting value that + * should be added to the other, secondary easting value. + * + * @private + * @param {string} e The first letter from a two-letter MGRS 100´k zone. + * @param {number} set The MGRS table set for the zone number. + * @return {number} The easting value for the given letter and set. + */ + function getEastingFromChar(e, set) { + // colOrigin is the letter at the origin of the set for the + // column + let curCol = SET_ORIGIN_COLUMN_LETTERS.charCodeAt(set - 1); + let eastingValue = 100000; + let rewindMarker = false; + + while (curCol !== e.charCodeAt(0)) { curCol++; - } - if (curCol > Z) { - if (rewindMarker) { - throw ("Bad character: " + e); + if (curCol === I) { + curCol++; + } + if (curCol === O) { + curCol++; + } + if (curCol > Z) { + if (rewindMarker) { + throw new Error(`Bad character: ${e}`); + } + curCol = A; + rewindMarker = true; } - curCol = A; - rewindMarker = true; + eastingValue += 100000; } - eastingValue += 100000.0; - } - return eastingValue; -} - -/** - * Given the second letter from a two-letter MGRS 100k zone, and given the - * MGRS table set for the zone number, figure out the northing value that - * should be added to the other, secondary northing value. You have to - * remember that Northings are determined from the equator, and the vertical - * cycle of letters mean a 2000000 additional northing meters. This happens - * approx. every 18 degrees of latitude. This method does *NOT* count any - * additional northings. You have to figure out how many 2000000 meters need - * to be added for the zone letter of the MGRS coordinate. - * - * @private - * @param {char} n Second letter of the MGRS 100k zone - * @param {number} set The MGRS table set number, which is dependent on the - * UTM zone number. - * @return {number} The northing value for the given letter and set. - */ -function getNorthingFromChar(n, set) { - - if (n > 'V') { - throw ("MGRSPoint given invalid Northing " + n); - } + return eastingValue; + } + + /** + * Given the second letter from a two-letter MGRS 100k zone, and given the + * MGRS table set for the zone number, figure out the northing value that + * should be added to the other, secondary northing value. You have to + * remember that Northings are determined from the equator, and the vertical + * cycle of letters mean a 2000000 additional northing meters. This happens + * approx. every 18 degrees of latitude. This method does *NOT* count any + * additional northings. You have to figure out how many 2000000 meters need + * to be added for the zone letter of the MGRS coordinate. + * + * @private + * @param {string} n Second letter of the MGRS 100k zone + * @param {number} set The MGRS table set number, which is dependent on the + * UTM zone number. + * @return {number} The northing value for the given letter and set. + */ + function getNorthingFromChar(n, set) { + + if (n > 'V') { + throw new TypeError(`MGRSPoint given invalid Northing ${n}`); + } - // rowOrigin is the letter at the origin of the set for the - // column - var curRow = SET_ORIGIN_ROW_LETTERS.charCodeAt(set - 1); - var northingValue = 0.0; - var rewindMarker = false; + // rowOrigin is the letter at the origin of the set for the + // column + let curRow = SET_ORIGIN_ROW_LETTERS.charCodeAt(set - 1); + let northingValue = 0; + let rewindMarker = false; - while (curRow !== n.charCodeAt(0)) { - curRow++; - if (curRow === I) { + while (curRow !== n.charCodeAt(0)) { curRow++; + if (curRow === I) { + curRow++; + } + if (curRow === O) { + curRow++; + } + // fixing a bug making whole application hang in this loop + // when 'n' is a wrong character + if (curRow > V) { + if (rewindMarker) { // making sure that this loop ends + throw new Error(`Bad character: ${n}`); + } + curRow = A; + rewindMarker = true; + } + northingValue += 100000; } - if (curRow === O) { - curRow++; + + return northingValue; + } + + /** + * The function getMinNorthing returns the minimum northing value of a MGRS + * zone. + * + * Ported from Geotrans' c Lattitude_Band_Value structure table. + * + * @private + * @param {string} zoneLetter The MGRS zone to get the min northing for. + * @return {number} + */ + function getMinNorthing(zoneLetter) { + let northing; + switch (zoneLetter) { + case 'C': + northing = 1100000; + break; + case 'D': + northing = 2000000; + break; + case 'E': + northing = 2800000; + break; + case 'F': + northing = 3700000; + break; + case 'G': + northing = 4600000; + break; + case 'H': + northing = 5500000; + break; + case 'J': + northing = 6400000; + break; + case 'K': + northing = 7300000; + break; + case 'L': + northing = 8200000; + break; + case 'M': + northing = 9100000; + break; + case 'N': + northing = 0; + break; + case 'P': + northing = 800000; + break; + case 'Q': + northing = 1700000; + break; + case 'R': + northing = 2600000; + break; + case 'S': + northing = 3500000; + break; + case 'T': + northing = 4400000; + break; + case 'U': + northing = 5300000; + break; + case 'V': + northing = 6200000; + break; + case 'W': + northing = 7000000; + break; + case 'X': + northing = 7900000; + break; + default: + northing = -1; } - // fixing a bug making whole application hang in this loop - // when 'n' is a wrong character - if (curRow > V) { - if (rewindMarker) { // making sure that this loop ends - throw ("Bad character: " + n); - } - curRow = A; - rewindMarker = true; + if (northing >= 0) { + return northing; + } + else { + throw new TypeError(`Invalid zone letter: ${zoneLetter}`); } - northingValue += 100000.0; - } - return northingValue; -} - -/** - * The function getMinNorthing returns the minimum northing value of a MGRS - * zone. - * - * Ported from Geotrans' c Lattitude_Band_Value structure table. - * - * @private - * @param {char} zoneLetter The MGRS zone to get the min northing for. - * @return {number} - */ -function getMinNorthing(zoneLetter) { - var northing; - switch (zoneLetter) { - case 'C': - northing = 1100000.0; - break; - case 'D': - northing = 2000000.0; - break; - case 'E': - northing = 2800000.0; - break; - case 'F': - northing = 3700000.0; - break; - case 'G': - northing = 4600000.0; - break; - case 'H': - northing = 5500000.0; - break; - case 'J': - northing = 6400000.0; - break; - case 'K': - northing = 7300000.0; - break; - case 'L': - northing = 8200000.0; - break; - case 'M': - northing = 9100000.0; - break; - case 'N': - northing = 0.0; - break; - case 'P': - northing = 800000.0; - break; - case 'Q': - northing = 1700000.0; - break; - case 'R': - northing = 2600000.0; - break; - case 'S': - northing = 3500000.0; - break; - case 'T': - northing = 4400000.0; - break; - case 'U': - northing = 5300000.0; - break; - case 'V': - northing = 6200000.0; - break; - case 'W': - northing = 7000000.0; - break; - case 'X': - northing = 7900000.0; - break; - default: - northing = -1.0; } - if (northing >= 0.0) { - return northing; - } - else { - throw ("Invalid zone letter: " + zoneLetter); - } - -} -exports['default'] = mgrs; -exports.forward = forward; -exports.inverse = inverse; -exports.toPoint = toPoint; + exports.forward = forward; + exports.getLetterDesignator = getLetterDesignator; + exports.inverse = inverse; + exports.toPoint = toPoint; -Object.defineProperty(exports, '__esModule', { value: true }); + Object.defineProperty(exports, '__esModule', { value: true }); -}))); +})); diff --git a/dist/mgrs.min.js b/dist/mgrs.min.js new file mode 100644 index 0000000..712635c --- /dev/null +++ b/dist/mgrs.min.js @@ -0,0 +1,2 @@ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e=e||self).mgrs={})}(this,(function(e){"use strict";const t=65,r=73,n=79;function o(e){return e*(Math.PI/180)}function a(e){return e/Math.PI*180}function i(e){const t=e.northing,r=e.easting,{zoneLetter:n,zoneNumber:o}=e;if(o<0||o>60)return null;const s=6378137,c=(1-Math.sqrt(.99330562))/(1+Math.sqrt(.99330562)),h=r-5e5;let f=t;n<"N"&&(f-=1e7);const l=6*(o-1)-180+3,u=f/.9996/6367449.145945056,d=u+(3*c/2-27*c*c*c/32)*Math.sin(2*u)+(21*c*c/16-55*c*c*c*c/32)*Math.sin(4*u)+151*c*c*c/96*Math.sin(6*u),b=s/Math.sqrt(1-.00669438*Math.sin(d)*Math.sin(d)),M=Math.tan(d)*Math.tan(d),g=.006739496752268451*Math.cos(d)*Math.cos(d),w=.99330562*s/Math.pow(1-.00669438*Math.sin(d)*Math.sin(d),1.5),p=h/(.9996*b);let y=d-b*Math.tan(d)/w*(p*p/2-(5+3*M+10*g-4*g*g-.06065547077041606)*p*p*p*p/24+(61+90*M+298*g+45*M*M-1.6983531815716497-3*g*g)*p*p*p*p*p*p/720);y=a(y);let m,A=(p-(1+2*M+g)*p*p*p/6+(5-2*g+28*M-3*g*g+.05391597401814761+24*M*M)*p*p*p*p*p/120)/Math.cos(d);if(A=l+a(A),"number"==typeof e.accuracy){const t=i({northing:e.northing+e.accuracy,easting:e.easting+e.accuracy,zoneLetter:e.zoneLetter,zoneNumber:e.zoneNumber});m={top:t.lat,right:t.lon,bottom:y,left:A}}else m={lat:y,lon:A};return m}function s(e){if(e<=84&&e>=72)return"X";if(e<72&&e>=-80){const t=8,r=-80;return"CDEFGHJKLMNPQRSTUVWX"[Math.floor((e-r)/t)]}return e>84||e<-80?"Z":void 0}function c(e){let t=e%6;return 0===t&&(t=6),t}function h(e){if(e&&0===e.length)throw new TypeError("MGRSPoint coverting from nothing");e=e.replace(/ /g,"");const{length:o}=e;let a,i=null,s="",h=0;for(;!/[A-Z]/.test(a=e.charAt(h));){if(h>=2)throw new Error("MGRSPoint bad conversion from: "+e);s+=a,h++}const l=parseInt(s,10);if(0===h||h+3>o)throw new Error("MGRSPoint bad conversion from "+e);const u=e.charAt(h++);if(u<="A"||"B"===u||"Y"===u||u>="Z"||"I"===u||"O"===u)throw new Error(`MGRSPoint zone letter ${u} not handled: ${e}`);i=e.substring(h,h+=2);const d=c(l),b=function(e,o){let a="AJSAJS".charCodeAt(o-1),i=1e5,s=!1;for(;a!==e.charCodeAt(0);){if(a++,a===r&&a++,a===n&&a++,a>90){if(s)throw new Error("Bad character: "+e);a=t,s=!0}i+=1e5}return i}(i.charAt(0),d);let M=function(e,o){if(e>"V")throw new TypeError("MGRSPoint given invalid Northing "+e);let a="AFAFAF".charCodeAt(o-1),i=0,s=!1;for(;a!==e.charCodeAt(0);){if(a++,a===r&&a++,a===n&&a++,a>86){if(s)throw new Error("Bad character: "+e);a=t,s=!0}i+=1e5}return i}(i.charAt(1),d);for(;M0&&(p=1e5/Math.pow(10,w),y=e.substring(h,h+w),A=parseFloat(y)*p,m=e.substring(h+w),k=parseFloat(m)*p);return{easting:A+b,northing:k+M,zoneLetter:u,zoneNumber:l,accuracy:p}}function f(e){let t;switch(e){case"C":t=11e5;break;case"D":t=2e6;break;case"E":t=28e5;break;case"F":t=37e5;break;case"G":t=46e5;break;case"H":t=55e5;break;case"J":t=64e5;break;case"K":t=73e5;break;case"L":t=82e5;break;case"M":t=91e5;break;case"N":t=0;break;case"P":t=8e5;break;case"Q":t=17e5;break;case"R":t=26e5;break;case"S":t=35e5;break;case"T":t=44e5;break;case"U":t=53e5;break;case"V":t=62e5;break;case"W":t=7e6;break;case"X":t=79e5;break;default:t=-1}if(t>=0)return t;throw new TypeError("Invalid zone letter: "+e)}e.forward=function(e,a){if(a="number"==typeof a?a:5,!Array.isArray(e))throw new TypeError("forward did not receive an array");if("string"==typeof e[0]||"string"==typeof e[1])throw new TypeError("forward received an array of strings, but it only accepts an array of numbers.");const[i,h]=e;if(i<-180||i>180)throw new TypeError("forward received an invalid longitude of "+i);if(h<-90||h>90)throw new TypeError("forward received an invalid latitude of "+h);if(h<-80||h>84)throw new TypeError(`forward received a latitude of ${h}, but this library does not support conversions of points in polar regions below 80°S and above 84°N`);return function(e,o){const a="00000"+e.easting,i="00000"+e.northing;return e.zoneNumber+e.zoneLetter+function(e,o,a){const i=c(a),s=Math.floor(e/1e5),h=Math.floor(o/1e5)%20;return function(e,o,a){const i=a-1,s="AJSAJS".charCodeAt(i),c="AFAFAF".charCodeAt(i);let h=s+e-1,f=c+o,l=!1;h>90&&(h=h-90+t-1,l=!0);(h===r||sr||(h>r||sn||(h>n||s90&&(h=h-90+t-1);f>86?(f=f-86+t-1,l=!0):l=!1;(f===r||cr||(f>r||cn||(f>n||c86&&(f=f-86+t-1);return String.fromCharCode(h)+String.fromCharCode(f)}(s,h,i)}(e.easting,e.northing,e.zoneNumber)+a.substr(a.length-5,o)+i.substr(i.length-5,o)}(function(e){const t=e.lat,r=e.lon,n=6378137,a=o(t),i=o(r);let c;c=Math.floor((r+180)/6)+1,180===r&&(c=60);t>=56&&t<64&&r>=3&&r<12&&(c=32);t>=72&&t<84&&(r>=0&&r<9?c=31:r>=9&&r<21?c=33:r>=21&&r<33?c=35:r>=33&&r<42&&(c=37));const h=o(6*(c-1)-180+3),f=n/Math.sqrt(1-.00669438*Math.sin(a)*Math.sin(a)),l=Math.tan(a)*Math.tan(a),u=.006739496752268451*Math.cos(a)*Math.cos(a),d=Math.cos(a)*(i-h),b=n*(.9983242984503243*a-.002514607064228144*Math.sin(2*a)+2639046602129982e-21*Math.sin(4*a)-3.418046101696858e-9*Math.sin(6*a)),M=.9996*f*(d+(1-l+u)*d*d*d/6+(5-18*l+l*l+72*u-.39089081163157013)*d*d*d*d*d/120)+5e5;let g=.9996*(b+f*Math.tan(a)*(d*d/2+(5-l+9*u+4*u*u)*d*d*d*d/24+(61-58*l+l*l+600*u-2.2240339282485886)*d*d*d*d*d*d/720));t<0&&(g+=1e7);return{northing:Math.trunc(g),easting:Math.trunc(M),zoneNumber:c,zoneLetter:s(t)}}({lat:h,lon:i}),a)},e.getLetterDesignator=s,e.inverse=function(e){const t=i(h(e.toUpperCase()));return t.lat&&t.lon?[t.lon,t.lat,t.lon,t.lat]:[t.left,t.bottom,t.right,t.top]},e.toPoint=function(e){if(""===e)throw new TypeError("toPoint received a blank string");const t=i(h(e.toUpperCase()));return t.lat&&t.lon?[t.lon,t.lat]:[(t.left+t.right)/2,(t.top+t.bottom)/2]},Object.defineProperty(e,"__esModule",{value:!0})})); +//# sourceMappingURL=mgrs.min.js.map diff --git a/dist/mgrs.min.js.map b/dist/mgrs.min.js.map new file mode 100644 index 0000000..d194a2a --- /dev/null +++ b/dist/mgrs.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"mgrs.min.js","sources":["../mgrs.js"],"sourcesContent":["/**\n * UTM zones are grouped, and assigned to one of a group of 6\n * sets.\n *\n * {int} @private\n */\nconst NUM_100K_SETS = 6;\n\n/**\n * The column letters (for easting) of the lower left value, per\n * set.\n *\n * {string} @private\n */\nconst SET_ORIGIN_COLUMN_LETTERS = 'AJSAJS';\n\n/**\n * The row letters (for northing) of the lower left value, per\n * set.\n *\n * {string} @private\n */\nconst SET_ORIGIN_ROW_LETTERS = 'AFAFAF';\n\nconst A = 65; // A\nconst I = 73; // I\nconst O = 79; // O\nconst V = 86; // V\nconst Z = 90; // Z\n\n/**\n * First eccentricity squared\n * {number} @private\n */\nconst ECC_SQUARED = 0.00669438;\n\n/**\n * Scale factor along the central meridian\n * {number} @private\n */\nconst SCALE_FACTOR = 0.9996;\n\n/**\n * Semimajor axis (half the width of the earth) in meters\n * {number} @private\n */\nconst SEMI_MAJOR_AXIS = 6378137;\n\n/**\n * The easting of the central meridian of each UTM zone\n * {number} @private\n */\nconst EASTING_OFFSET = 500000;\n\n/**\n * The northing of the equator for southern hemisphere locations (in UTM)\n * {number} @private\n */\nconst NORTHING_OFFFSET = 10000000;\n\n/**\n * UTM zone width in degrees\n * {number} private\n */\nconst UTM_ZONE_WIDTH = 6;\n\n/**\n * Half the width of a UTM zone in degrees\n * {number} private\n */\nconst HALF_UTM_ZONE_WIDTH = UTM_ZONE_WIDTH / 2;\n\n/**\n * Convert lat/lon to MGRS.\n *\n * @param {[number, number]} ll Array with longitude and latitude on a\n * WGS84 ellipsoid.\n * @param {number} [accuracy=5] Accuracy in digits (5 for 1 m, 4 for 10 m, 3 for\n * 100 m, 2 for 1 km, 1 for 10 km or 0 for 100 km). Optional, default is 5.\n * @return {string} the MGRS string for the given location and accuracy.\n */\nexport function forward(ll, accuracy) {\n accuracy = typeof accuracy === 'number' ? accuracy : 5; // default accuracy 1m\n\n if (!Array.isArray(ll)) {\n throw new TypeError('forward did not receive an array');\n }\n\n if (typeof ll[0] === 'string' || typeof ll[1] === 'string') {\n throw new TypeError('forward received an array of strings, but it only accepts an array of numbers.');\n }\n\n const [ lon, lat ] = ll;\n if (lon < -180 || lon > 180) {\n throw new TypeError(`forward received an invalid longitude of ${lon}`);\n }\n if (lat < -90 || lat > 90) {\n throw new TypeError(`forward received an invalid latitude of ${lat}`);\n }\n\n if (lat < -80 || lat > 84) {\n throw new TypeError(`forward received a latitude of ${lat}, but this library does not support conversions of points in polar regions below 80°S and above 84°N`);\n }\n\n return encode(LLtoUTM({ lat, lon }), accuracy);\n}\n\n/**\n * Convert MGRS to lat/lon bounding box.\n *\n * @param {string} mgrs MGRS string.\n * @return {[number,number,number,number]} An array with left (longitude),\n * bottom (latitude), right\n * (longitude) and top (latitude) values in WGS84, representing the\n * bounding box for the provided MGRS reference.\n */\nexport function inverse(mgrs) {\n const bbox = UTMtoLL(decode(mgrs.toUpperCase()));\n if (bbox.lat && bbox.lon) {\n return [bbox.lon, bbox.lat, bbox.lon, bbox.lat];\n }\n return [bbox.left, bbox.bottom, bbox.right, bbox.top];\n}\n\nexport function toPoint(mgrs) {\n if (mgrs === '') {\n throw new TypeError('toPoint received a blank string');\n }\n const bbox = UTMtoLL(decode(mgrs.toUpperCase()));\n if (bbox.lat && bbox.lon) {\n return [bbox.lon, bbox.lat];\n }\n return [(bbox.left + bbox.right) / 2, (bbox.top + bbox.bottom) / 2];\n}\n\n/**\n * Conversion from degrees to radians.\n *\n * @private\n * @param {number} deg the angle in degrees.\n * @return {number} the angle in radians.\n */\nfunction degToRad(deg) {\n return (deg * (Math.PI / 180));\n}\n\n/**\n * Conversion from radians to degrees.\n *\n * @private\n * @param {number} rad the angle in radians.\n * @return {number} the angle in degrees.\n */\nfunction radToDeg(rad) {\n return (180 * (rad / Math.PI));\n}\n\n/**\n * Converts a set of Longitude and Latitude co-ordinates to UTM\n * using the WGS84 ellipsoid.\n *\n * @private\n * @param {object} ll Object literal with lat and lon properties\n * representing the WGS84 coordinate to be converted.\n * @return {object} Object literal containing the UTM value with easting,\n * northing, zoneNumber and zoneLetter properties, and an optional\n * accuracy property in digits. Returns null if the conversion failed.\n */\nfunction LLtoUTM(ll) {\n const Lat = ll.lat;\n const Long = ll.lon;\n const a = SEMI_MAJOR_AXIS;\n const LatRad = degToRad(Lat);\n const LongRad = degToRad(Long);\n let ZoneNumber;\n // (int)\n ZoneNumber = Math.floor((Long + 180) / 6) + 1;\n\n //Make sure the longitude 180 is in Zone 60\n if (Long === 180) {\n ZoneNumber = 60;\n }\n\n // Special zone for Norway\n if (Lat >= 56 && Lat < 64 && Long >= 3 && Long < 12) {\n ZoneNumber = 32;\n }\n\n // Special zones for Svalbard\n if (Lat >= 72 && Lat < 84) {\n if (Long >= 0 && Long < 9) {\n ZoneNumber = 31;\n }\n else if (Long >= 9 && Long < 21) {\n ZoneNumber = 33;\n }\n else if (Long >= 21 && Long < 33) {\n ZoneNumber = 35;\n }\n else if (Long >= 33 && Long < 42) {\n ZoneNumber = 37;\n }\n }\n\n // +HALF_UTM_ZONE_WIDTH puts origin in middle of zone\n const LongOrigin = (ZoneNumber - 1) * UTM_ZONE_WIDTH - 180 + HALF_UTM_ZONE_WIDTH;\n\n const LongOriginRad = degToRad(LongOrigin);\n\n const eccPrimeSquared = (ECC_SQUARED) / (1 - ECC_SQUARED);\n\n const N = a / Math.sqrt(1 - ECC_SQUARED * Math.sin(LatRad) * Math.sin(LatRad));\n const T = Math.tan(LatRad) * Math.tan(LatRad);\n const C = eccPrimeSquared * Math.cos(LatRad) * Math.cos(LatRad);\n const A = Math.cos(LatRad) * (LongRad - LongOriginRad);\n\n const M = a * ((1 - ECC_SQUARED / 4 - 3 * ECC_SQUARED * ECC_SQUARED / 64 - 5 * ECC_SQUARED * ECC_SQUARED * ECC_SQUARED / 256) * LatRad - (3 * ECC_SQUARED / 8 + 3 * ECC_SQUARED * ECC_SQUARED / 32 + 45 * ECC_SQUARED * ECC_SQUARED * ECC_SQUARED / 1024) * Math.sin(2 * LatRad) + (15 * ECC_SQUARED * ECC_SQUARED / 256 + 45 * ECC_SQUARED * ECC_SQUARED * ECC_SQUARED / 1024) * Math.sin(4 * LatRad) - (35 * ECC_SQUARED * ECC_SQUARED * ECC_SQUARED / 3072) * Math.sin(6 * LatRad));\n\n const UTMEasting = (SCALE_FACTOR * N * (A + (1 - T + C) * A * A * A / 6 + (5 - 18 * T + T * T + 72 * C - 58 * eccPrimeSquared) * A * A * A * A * A / 120) + EASTING_OFFSET);\n\n let UTMNorthing = (SCALE_FACTOR * (M + N * Math.tan(LatRad) * (A * A / 2 + (5 - T + 9 * C + 4 * C * C) * A * A * A * A / 24 + (61 - 58 * T + T * T + 600 * C - 330 * eccPrimeSquared) * A * A * A * A * A * A / 720)));\n if (Lat < 0) {\n UTMNorthing += NORTHING_OFFFSET;\n }\n\n return {\n northing: Math.trunc(UTMNorthing),\n easting: Math.trunc(UTMEasting),\n zoneNumber: ZoneNumber,\n zoneLetter: getLetterDesignator(Lat)\n };\n}\n\n/**\n * Converts UTM coords to lat/long, using the WGS84 ellipsoid. This is a convenience\n * class where the Zone can be specified as a single string eg.\"60N\" which\n * is then broken down into the ZoneNumber and ZoneLetter.\n *\n * @private\n * @param {object} utm An object literal with northing, easting, zoneNumber\n * and zoneLetter properties. If an optional accuracy property is\n * provided (in meters), a bounding box will be returned instead of\n * latitude and longitude.\n * @return {object} An object literal containing either lat and lon values\n * (if no accuracy was provided), or top, right, bottom and left values\n * for the bounding box calculated according to the provided accuracy.\n * Returns null if the conversion failed.\n */\nfunction UTMtoLL(utm) {\n\n const UTMNorthing = utm.northing;\n const UTMEasting = utm.easting;\n const { zoneLetter, zoneNumber } = utm;\n // check the ZoneNummber is valid\n if (zoneNumber < 0 || zoneNumber > 60) {\n return null;\n }\n\n const a = SEMI_MAJOR_AXIS;\n const e1 = (1 - Math.sqrt(1 - ECC_SQUARED)) / (1 + Math.sqrt(1 - ECC_SQUARED));\n\n // remove 500,000 meter offset for longitude\n const x = UTMEasting - EASTING_OFFSET;\n let y = UTMNorthing;\n\n // We must know somehow if we are in the Northern or Southern\n // hemisphere, this is the only time we use the letter So even\n // if the Zone letter isn't exactly correct it should indicate\n // the hemisphere correctly\n if (zoneLetter < 'N') {\n y -= NORTHING_OFFFSET; // remove offset used for southern hemisphere\n }\n\n // +HALF_UTM_ZONE_WIDTH puts origin in middle of zone\n const LongOrigin = (zoneNumber - 1) * UTM_ZONE_WIDTH - 180 + HALF_UTM_ZONE_WIDTH;\n\n const eccPrimeSquared = (ECC_SQUARED) / (1 - ECC_SQUARED);\n\n const M = y / SCALE_FACTOR;\n const mu = M / (a * (1 - ECC_SQUARED / 4 - 3 * ECC_SQUARED * ECC_SQUARED / 64 - 5 * ECC_SQUARED * ECC_SQUARED * ECC_SQUARED / 256));\n\n const phi1Rad = mu + (3 * e1 / 2 - 27 * e1 * e1 * e1 / 32) * Math.sin(2 * mu) + (21 * e1 * e1 / 16 - 55 * e1 * e1 * e1 * e1 / 32) * Math.sin(4 * mu) + (151 * e1 * e1 * e1 / 96) * Math.sin(6 * mu);\n // double phi1 = ProjMath.radToDeg(phi1Rad);\n\n const N1 = a / Math.sqrt(1 - ECC_SQUARED * Math.sin(phi1Rad) * Math.sin(phi1Rad));\n const T1 = Math.tan(phi1Rad) * Math.tan(phi1Rad);\n const C1 = eccPrimeSquared * Math.cos(phi1Rad) * Math.cos(phi1Rad);\n const R1 = a * (1 - ECC_SQUARED) / Math.pow(1 - ECC_SQUARED * Math.sin(phi1Rad) * Math.sin(phi1Rad), 1.5);\n const D = x / (N1 * SCALE_FACTOR);\n\n let lat = phi1Rad - (N1 * Math.tan(phi1Rad) / R1) * (D * D / 2 - (5 + 3 * T1 + 10 * C1 - 4 * C1 * C1 - 9 * eccPrimeSquared) * D * D * D * D / 24 + (61 + 90 * T1 + 298 * C1 + 45 * T1 * T1 - 252 * eccPrimeSquared - 3 * C1 * C1) * D * D * D * D * D * D / 720);\n lat = radToDeg(lat);\n\n let lon = (D - (1 + 2 * T1 + C1) * D * D * D / 6 + (5 - 2 * C1 + 28 * T1 - 3 * C1 * C1 + 8 * eccPrimeSquared + 24 * T1 * T1) * D * D * D * D * D / 120) / Math.cos(phi1Rad);\n lon = LongOrigin + radToDeg(lon);\n\n let result;\n if (typeof utm.accuracy === 'number') {\n const topRight = UTMtoLL({\n northing: utm.northing + utm.accuracy,\n easting: utm.easting + utm.accuracy,\n zoneLetter: utm.zoneLetter,\n zoneNumber: utm.zoneNumber\n });\n result = {\n top: topRight.lat,\n right: topRight.lon,\n bottom: lat,\n left: lon\n };\n }\n else {\n result = {\n lat,\n lon\n };\n }\n return result;\n}\n\n/**\n * Calculates the MGRS letter designator for the given latitude.\n *\n * @private (Not intended for public API, only exported for testing.)\n * @param {number} latitude The latitude in WGS84 to get the letter designator\n * for.\n * @return {string} The letter designator.\n */\nexport function getLetterDesignator(latitude) {\n if (latitude <= 84 && latitude >= 72) {\n // the X band is 12 degrees high\n return 'X';\n } else if (latitude < 72 && latitude >= -80) {\n // Latitude bands are lettered C through X, excluding I and O\n const bandLetters = 'CDEFGHJKLMNPQRSTUVWX';\n const bandHeight = 8;\n const minLatitude = -80;\n const index = Math.floor((latitude - minLatitude) / bandHeight);\n return bandLetters[index];\n } else if (latitude > 84 || latitude < -80) {\n //This is here as an error flag to show that the Latitude is\n //outside MGRS limits\n return 'Z';\n }\n}\n\n/**\n * Encodes a UTM location as MGRS string.\n *\n * @private\n * @param {object} utm An object literal with easting, northing,\n * zoneLetter, zoneNumber\n * @param {number} accuracy Accuracy in digits (0-5).\n * @return {string} MGRS string for the given UTM location.\n */\nfunction encode(utm, accuracy) {\n // prepend with leading zeroes\n const seasting = '00000' + utm.easting,\n snorthing = '00000' + utm.northing;\n\n return utm.zoneNumber + utm.zoneLetter + get100kID(utm.easting, utm.northing, utm.zoneNumber) + seasting.substr(seasting.length - 5, accuracy) + snorthing.substr(snorthing.length - 5, accuracy);\n}\n\n/**\n * Get the two letter 100k designator for a given UTM easting,\n * northing and zone number value.\n *\n * @private\n * @param {number} easting\n * @param {number} northing\n * @param {number} zoneNumber\n * @return {string} the two letter 100k designator for the given UTM location.\n */\nfunction get100kID(easting, northing, zoneNumber) {\n const setParm = get100kSetForZone(zoneNumber);\n const setColumn = Math.floor(easting / 100000);\n const setRow = Math.floor(northing / 100000) % 20;\n return getLetter100kID(setColumn, setRow, setParm);\n}\n\n/**\n * Given a UTM zone number, figure out the MGRS 100K set it is in.\n *\n * @private\n * @param {number} i An UTM zone number.\n * @return {number} the 100k set the UTM zone is in.\n */\nfunction get100kSetForZone(i) {\n let setParm = i % NUM_100K_SETS;\n if (setParm === 0) {\n setParm = NUM_100K_SETS;\n }\n\n return setParm;\n}\n\n/**\n * Get the two-letter MGRS 100k designator given information\n * translated from the UTM northing, easting and zone number.\n *\n * @private\n * @param {number} column the column index as it relates to the MGRS\n * 100k set spreadsheet, created from the UTM easting.\n * Values are 1-8.\n * @param {number} row the row index as it relates to the MGRS 100k set\n * spreadsheet, created from the UTM northing value. Values\n * are from 0-19.\n * @param {number} parm the set block, as it relates to the MGRS 100k set\n * spreadsheet, created from the UTM zone. Values are from\n * 1-60.\n * @return {string} two letter MGRS 100k code.\n */\nfunction getLetter100kID(column, row, parm) {\n // colOrigin and rowOrigin are the letters at the origin of the set\n const index = parm - 1;\n const colOrigin = SET_ORIGIN_COLUMN_LETTERS.charCodeAt(index);\n const rowOrigin = SET_ORIGIN_ROW_LETTERS.charCodeAt(index);\n\n // colInt and rowInt are the letters to build to return\n let colInt = colOrigin + column - 1;\n let rowInt = rowOrigin + row;\n let rollover = false;\n\n if (colInt > Z) {\n colInt = colInt - Z + A - 1;\n rollover = true;\n }\n\n if (colInt === I || (colOrigin < I && colInt > I) || ((colInt > I || colOrigin < I) && rollover)) {\n colInt++;\n }\n\n if (colInt === O || (colOrigin < O && colInt > O) || ((colInt > O || colOrigin < O) && rollover)) {\n colInt++;\n\n if (colInt === I) {\n colInt++;\n }\n }\n\n if (colInt > Z) {\n colInt = colInt - Z + A - 1;\n }\n\n if (rowInt > V) {\n rowInt = rowInt - V + A - 1;\n rollover = true;\n }\n else {\n rollover = false;\n }\n\n if (((rowInt === I) || ((rowOrigin < I) && (rowInt > I))) || (((rowInt > I) || (rowOrigin < I)) && rollover)) {\n rowInt++;\n }\n\n if (((rowInt === O) || ((rowOrigin < O) && (rowInt > O))) || (((rowInt > O) || (rowOrigin < O)) && rollover)) {\n rowInt++;\n\n if (rowInt === I) {\n rowInt++;\n }\n }\n\n if (rowInt > V) {\n rowInt = rowInt - V + A - 1;\n }\n\n const twoLetter = String.fromCharCode(colInt) + String.fromCharCode(rowInt);\n return twoLetter;\n}\n\n/**\n * Decode the UTM parameters from a MGRS string.\n *\n * @private\n * @param {string} mgrsString an UPPERCASE coordinate string is expected.\n * @return {object} An object literal with easting, northing, zoneLetter,\n * zoneNumber and accuracy (in meters) properties.\n */\nfunction decode(mgrsString) {\n\n if (mgrsString && mgrsString.length === 0) {\n throw new TypeError('MGRSPoint coverting from nothing');\n }\n\n //remove any spaces in MGRS String\n mgrsString = mgrsString.replace(/ /g, '');\n\n const { length } = mgrsString;\n\n let hunK = null;\n let sb = '';\n let testChar;\n let i = 0;\n\n // get Zone number\n while (!(/[A-Z]/).test(testChar = mgrsString.charAt(i))) {\n if (i >= 2) {\n throw new Error(`MGRSPoint bad conversion from: ${mgrsString}`);\n }\n sb += testChar;\n i++;\n }\n\n const zoneNumber = parseInt(sb, 10);\n\n if (i === 0 || i + 3 > length) {\n // A good MGRS string has to be 4-5 digits long,\n // ##AAA/#AAA at least.\n throw new Error(`MGRSPoint bad conversion from ${mgrsString}`);\n }\n\n const zoneLetter = mgrsString.charAt(i++);\n\n // Should we check the zone letter here? Why not.\n if (zoneLetter <= 'A' || zoneLetter === 'B' || zoneLetter === 'Y' || zoneLetter >= 'Z' || zoneLetter === 'I' || zoneLetter === 'O') {\n throw new Error(`MGRSPoint zone letter ${zoneLetter} not handled: ${mgrsString}`);\n }\n\n hunK = mgrsString.substring(i, i += 2);\n\n const set = get100kSetForZone(zoneNumber);\n\n const east100k = getEastingFromChar(hunK.charAt(0), set);\n let north100k = getNorthingFromChar(hunK.charAt(1), set);\n\n // We have a bug where the northing may be 2000000 too low.\n // How\n // do we know when to roll over?\n\n while (north100k < getMinNorthing(zoneLetter)) {\n north100k += 2000000;\n }\n\n // calculate the char index for easting/northing separator\n const remainder = length - i;\n\n if (remainder % 2 !== 0) {\n throw new Error(`MGRSPoint has to have an even number\nof digits after the zone letter and two 100km letters - front\nhalf for easting meters, second half for\nnorthing meters ${mgrsString}`);\n }\n\n const sep = remainder / 2;\n\n let sepEasting = 0;\n let sepNorthing = 0;\n let accuracyBonus, sepEastingString, sepNorthingString;\n if (sep > 0) {\n accuracyBonus = 100000 / Math.pow(10, sep);\n sepEastingString = mgrsString.substring(i, i + sep);\n sepEasting = parseFloat(sepEastingString) * accuracyBonus;\n sepNorthingString = mgrsString.substring(i + sep);\n sepNorthing = parseFloat(sepNorthingString) * accuracyBonus;\n }\n\n const easting = sepEasting + east100k;\n const northing = sepNorthing + north100k;\n\n return {\n easting,\n northing,\n zoneLetter,\n zoneNumber,\n accuracy: accuracyBonus\n };\n}\n\n/**\n * Given the first letter from a two-letter MGRS 100k zone, and given the\n * MGRS table set for the zone number, figure out the easting value that\n * should be added to the other, secondary easting value.\n *\n * @private\n * @param {string} e The first letter from a two-letter MGRS 100´k zone.\n * @param {number} set The MGRS table set for the zone number.\n * @return {number} The easting value for the given letter and set.\n */\nfunction getEastingFromChar(e, set) {\n // colOrigin is the letter at the origin of the set for the\n // column\n let curCol = SET_ORIGIN_COLUMN_LETTERS.charCodeAt(set - 1);\n let eastingValue = 100000;\n let rewindMarker = false;\n\n while (curCol !== e.charCodeAt(0)) {\n curCol++;\n if (curCol === I) {\n curCol++;\n }\n if (curCol === O) {\n curCol++;\n }\n if (curCol > Z) {\n if (rewindMarker) {\n throw new Error(`Bad character: ${e}`);\n }\n curCol = A;\n rewindMarker = true;\n }\n eastingValue += 100000;\n }\n\n return eastingValue;\n}\n\n/**\n * Given the second letter from a two-letter MGRS 100k zone, and given the\n * MGRS table set for the zone number, figure out the northing value that\n * should be added to the other, secondary northing value. You have to\n * remember that Northings are determined from the equator, and the vertical\n * cycle of letters mean a 2000000 additional northing meters. This happens\n * approx. every 18 degrees of latitude. This method does *NOT* count any\n * additional northings. You have to figure out how many 2000000 meters need\n * to be added for the zone letter of the MGRS coordinate.\n *\n * @private\n * @param {string} n Second letter of the MGRS 100k zone\n * @param {number} set The MGRS table set number, which is dependent on the\n * UTM zone number.\n * @return {number} The northing value for the given letter and set.\n */\nfunction getNorthingFromChar(n, set) {\n\n if (n > 'V') {\n throw new TypeError(`MGRSPoint given invalid Northing ${n}`);\n }\n\n // rowOrigin is the letter at the origin of the set for the\n // column\n let curRow = SET_ORIGIN_ROW_LETTERS.charCodeAt(set - 1);\n let northingValue = 0;\n let rewindMarker = false;\n\n while (curRow !== n.charCodeAt(0)) {\n curRow++;\n if (curRow === I) {\n curRow++;\n }\n if (curRow === O) {\n curRow++;\n }\n // fixing a bug making whole application hang in this loop\n // when 'n' is a wrong character\n if (curRow > V) {\n if (rewindMarker) { // making sure that this loop ends\n throw new Error(`Bad character: ${n}`);\n }\n curRow = A;\n rewindMarker = true;\n }\n northingValue += 100000;\n }\n\n return northingValue;\n}\n\n/**\n * The function getMinNorthing returns the minimum northing value of a MGRS\n * zone.\n *\n * Ported from Geotrans' c Lattitude_Band_Value structure table.\n *\n * @private\n * @param {string} zoneLetter The MGRS zone to get the min northing for.\n * @return {number}\n */\nfunction getMinNorthing(zoneLetter) {\n let northing;\n switch (zoneLetter) {\n case 'C':\n northing = 1100000;\n break;\n case 'D':\n northing = 2000000;\n break;\n case 'E':\n northing = 2800000;\n break;\n case 'F':\n northing = 3700000;\n break;\n case 'G':\n northing = 4600000;\n break;\n case 'H':\n northing = 5500000;\n break;\n case 'J':\n northing = 6400000;\n break;\n case 'K':\n northing = 7300000;\n break;\n case 'L':\n northing = 8200000;\n break;\n case 'M':\n northing = 9100000;\n break;\n case 'N':\n northing = 0;\n break;\n case 'P':\n northing = 800000;\n break;\n case 'Q':\n northing = 1700000;\n break;\n case 'R':\n northing = 2600000;\n break;\n case 'S':\n northing = 3500000;\n break;\n case 'T':\n northing = 4400000;\n break;\n case 'U':\n northing = 5300000;\n break;\n case 'V':\n northing = 6200000;\n break;\n case 'W':\n northing = 7000000;\n break;\n case 'X':\n northing = 7900000;\n break;\n default:\n northing = -1;\n }\n if (northing >= 0) {\n return northing;\n }\n else {\n throw new TypeError(`Invalid zone letter: ${zoneLetter}`);\n }\n\n}\n"],"names":["A","I","O","degToRad","deg","Math","PI","radToDeg","rad","UTMtoLL","utm","UTMNorthing","northing","UTMEasting","easting","zoneLetter","zoneNumber","a","e1","sqrt","x","y","LongOrigin","UTM_ZONE_WIDTH","mu","phi1Rad","sin","N1","T1","tan","C1","cos","R1","pow","D","lat","result","lon","accuracy","topRight","top","right","bottom","left","getLetterDesignator","latitude","bandHeight","minLatitude","floor","get100kSetForZone","i","setParm","decode","mgrsString","length","TypeError","replace","testChar","hunK","sb","test","charAt","Error","parseInt","substring","set","east100k","e","curCol","charCodeAt","eastingValue","rewindMarker","getEastingFromChar","north100k","n","curRow","northingValue","getNorthingFromChar","getMinNorthing","remainder","sep","accuracyBonus","sepEastingString","sepNorthingString","sepEasting","sepNorthing","parseFloat","ll","Array","isArray","seasting","snorthing","setColumn","setRow","column","row","parm","index","colOrigin","rowOrigin","colInt","rowInt","rollover","String","fromCharCode","getLetter100kID","get100kID","substr","encode","Lat","Long","LatRad","LongRad","ZoneNumber","LongOriginRad","N","T","C","M","trunc","LLtoUTM","mgrs","bbox","toUpperCase"],"mappings":"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"} \ No newline at end of file diff --git a/package.json b/package.json index 522e111..4375dc6 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,15 @@ "main": "dist/mgrs.min.js", "module": "dist/mgrs.esm.js", "types": "index.d.ts", + "files": [ + "mgrs.js", + "index.d.ts", + "dist/mgrs.esm.js", + "dist/mgrs.esm.js.map", + "dist/mgrs.js", + "dist/mgrs.min.js", + "dist/mgrs.min.js.map" + ], "scripts": { "lint": "eslint mgrs.js && eslint test", "pretest": "npm run clean && npm run build",