This is an automated email from the git hooks/post-receive script. sebastic-guest pushed a commit to branch master in repository mgrs.
commit 016e336b4c3720e01b4c73a931fd0e3f1bc9af32 Author: Bas Couwenberg <sebas...@xs4all.nl> Date: Sat Jan 3 00:17:55 2015 +0100 Imported Upstream version 0.0~20131209-80d5465 --- .gitignore | 5 + license.md | 19 ++ mgrs.js | 735 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ openmap.md | 145 ++++++++++++ package.json | 30 +++ readme.md | 44 ++++ test/test.js | 31 +++ 7 files changed, 1009 insertions(+) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0df0b9d --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +*~ +node_modules +.DS_STORE +coverage +dist \ No newline at end of file diff --git a/license.md b/license.md new file mode 100644 index 0000000..f999ce2 --- /dev/null +++ b/license.md @@ -0,0 +1,19 @@ +Copyright (c) 2012, Mike Adair, Richard Greenwood, Didier Richard, Stephen Irons, Olivier Terral, Calvin Metcalf + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + _THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE._ \ No newline at end of file diff --git a/mgrs.js b/mgrs.js new file mode 100644 index 0000000..3e5f8d8 --- /dev/null +++ b/mgrs.js @@ -0,0 +1,735 @@ + + + +/** + * 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 + +/** + * 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, 4 for 1000 m or 5 for 10000 m). Optional, default is 5. + * @return {string} the MGRS string for the given location and accuracy. + */ +exports.forward = function(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. + */ +exports.inverse = function(mgrs) { + var bbox = UTMtoLL(decode(mgrs.toUpperCase())); + return [bbox.left, bbox.bottom, bbox.right, bbox.top]; +}; + +exports.toPoint = function(mgrsStr) { + var llbbox = exports.inverse(mgrsStr); + return [(llbbox[2] + llbbox[0]) / 2, (llbbox[3] + llbbox[1]) / 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; + } + + // Special zone for Norway + if (Lat >= 56.0 && Lat < 64.0 && Long >= 3.0 && Long < 12.0) { + ZoneNumber = 32; + } + + // Special zones for Svalbard + if (Lat >= 72.0 && Lat < 84.0) { + if (Long >= 0.0 && Long < 9.0) { + ZoneNumber = 31; + } + else if (Long >= 9.0 && Long < 21.0) { + ZoneNumber = 33; + } + else if (Long >= 21.0 && Long < 33.0) { + ZoneNumber = 35; + } + else if (Long >= 33.0 && Long < 42.0) { + ZoneNumber = 37; + } + } + + LongOrigin = (ZoneNumber - 1) * 6 - 180 + 3; //+3 puts origin + // in middle of + // zone + LongOriginRad = degToRad(LongOrigin); + + eccPrimeSquared = (eccSquared) / (1 - eccSquared); + + 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); + + 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)); + + 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); + + 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 + } + + return { + northing: Math.round(UTMNorthing), + easting: Math.round(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; + } + + 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 + } + + // 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 + }; + } + 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) { + var seasting = "" + utm.easting, + snorthing = "" + 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 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 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; + } + + if (colInt === I || (colOrigin < I && colInt > I) || ((colInt > I || colOrigin < I) && rollover)) { + colInt++; + } + + if (colInt === O || (colOrigin < O && colInt > O) || ((colInt > O || colOrigin < O) && rollover)) { + colInt++; + + if (colInt === I) { + colInt++; + } + } + + if (colInt > Z) { + colInt = colInt - Z + A - 1; + } + + if (rowInt > V) { + rowInt = rowInt - V + A - 1; + rollover = true; + } + else { + rollover = false; + } + + if (((rowInt === I) || ((rowOrigin < I) && (rowInt > I))) || (((rowInt > I) || (rowOrigin < I)) && rollover)) { + rowInt++; + } + + if (((rowInt === O) || ((rowOrigin < O) && (rowInt > O))) || (((rowInt > O) || (rowOrigin < O)) && rollover)) { + rowInt++; + + if (rowInt === I) { + rowInt++; + } + } + + if (rowInt > V) { + rowInt = rowInt - V + A - 1; + } + + 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"); + } + + var length = mgrsString.length; + + var hunK = null; + var sb = ""; + var testChar; + var i = 0; + + // get Zone number + while (!(/[A-Z]/).test(testChar = mgrsString.charAt(i))) { + if (i >= 2) { + throw ("MGRSPoint bad conversion from: " + mgrsString); + } + sb += testChar; + i++; + } + + var 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); + } + + var 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); + } + + hunK = mgrsString.substring(i, i += 2); + + var set = get100kSetForZone(zoneNumber); + + var east100k = getEastingFromChar(hunK.charAt(0), set); + var 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? + + while (north100k < getMinNorthing(zoneLetter)) { + north100k += 2000000; + } + + // calculate the char index for easting/northing separator + var 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); + } + + 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; + } + + 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) { + curCol++; + } + if (curCol > Z) { + if (rewindMarker) { + throw ("Bad character: " + e); + } + curCol = A; + rewindMarker = true; + } + 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); + } + + // 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; + + 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 ("Bad character: " + n); + } + curRow = A; + rewindMarker = true; + } + 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); + } + +} diff --git a/openmap.md b/openmap.md new file mode 100644 index 0000000..cba0d76 --- /dev/null +++ b/openmap.md @@ -0,0 +1,145 @@ +OpenMap Software License Agreement +====== + +This Agreement sets forth the terms and conditions under which +the software known as OpenMap(tm) will be licensed by BBN +Technologies ("BBN") to you ("Licensee"), and by which Derivative +Works (as hereafter defined) of OpenMap will be licensed by you to BBN. + +Definitions: + +- "Derivative Work(s)" shall mean any revision, enhancement, + modification, translation, abridgement, condensation or + expansion created by Licensee or BBN that is based upon the + Software or a portion thereof that would be a copyright + infringement if prepared without the authorization of the + copyright owners of the Software or portion thereof. + +- "OpenMap" shall mean a programmer's toolkit for building map + based applications as originally created by BBN, and any + Derivative Works thereof as created by either BBN or Licensee, + but shall include only those Derivative Works BBN has approved + for inclusion into, and BBN has integrated into OpenMap. + +- "Standard Version" shall mean OpenMap, as originally created by + BBN. + +- "Software" shall mean OpenMap and the Derivative Works created + by Licensee and the collection of files distributed by the + Licensee with OpenMap, and the collection of files created + through textual modifications. + +- "Copyright Holder" is whoever is named in the copyright or + copyrights for the Derivative Works. + +- "Licensee" is you, only if you agree to be bound by the terms + and conditions set forth in this Agreement. + +- "Reasonable copying fee" is whatever you can justify on the + basis of media cost, duplication charges, time of people + involved. + +- "Freely Available" means that no fee is charged for the item + itself, though there may be fees involved in handling the item. + It also means that recipients of the item may redistribute it + under the same conditions that they received it. + +1. BBN maintains all rights, title and interest in and to +OpenMap, including all applicable copyrights, trade secrets, +patents and other intellectual rights therein. Licensee hereby +grants to BBN all right, title and interest into the compilation +of OpenMap. Licensee shall own all rights, title and interest +into the Derivative Works created by Licensee (subject to the +compilation ownership by BBN). + +2. BBN hereby grants to Licensee a royalty free, worldwide right +and license to use, copy, distribute and make Derivative Works of +OpenMap, and sublicensing rights of any of the foregoing in +accordance with the terms and conditions of this Agreement, +provided that you duplicate all of the original copyright notices +and associated disclaimers. + +3. Licensee hereby grants to BBN a royalty free, worldwide right +and license to use, copy, distribute and make Derivative Works of +Derivative Works created by Licensee and sublicensing rights of +any of the foregoing. + +4. Licensee's right to create Derivative Works in the Software is +subject to Licensee agreement to insert a prominent notice in +each changed file stating how and when you changed that file, and +provided that you do at least ONE of the following: + + - a) place your modifications in the Public Domain or otherwise + make them Freely Available, such as by posting said + modifications to Usenet or an equivalent medium, or + placing the modifications on a major archive site and by + providing your modifications to the Copyright Holder. + + - b) use the modified Package only within your corporation or + organization. + + - c) rename any non-standard executables so the names do not + conflict with standard executables, which must also be + provided, and provide a separate manual page for each + non-standard executable that clearly documents how it + differs from OpenMap. + + - d) make other distribution arrangements with the Copyright + Holder. +5. Licensee may distribute the programs of this Software in +object code or executable form, provided that you do at least ONE +of the following: + + - a) distribute an OpenMap version of the executables and + library files, together with instructions (in the manual + page or equivalent) on where to get OpenMap. + + - b) accompany the distribution with the machine-readable + source code with your modifications. + + - c) accompany any non-standard executables with their + corresponding OpenMap executables, giving the non-standard + executables non-standard names, and clearly documenting + the differences in manual pages (or equivalent), together + with instructions on where to get OpenMap. + + - d) make other distribution arrangements with the Copyright + Holder. +6. You may charge a reasonable copying fee for any distribution +of this Software. You may charge any fee you choose for support +of this Software. You may not charge a fee for this Software +itself. However, you may distribute this Software in aggregate +with other (possibly commercial) programs as part of a larger +(possibly commercial) software distribution provided that you do +not advertise this Software as a product of your own. + +7. The data and images supplied as input to or produced as output +from the Software do not automatically fall under the copyright +of this Software, but belong to whomever generated them, and may +be sold commercially, and may be aggregated with this Software. + +8. BBN makes no representation about the suitability of OpenMap +for any purposes. BBN shall have no duty or requirement to +include any Derivative Works into OpenMap. + +9. Each party hereto represents and warrants that they have the +full unrestricted right to grant all rights and licenses granted +to the other party herein. + +10. THIS PACKAGE IS PROVIDED "AS IS" WITHOUT WARRANTIES OF ANY +KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING (BUT NOT LIMITED TO) +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, AND +WITHOUT ANY WARRANTIES AS TO NONINFRINGEMENT. + +11. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, +SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES WHATSOEVER RESULTING +FROM LOSS OF USE OF DATA OR PROFITS, WHETHER IN AN ACTION OF +CONTRACT, NEGLIGENCE OR OTHER TORTIOUS CONDUCT, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS PACKAGE. + +12. Without limitation of the foregoing, You agree to commit no +act which, directly or indirectly, would violate any U.S. law, +regulation, or treaty, or any other international treaty or +agreement to which the United States adheres or with which the +United States complies, relating to the export or re-export of +any commodities, software, or technical data. \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..a966c4f --- /dev/null +++ b/package.json @@ -0,0 +1,30 @@ +{ + "name": "mgrs", + "version": "0.0.0", + "description": "Utility for converting between WGS84 lat/lng and MGRS coordinates", + "main": "mgrs.js", + "scripts": { + "test": "./node_modules/istanbul/lib/cli.js test ./node_modules/mocha/bin/_mocha test/test.js", + "build":"mkdir -p dist && browserify mgrs.js -s mgrs -o dist/mgrs.js" + }, + "repository": { + "type": "git", + "url": "git://github.com/proj4js/mgrs.git" + }, + "keywords": [ + "mgrs", + "proj4", + "gis" + ], + "author": "proj4 team", + "license": "MIT", + "bugs": { + "url": "https://github.com/proj4js/mgrs/issues" + }, + "devDependencies": { + "mocha": "~1.15.1", + "istanbul": "~0.1.46", + "browserify": "~2.36.1", + "chai": "~1.8.1" + } +} diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..f879495 --- /dev/null +++ b/readme.md @@ -0,0 +1,44 @@ +mgrs +==== + +Utility for converting between WGS84 lat/lng and MGRS coordinates, spunoff from [proj4js](https://github.com/proj4js/proj4js) + +has 3 methods + +- forward, takes an array of `[lon,lat]` and optional accuracy and returns an mgrs string +- inverse, takes an mgrs string and returns a bbox. +- toPoint, takes an mgrs string, returns an array of '[lon,lat]' + +install dev dependencies with + +```bash +npm install +``` + +test with + +```bash +npm test +``` + +test coverage with + +```bash +npm test --coverage +``` + +build with + +```bash +npm run build +``` + + +Lisensed under the MIT linsense except: + +Portions of this software are based on a port of components from the OpenMap +com.bbn.openmap.proj.coords Java package. An initial port was initially created +by Patrice G. Cappelaere and included in Community Mapbuilder +(http://svn.codehaus.org/mapbuilder/), which is licensed under the LGPL license +as per http://www.gnu.org/copyleft/lesser.html. OpenMap is licensed under the +[following license agreement](openmap.md): \ No newline at end of file diff --git a/test/test.js b/test/test.js new file mode 100644 index 0000000..acab8f2 --- /dev/null +++ b/test/test.js @@ -0,0 +1,31 @@ +var should = require('chai').should(); +var mgrs = require('../mgrs'); +describe('First MGRS set', function() { + var mgrsStr = "33UXP04"; + var point = mgrs.toPoint(mgrsStr); + it('Longitude of point from MGRS correct.', function() { + point[0].should.be.closeTo(16.41450, 0.000001); + }); + it('Latitude of point from MGRS correct.', function() { + point[1].should.be.closeTo(48.24949, 0.000001); + }); + it('MGRS reference with highest accuracy correct.', function() { + mgrs.forward(point).should.equal("33UXP0500444998"); + }); + it('MGRS reference with 1-digit accuracy correct.', function() { + mgrs.forward(point,1).should.equal(mgrsStr); + }); +}); +describe('Second MGRS set', function() { + var mgrsStr = "24XWT783908"; // near UTM zone border, so there are two ways to reference this + var point = mgrs.toPoint(mgrsStr); + it('Longitude of point from MGRS correct.', function() { + point[0].should.be.closeTo(-32.66433, 0.00001); + }); + it('Latitude of point from MGRS correct.', function() { + point[1].should.be.closeTo(83.62778, 0.00001); + }); + it('MGRS reference with 1-digit accuracy correct.', function() { + mgrs.forward(point,3).should.equal('25XEN041865'); + }); +}) \ No newline at end of file -- Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/mgrs.git _______________________________________________ Pkg-grass-devel mailing list Pkg-grass-devel@lists.alioth.debian.org http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-grass-devel