Commit 91672441 authored by Calvin Metcalf's avatar Calvin Metcalf
Browse files

MGRS done

parent 6191cf5d
Loading
Loading
Loading
Loading
+725 −740
Original line number Diff line number Diff line
/*jshint browser: true, node: true*/
/*
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
@@ -156,7 +157,9 @@ United States complies, relating to the export or re-export of
any commodities, software, or technical data.
*/

if (window.proj4 && !proj4.util) { proj4.util = {}; }
if (typeof proj4 !== 'undefined' && !proj4.util) {
  proj4.util = {};
}

/**
 * Converts between lat/lon and MGRS coordinates. Note that this static class
@@ -168,7 +171,7 @@ if (window.proj4 && !proj4.util) { proj4.util = {}; }
 *
 * @static
 */
(window.proj4 ? proj4.util : window)["MGRS"] = (function() {
(function() {

  /**
   * UTM zones are grouped, and assigned to one of a group of 6
@@ -211,7 +214,10 @@ if (window.proj4 && !proj4.util) { proj4.util = {}; }
   */
  function forward(ll, accuracy) {
    accuracy = accuracy || 5; // default accuracy 1m
		return encode(LLtoUTM({lat: ll.lat, lon: ll.lon}), accuracy);
    return encode(LLtoUTM({
      lat: ll.lat,
      lon: ll.lon
    }), accuracy);
  }

  /**
@@ -277,7 +283,7 @@ if (window.proj4 && !proj4.util) { proj4.util = {}; }
    ZoneNumber = Math.floor((Long + 180) / 6) + 1;

    //Make sure the longitude 180.00 is in Zone 60
        if (Long == 180) {
    if (Long === 180) {
      ZoneNumber = 60;
    }

@@ -288,15 +294,19 @@ if (window.proj4 && !proj4.util) { proj4.util = {}; }

    // Special zones for Svalbard
    if (Lat >= 72.0 && Lat < 84.0) {
            if (Long >= 0.0 && Long < 9.0)
      if (Long >= 0.0 && Long < 9.0){
        ZoneNumber = 31;
            else if (Long >= 9.0 && Long < 21.0)
      }
      else if (Long >= 9.0 && Long < 21.0){
        ZoneNumber = 33;
            else if (Long >= 21.0 && Long < 33.0)
      }
      else if (Long >= 21.0 && Long < 33.0){
        ZoneNumber = 35;
            else if (Long >= 33.0 && Long < 42.0)
      }
      else if (Long >= 33.0 && Long < 42.0){
        ZoneNumber = 37;
      }
    }

    LongOrigin = (ZoneNumber - 1) * 6 - 180 + 3; //+3 puts origin
    // in middle of
@@ -310,31 +320,11 @@ if (window.proj4 && !proj4.util) { proj4.util = {}; }
    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)));
    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
@@ -406,9 +396,7 @@ if (window.proj4 && !proj4.util) { proj4.util = {}; }
    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);
    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));
@@ -417,17 +405,10 @@ if (window.proj4 && !proj4.util) { proj4.util = {}; }
    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);
    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);
    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;
@@ -444,7 +425,8 @@ if (window.proj4 && !proj4.util) { proj4.util = {}; }
        bottom: lat,
        left: lon
      };
        } else {
    }
    else {
      result = {
        lat: lat,
        lon: lon
@@ -466,46 +448,47 @@ if (window.proj4 && !proj4.util) { proj4.util = {}; }
    //outside MGRS limits
    var LetterDesignator = 'Z';

        if ((84 >= lat) && (lat >= 72))
    if ((84 >= lat) && (lat >= 72)){
      LetterDesignator = 'X';
        else if ((72 > lat) && (lat >= 64))
    } else if ((72 > lat) && (lat >= 64)){
      LetterDesignator = 'W';
        else if ((64 > lat) && (lat >= 56))
    } else if ((64 > lat) && (lat >= 56)){
      LetterDesignator = 'V';
        else if ((56 > lat) && (lat >= 48))
    } else if ((56 > lat) && (lat >= 48)){
      LetterDesignator = 'U';
        else if ((48 > lat) && (lat >= 40))
    } else if ((48 > lat) && (lat >= 40)){
      LetterDesignator = 'T';
        else if ((40 > lat) && (lat >= 32))
    } else if ((40 > lat) && (lat >= 32)){
      LetterDesignator = 'S';
        else if ((32 > lat) && (lat >= 24))
    } else if ((32 > lat) && (lat >= 24)){
      LetterDesignator = 'R';
        else if ((24 > lat) && (lat >= 16))
    } else if ((24 > lat) && (lat >= 16)){
      LetterDesignator = 'Q';
        else if ((16 > lat) && (lat >= 8))
    } else if ((16 > lat) && (lat >= 8)){
      LetterDesignator = 'P';
        else if ((8 > lat) && (lat >= 0))
    } else if ((8 > lat) && (lat >= 0)){
      LetterDesignator = 'N';
        else if ((0 > lat) && (lat >= -8))
    } else if ((0 > lat) && (lat >= -8)){
      LetterDesignator = 'M';
        else if ((-8 > lat) && (lat >= -16))
    } else if ((-8 > lat) && (lat >= -16)){
      LetterDesignator = 'L';
        else if ((-16 > lat) && (lat >= -24))
    } else if ((-16 > lat) && (lat >= -24)){
      LetterDesignator = 'K';
        else if ((-24 > lat) && (lat >= -32))
    } else if ((-24 > lat) && (lat >= -32)){
      LetterDesignator = 'J';
        else if ((-32 > lat) && (lat >= -40))
    } else if ((-32 > lat) && (lat >= -40)){
      LetterDesignator = 'H';
        else if ((-40 > lat) && (lat >= -48))
    } else if ((-40 > lat) && (lat >= -48)){
      LetterDesignator = 'G';
        else if ((-48 > lat) && (lat >= -56))
    } else if ((-48 > lat) && (lat >= -56)){
      LetterDesignator = 'F';
        else if ((-56 > lat) && (lat >= -64))
    } else if ((-56 > lat) && (lat >= -64)){
      LetterDesignator = 'E';
        else if ((-64 > lat) && (lat >= -72))
    } else if ((-64 > lat) && (lat >= -72)){
      LetterDesignator = 'D';
        else if ((-72 > lat) && (lat >= -80))
    } else if ((-72 > lat) && (lat >= -80)){
      LetterDesignator = 'C';
    }
    return LetterDesignator;
  }

@@ -522,10 +505,7 @@ if (window.proj4 && !proj4.util) { proj4.util = {}; }
    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);
    return utm.zoneNumber + utm.zoneLetter + get100kID(utm.easting, utm.northing, utm.zoneNumber) + seasting.substr(seasting.length - 5, accuracy) + snorthing.substr(snorthing.length - 5, accuracy);
  }

  /**
@@ -554,8 +534,9 @@ if (window.proj4 && !proj4.util) { proj4.util = {}; }
   */
  function get100kSetForZone(i) {
    var setParm = i % NUM_100K_SETS;
        if (setParm == 0)
    if (setParm === 0){
      setParm = NUM_100K_SETS;
    }

    return setParm;
  }
@@ -592,16 +573,14 @@ if (window.proj4 && !proj4.util) { proj4.util = {}; }
      rollover = true;
    }

		if (colInt == I || (colOrigin < I && colInt > I)
                || ((colInt > I || colOrigin < I) && rollover)) {
    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)) {
    if (colInt === O || (colOrigin < O && colInt > O) || ((colInt > O || colOrigin < O) && rollover)) {
      colInt++;

            if (colInt == I) {
      if (colInt === I) {
        colInt++;
      }
    }
@@ -613,20 +592,19 @@ if (window.proj4 && !proj4.util) { proj4.util = {}; }
    if (rowInt > V) {
      rowInt = rowInt - V + A - 1;
      rollover = true;
        } else {
    }
    else {
      rollover = false;
    }

        if( ((rowInt == I) || ((rowOrigin < I) && (rowInt > I)))
                || (((rowInt > I)||(rowOrigin < I)) && rollover)) {
    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)) {
    if (((rowInt === O) || ((rowOrigin < O) && (rowInt > O))) || (((rowInt > O) || (rowOrigin < O)) && rollover)) {
      rowInt++;

            if (rowInt == I) {
      if (rowInt === I) {
        rowInt++;
      }
    }
@@ -649,7 +627,7 @@ if (window.proj4 && !proj4.util) { proj4.util = {}; }
   */
  function decode(mgrsString) {

        if (mgrsString == null || mgrsString.length == 0) {
    if (mgrsString && mgrsString.length === 0) {
      throw ("MGRSPoint coverting from nothing");
    }

@@ -663,8 +641,7 @@ if (window.proj4 && !proj4.util) { proj4.util = {}; }
    // get Zone number
    while (!(/[A-Z]/).test(testChar = mgrsString.charAt(i))) {
      if (i >= 2) {
                throw("MGRSPoint bad conversion from: "
                        + mgrsString);
        throw ("MGRSPoint bad conversion from: " + mgrsString);
      }
      sb += testChar;
      i++;
@@ -672,21 +649,17 @@ if (window.proj4 && !proj4.util) { proj4.util = {}; }

    var zoneNumber = parseInt(sb, 10);

        if (i == 0 || i + 3 > length) {
    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);
      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);
    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);
@@ -707,21 +680,20 @@ if (window.proj4 && !proj4.util) { proj4.util = {}; }
    // 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);
    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) {
            var accuracyBonus = 100000.0 / Math.pow(10, sep);
            var sepEastingString = mgrsString.substring(i, i + sep);
      accuracyBonus = 100000.0 / Math.pow(10, sep);
      sepEastingString = mgrsString.substring(i, i + sep);
      sepEasting = parseFloat(sepEastingString) * accuracyBonus;
            var sepNorthingString = mgrsString.substring(i + sep);
      sepNorthingString = mgrsString.substring(i + sep);
      sepNorthing = parseFloat(sepNorthingString) * accuracyBonus;
    }

@@ -754,12 +726,14 @@ if (window.proj4 && !proj4.util) { proj4.util = {}; }
    var eastingValue = 100000.0;
    var rewindMarker = false;

        while (curCol != e.charCodeAt(0)) {
    while (curCol !== e.charCodeAt(0)) {
      curCol++;
            if (curCol == I)
      if (curCol === I){
        curCol++;
            if (curCol == O)
      }
      if (curCol === O){
        curCol++;
      }
      if (curCol > Z) {
        if (rewindMarker) {
          throw ("Bad character: " + e);
@@ -792,8 +766,7 @@ if (window.proj4 && !proj4.util) { proj4.util = {}; }
  function getNorthingFromChar(n, set) {

    if (n > 'V') {
            throw("MGRSPoint given invalid Northing "
                    + n);
      throw ("MGRSPoint given invalid Northing " + n);
    }

    // rowOrigin is the letter at the origin of the set for the
@@ -802,12 +775,14 @@ if (window.proj4 && !proj4.util) { proj4.util = {}; }
    var northingValue = 0.0;
    var rewindMarker = false;

        while (curRow != n.charCodeAt(0)) {
    while (curRow !== n.charCodeAt(0)) {
      curRow++;
            if (curRow == I)
      if (curRow === I){
        curRow++;
            if (curRow == O)
      }
      if (curRow === O){
        curRow++;
      }
      // fixing a bug making whole application hang in this loop
      // when 'n' is a wrong character
      if (curRow > V) {
@@ -901,21 +876,30 @@ if (window.proj4 && !proj4.util) { proj4.util = {}; }
    }
    if (northing >= 0.0) {
      return northing;
        } else {
            throw("Invalid zone letter: "
                    + zoneLetter);
    }
    else {
      throw ("Invalid zone letter: " + zoneLetter);
    }

  }

    return {
  var MGRS = {
    forward: forward,
    inverse: inverse
  };
  if (typeof proj4 !== 'undefined') {
    proj4.util.MGRS = MGRS;
  }
  else if (typeof window !== 'undefined') {
    window.MGRS = MGRS;
  }
  else if (typeof module !== 'undefined') {
    module.exports = MGRS;
  }

})();

if (window.proj4 && proj4.Point) {
if (typeof proj4 !== 'undefined' && proj4.Point) {

  /**
   * Creates a proj4.Point instance from a MGRS reference. The point will
@@ -929,9 +913,7 @@ if (window.proj4 && proj4.Point) {
  proj4.Point.fromMGRS = function(mgrs) {
    var llbbox = proj4.util.MGRS.inverse(mgrs);
    return new proj4.Point(
            (llbbox[2] + llbbox[0]) / 2,
            (llbbox[3] + llbbox[1]) / 2
        );
    (llbbox[2] + llbbox[0]) / 2, (llbbox[3] + llbbox[1]) / 2);
  };

  /**
@@ -944,7 +926,10 @@ if (window.proj4 && proj4.Point) {
   *     for 1 m, 4 for 10 m, 3 for 100 m, 4 for 1000 m or 5 for 10000 m) 
   */
  proj4.Point.prototype.toMGRS = function(accuracy) {
        return proj4.util.MGRS.forward({lon: this.x, lat: this.y}, accuracy);
    return proj4.util.MGRS.forward({
      lon: this.x,
      lat: this.y
    }, accuracy);
  };

}
 No newline at end of file