var deg2rad = Math.PI / 180;
var rad2deg = 180.0 / Math.PI;
var pi = Math.PI;
var locres = 6; //locator characters
domain = 'globetrotter.net';
user = 'leware';
var testno = 0;

var bulkErrors = 0;

var  coordd;
var  coordm;
var  coords;
var  coordh;

var  preciseEasting = 0.0;
var  preciseNorthing = 0.0;


function SetLatLong(lat,lon) {
  document.MTShopCheckoutForm.elements['aInput[gps_dec_lat]'].value = lat;
  document.MTShopCheckoutForm.elements['aInput[gps_dec_lon]'].value = lon;
  if (ESONOPreviewOnly) {
    ESONOPreviewOnly = false;
  } else {
    ESONOPreviewOnly = false;
    $('#gpscalculator').toggle();
    //utmReset();
  }
}

function utmMtmSelected()
{
   document.myform3.north.value = " ";
   document.myform3.east.value = " ";
   document.myform3.zone.value = " ";
   document.myform3.zletter.selectedIndex = 0;
   //document.myform3.zletter.value = ' ';
   document.myform3.mtmRefMeridian.value = "";
}

function utmReset()
{
  document.myform3.reset();
  document.myform3.ellipsoid.selectedIndex = 22;
  document.myform3.mtmRefMeridian.value = "";
  testno = 0;
}

function northAmerica()
{
  document.myform3.latb.selectedIndex = 1;
  document.myform3.lonb.selectedIndex = 1;
  document.myform3.zletter.value = 'T';
  // document.myform3.zone.value = 18;
}


//-------------------------------------------------------------------
//function adapted from NSRUG  (caution: longitudes are +ve here)
function gsrugZoner(mtmLat, mtmLong, mtmZone)
{
   // Adapted from FORTRAN: SUBROUTINE ZONER(SAT,SLG,mtmZone)
   // Downloaded via below URL for Online Geodetic Tools:
   //    http://www.geod.rncan.gc.ca/tools-outils/index_e.php
   //    http://www.geod.rncan.gc.ca/tools-outils/tools_info_e.php?apps=gsrug
   // Here: C:/Docume~1/pilewis/Desktop/Lew/GPS72/GSRUG/GSRUG.FOR

   // Includes the official NSRUG Jan2008 fixes (see emails from Pat Legree)

   var mtmDegs =   // bounds for MTM zones 14 to 32
      [85.5,  88.5,  91.5,
       94.5,  97.5,  100.5,
       103.5, 106.5, 109.5,
       112.5, 115.5, 118.5,
       121.5, 124.5, 127.5,
       130.5, 133.5, 136.5,
       139.5, 142.5];

   var mtmSmers =  // MTM zone to reference meridian
      [0., 53., 56.,
                      58.5, 61.5, 64.5, 67.5, 70.5, 73.5,
       76.5, 79.5, 82.5,
                          81., 84., 87., 90., 93., 96., 99.,
       102., 105., 108., 111., 114., 117., 120., 123., 126.,
       129., 132., 135., 138., 141.];  // last was 142 ?!! I think it should be 141.

   // ? matches http://www.posc.org/Epicentre.2_2/DataModel/LogicalDictionary/StandardValues/coordinate_transformation.html

   if (mtmZone == 0)  // determine zone from lat/lon
   {
      if (mtmLong > 51.5 && mtmLong <= 54.5) mtmZone=1;

      if (mtmLong > 54.5 && mtmLong <= 57.5) mtmZone=2;

      if (mtmLat <= 46.5 && mtmLong <= 59.5 && mtmLong > 57.5 ||
          mtmLat > 46.5 && mtmLong <= 60. && mtmLong > 57.5) mtmZone=3;

      if (mtmLat < 46.5 && mtmLong <= 63. && mtmLong > 59.5 ||
          mtmLat >= 46.5 && mtmLong <= 63. && mtmLong > 60.) mtmZone=4;

      if (mtmLong > 63. && mtmLong <= 66.5 && mtmLat <= 44.75 ||
          mtmLong > 63. && mtmLat > 44.75 && mtmLong <= 66.) mtmZone=5;

      if (mtmLong > 66. && mtmLat > 44.75 && mtmLong <= 69. ||
          mtmLong > 66.5 && mtmLat <= 44.75 && mtmLong <= 69.) mtmZone=6;

      if (mtmLong > 69. && mtmLong <= 72.) mtmZone=7;

      if (mtmLong > 72. && mtmLong <= 75.) mtmZone=8;

      if (mtmLong > 75. && mtmLong <= 78.) mtmZone=9;

      if (mtmLat >  47. && mtmLong > 78. && mtmLong <= 79.5 ||
          mtmLat <= 47. && mtmLat  > 46. && mtmLong > 78. && mtmLong <= 80.25 ||
          mtmLat <= 46. && mtmLong > 78. && mtmLong <= 81.) mtmZone=10;

      if (mtmLong > 81. && mtmLong <= 84. && mtmLat <= 46.) mtmZone=11;

      if (mtmLong > 79.5  && mtmLong <= 82.5 && mtmLat > 47. ||
          mtmLong > 80.25 && mtmLong <= 82.5 && mtmLat <= 47. && mtmLat > 46.) mtmZone= 12;

      // if (mtmLong > 82.5 && mtmLong <= 85.5 && mtmLat > 46. ||
      //     mtmLong > 84. && mtmLong <= 85.5 && mtmLat <= 46.) mtmZone=13;

      if (mtmLong > 82.5 && mtmLong <= 85.5 && mtmLat > 46.) mtmZone=13;

      if (mtmZone == 0) // still not found, try regular Western Canada
      {
         for (var z = 0; z <= 18; ++z)
         {
            if (mtmLong > mtmDegs[z] && mtmLong <= mtmDegs[z+1])
            {
               mtmZone = z+14;
               break;
            }
         }
      }
   }

   if (mtmZone < 1 || mtmZone > 32)
   {
      alert("Cannot figure out MTM zone -- outside Canada, lat=" + mtmLat + ", lon=" + mtmLong);
      var mtmZoner = {zone: 0 , refMeridian: -mtmLong};  // return something not totally insane
      return mtmZoner;
   }
   else
   {
      var mtmZoner = {zone: mtmZone , refMeridian: -mtmSmers[mtmZone]};
      return mtmZoner;
   }
}


//-------------------------------------------------------------------
//functions for myform3

//===================================================================
function parseCoordinate(coordinate,type,format,spaced)
{
  coordh = 0;
  if (coordinate.search(/(^ *-|[WOS])/i) >= 0) { coordh = -1; }
  if (coordinate.search(/(^ *\+|[NE])/i) >= 0)  { coordh = 1; }

  // if (coordinate.search(/[EW]/i) >= 0 && !type) { type = 'lon'; }
  // if (coordinate.search(/[NS]/i) >= 0 && !type) { type = 'lat'; }

  coordinate = coordinate.replace(/,/g, '.');  // french commas
  // not sure really needed.
  coordinate = coordinate.replace(/[NESWO+\-]/gi,' ');  // add also: °, ', "  --  or replace everything that is not a number or a dot

  // alert("coordinate = " + coordinate);
  if (coordinate.search(/[0-9]/i) < 0)
  {
     alert("Can't parse input field: " + coordinate);
     coordd = "";
     return;
  }
  // http://www.gpsvisualizer.com/calculators
  // http://www.javascriptkit.com/javatutors/redev2.shtml
  var parts = coordinate.match(/([0-9\.\-]+)[^0-9\.]*([0-9\.]+)?[^0-9\.]*([0-9\.]+)?/);

  //                           /                          (one or more)             /
  //                            ([0-9\.\-]+)              digits, dot or -, one set
  //                                        [^0-9\.]*            separator
  //                                                 ([0-9\.]+)?       digits, dot, zero or one set
  //                                                            [^0-9\.]*     separator
  //                                                                     ([0-9\.]+)?  digits, dot, zero or one set

  // *: 0|more   +: 1|more   ?: 0|1        http://www.javascriptkit.com/javatutors/redev2.shtml

  if (!parts[1])
  {
     alert("Can't parse input field: " + coordinate);
     coordd = "";
     return;
  }
  else
  {
     coordd = parts[1];
     if (parts[2]) {coordm = parts[2];} else {coordm = 0;}
     if (parts[3]) {coords = parts[3];} else {coords = 0;}
     // n = parseFloat(parts[1]);
     // if (parts[2]) { n = n + parseFloat(parts[2])/60; }
     // if (parts[3]) { n = n + parseFloat(parts[3])/3600; }
  }
}
//===================================================================
function geo_constants(ellipsoid, xtm)
{
  // returns ellipsoid values
  ellipsoid_axis = new Array();
  ellipsoid_eccen = new Array();
  ellipsoid_axis[0] = 6377563.396; ellipsoid_eccen[0] = 0.00667054;  //airy
  ellipsoid_axis[1] = 6377340.189; ellipsoid_eccen[1] = 0.00667054;  // mod airy
  ellipsoid_axis[2] = 6378160; ellipsoid_eccen[2] = 0.006694542;  //aust national
  ellipsoid_axis[3] = 6377397.155; ellipsoid_eccen[3] = 0.006674372;  //bessel 1841
  ellipsoid_axis[4] = 6378206.4; ellipsoid_eccen[4] = 0.006768658;  //clarke 1866 == NAD 27 (TBC)
  ellipsoid_axis[5] = 6378249.145; ellipsoid_eccen[5] = 0.006803511;  //clarke 1880
  ellipsoid_axis[6] = 6377276.345; ellipsoid_eccen[6] = 0.00637847;  //everest
  ellipsoid_axis[7] = 6377304.063; ellipsoid_eccen[7] = 0.006637847;  // mod everest
  ellipsoid_axis[8] = 6378166; ellipsoid_eccen[8] = 0.006693422;  //fischer 1960
  ellipsoid_axis[9] = 6378150; ellipsoid_eccen[9] = 0.006693422;  //fischer 1968
  ellipsoid_axis[10] = 6378155; ellipsoid_eccen[10] = 0.006693422;  // mod fischer
  ellipsoid_axis[11] = 6378160; ellipsoid_eccen[11] = 0.006694605;  //grs 1967
  ellipsoid_axis[12] = 6378137; ellipsoid_eccen[12] = 0.00669438;  //  grs 1980
  ellipsoid_axis[13] = 6378200; ellipsoid_eccen[13] = 0.006693422;  // helmert 1906
  ellipsoid_axis[14] = 6378270; ellipsoid_eccen[14] = 0.006693422;  // hough
  ellipsoid_axis[15] = 6378388; ellipsoid_eccen[15] = 0.00672267;  // int24
  ellipsoid_axis[16] = 6378245; ellipsoid_eccen[16] = 0.006693422;  // krassovsky
  ellipsoid_axis[17] = 6378160; ellipsoid_eccen[17] = 0.006694542;  // s america
  ellipsoid_axis[18] = 6378165; ellipsoid_eccen[18] = 0.006693422;  // wgs-60
  ellipsoid_axis[19] = 6378145; ellipsoid_eccen[19] = 0.006694542;  // wgs-66
  ellipsoid_axis[20] = 6378135; ellipsoid_eccen[20] = 0.006694318;  // wgs-72
  ellipsoid_axis[21] = 6378137; ellipsoid_eccen[21] = 0.00669438;  //wgs-84

  if (ellipsoid == 0)
      ellipsoid = 22;

  --ellipsoid; // table indexed differently

  if (xtm == 1) // WAS: if (ellipsoid > 22)
  {
     scaleTm = 0.9999;
     eastingOrg = 304800.;
  }
  else
  {
     scaleTm = 0.9996;
     eastingOrg = 500000.;
  }

  // return values as an object
  var ellipsoid = { axis: ellipsoid_axis[ellipsoid],
                    eccentricity: ellipsoid_eccen[ellipsoid],
                    eastingOrg: eastingOrg,
                    scaleTm: scaleTm
                    };
  return ellipsoid;
}

function sanitize_refMeridian()
{
   // var rm = document.myform3.mtmRefMeridian.value;
   var rm = document.myform3.mtmRefMeridian.value.replace(/^\s+|\s+$/g, '');
                                    // return str.replace(/^\s\s*/, '').replace(/\s\s*$/, '');

   if (rm == "")
      return 0.0;

   if (isNaN(rm))
   {
      alert("MTM ref meridian must be a number between -51 and -143, or totally blank\nIgnoring MTM ref meridian");
      return 0.0;
   }

   rm = Number(rm);

   if (rm > 0.0)  // fix sign if needed
   {
      rm = 0-rm;
   }

   if (rm > (-51) || rm < (-143))
   {
      alert("MTM ref meridian must be a number between -51 and -143, or totally blank\nIgnoring MTM ref meridian");
      return 0.0;
   }

   document.myform3.mtmRefMeridian.value = rm;

   return rm;
}

//===================================================================
function val_ll3()
{
  // alert("TMP val_ll3()");
  // get ellipsoid
  var d = document.myform3.ellipsoid.selectedIndex;
  var xtm = (document.myform3.utmmtm[1].checked) ? 1 : 0;
  var gW = 0;
  var ellipsoid = geo_constants(d, xtm);

  if (ellipsoid.axis == 0)
    {
    alert("Ellipsoid must be entered");
    return;
    }
  var axis = ellipsoid.axis;
  var eccent = ellipsoid.eccentricity;
  var scaleTm = ellipsoid.scaleTm;
  var eastingOrg = ellipsoid.eastingOrg;

  parseCoordinate(document.myform3.latdms.value);
  if (coordh != 0)
  {
     if (coordh > 0)
       document.myform3.latb.selectedIndex = 1;
     else
       document.myform3.latb.selectedIndex = 2;
  }

  var latd = coordd;
  var latm = coordm;
  var lats = coords;
  var latb = document.myform3.latb.selectedIndex;

  parseCoordinate(document.myform3.londms.value);
  if (coordh != 0)
  {
     if (coordh > 0)
       document.myform3.lonb.selectedIndex = 2;
     else
       document.myform3.lonb.selectedIndex = 1;
  }

  var lond = coordd;
  var lonm = coordm;
  var lons = coords;
  var lonb = document.myform3.lonb.selectedIndex;
  //locres = document.myform3.locc.selectedIndex;

  // cope with blank fields
  if (latd == "" || lond == "")
  {
    alert("Latitude and longitude degrees must be entered");
    return;
  }

  // defaults to NorthAmerica
  if (latb == 0)
    latb = "1";
  // if (lond == "")
  //   lond = "0";
  if (lonb == 0)
    lonb = 1;

  //validate
  //validate
  var valid = validate_dms(latd, latm, lats, latb, lonm, lond, lons, lonb);
  if (valid == 0)
  {
    alert("Invalid degrees, minutes or seconds");
    return;
  }

  // clear form and show entered values
  var saveMrm = document.myform3.mtmRefMeridian.value;
  document.myform3.reset();
  document.myform3.mtmRefMeridian.value = saveMrm;
  document.myform3.ellipsoid.selectedIndex = d;
  if (xtm)
     document.myform3.utmmtm[1].checked = true;
  // done below
  // document.myform3.latdms.value = latd + " " + latm + " " + lats;
  // document.myform3.londms.value = lond + " " + lonm + " " + lons;
  document.myform3.latb.selectedIndex = latb;  // default N
  document.myform3.lonb.selectedIndex = lonb;  // default W
  //document.myform3.locc.selectedIndex = locres;

  var lat = Number(latd);
  lat = lat + Number(latm) / 60;
  lat = lat + Number(lats) / 3600;
  if (latb == 2)  // S
    lat = lat * -1;
  var lon = Number(lond);
  lon = lon + Number(lonm) / 60;
  lon = lon + Number(lons) / 3600;
  if (lonb == 1)  // W
    lon = lon * -1;

  todms3(lat, lon);

  if (lat >= 84 || lat <= -80)
    {
    alert("UTM latitudes should be between 84N and 80S\nCalculation will proceed anyway as locator will be valid.");
    }

  calc_utm(lat, lon, axis, eccent, scaleTm, eastingOrg);
  SetLatLong(lat,lon);
  //loc = calcloc(lon, lat)
  //var locy = loc.substring(0, 6 + 2 * locres);
  //document.myform3.locator.value = locy;

  return eccent;
}

//===================================================================
function calc_utm(lat, lon, axis, eccent, scaleTm, eastingOrg)
{
  var mrm = sanitize_refMeridian();
  // alert("TMP calc_utm()");
  var k0 = scaleTm;
  var latrad = lat * deg2rad;
  var longrad = lon * deg2rad;
  var zonenum = floor((lon + 180) / 6) + 1;
  // @dc (180 - (-70.5))/3 - 76
  if (scaleTm == 0.9999)        // all these were originally (eastingOrg == 304800.)
  {
      // zonenum = floor((180 - lon) / 3) - 76;  // MTM, only in Quebec
      // if (zonenum < 3 || zonenum > 10)
      //     alert("MTM zone numbers only confirmed for 3-10, province of Quebec\nContinuing anyway");
      if (mrm == 0)
      {
         zonerResult = gsrugZoner(lat, -lon, 0);
         zonenum = zonerResult.zone;
      }
      else
         zonenum = "x";
  }

  if (lat >= 56.0 && lat < 64.0 && lon >= 3.0 && lon < 12.0 )
    zonenum = 32;
  // Special zones for Svalbard
  if( lat >= 72.0 && lat < 84.0 )
    {
    if (lon >= 0.0  && lon <  9.0 ) zonenum = 31;
    else if ( lon >= 9.0  && lon < 21.0 ) zonenum = 33;
    else if ( lon >= 21.0 && lon < 33.0 ) zonenum = 35;
    else if ( lon >= 33.0 && lon < 42.0 ) zonenum = 37;
   }

  var lonorig = (zonenum - 1) * 6 - 180 + 3;  //+3 puts origin in middle of zone
  // @dc 180 - (7+76) * 3 - 1.5
  if (scaleTm == 0.9999)
  {
      // lonorig = 180 - (zonenum + 76) * 3 - 1.5;
      if (mrm == 0)
      {
         zonerResult = gsrugZoner(lat, -lon, zonenum);
         lonorig = zonerResult.refMeridian;
      }
      else
      {
         lonorig = mrm;
         if (abs(lon - lonorig) > 4.)
            alert("MTM ref meridian more than 4 degrees away from longitude\nContinuing anyway");
      }
  }
  var lonorigrad = lonorig * deg2rad;

  //get letter
  var letter = get_zoneletter(lat);

  var eccPrimeSquared = (eccent) / (1 - eccent);

  //calculate
  var N = axis / sqrt(1 - eccent * sin(latrad) * sin(latrad));
  var T = tan(latrad) * tan(latrad);
  var C = eccPrimeSquared * cos(latrad) * cos(latrad);
  var A = cos(latrad) * (longrad - lonorigrad);
  var M = axis * ((1 - eccent / 4 - 3 * eccent * eccent / 64 - 5 * eccent * eccent * eccent / 256) * latrad - (3 * eccent / 8 + 3 * eccent * eccent / 32 + 45 * eccent * eccent *eccent / 1024) * sin(2 * latrad) + (15 * eccent * eccent / 256 + 45 * eccent * eccent * eccent / 1024) * sin(4 * latrad) - (35 * eccent * eccent * eccent / 3072) * sin(6 * latrad));

  var easting = (k0 * N * (A + (1 - T + C) * A * A * A / 6 + (5 - 18 * T + T * T + 72 * C - 58 * eccPrimeSquared) * A * A * A * A * A / 120) + eastingOrg);
  var northing = (k0 * (M + N * 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)
    northing += 10000000.0; //10000000 meter offset for southern hemisphere

  // round up
  // alert("easting = " + easting);
  // preciseEasting = easting;
  easting = floor(easting + .5);
  // alert("easting = " + easting);
  // alert("northing = " + northing);
  // preciseNorthing = northing;
  northing = floor(northing + .5);
  // alert("northing = " + northing);

  // correlate index with letter
  var cx ="C01D02E03F04G05H06J07K08L09M10N11P12Q13R14S15T16U17V18W19X20";
  var cxi = cx.indexOf(letter,0);
  var zl = Number(cx.substr(cxi + 1, 2));

  document.myform3.north.value = northing;
  document.myform3.east.value = easting;
  document.myform3.zone.value = zonenum;
  document.myform3.zletter.selectedIndex = zl;

  var tlatdm = Math.abs(lat) + 0.5 / 60000;  // round up 0.0005 minutes (1/1000th)
  var tlondm = Math.abs(lon) + 0.5 / 60000;

  var minlatdm = floor((tlatdm - floor(tlatdm)) * 60 * 1000) / 1000;

  var minlondm = floor((tlondm - floor(tlondm)) * 60 * 1000) / 1000;

}

//===================================================================

//===================================================================
function val_utm()
{
  // alert("TMP val_utm()");
  var mrm = sanitize_refMeridian();
  var zone = document.myform3.zone.value;
  var northing = document.myform3.north.value;
  var easting = document.myform3.east.value;
  var d = document.myform3.ellipsoid.selectedIndex;
  var xtm = (document.myform3.utmmtm[1].checked) ? 1 : 0;
  var gW = 0;
  var zl = document.myform3.zletter.selectedIndex;
  //locres = document.myform3.locc.selectedIndex;

  if (zone == 0 || zone > 60)
    {
    alert("Zone number is out of range.\nMust be between 1 and 60.");
    ++bulkErrors;
    return;
    }
  if (isNaN(northing))
    {
    alert("Northing should be numbers only,\nno letters or spaces.");
    ++bulkErrors;
    return;
    }
  if (isNaN(easting))
    {
    alert("Easting should be numbers only,\nno letters or spaces.");
    ++bulkErrors;
    return;
    }
  if (northing < 0 || northing > 10000000)
    {
    alert("Northing value is out of range");
    ++bulkErrors;
    return;
    }
  if (mrm == 0 && (easting < 160000 || easting > 834000) )
    {
    alert("Easting value is out of range");
    ++bulkErrors;
    return;
    }
  ellipsoid = geo_constants(22, xtm);
  if (zone == "" && mrm == 0 || (zl == 0 && ellipsoid.eastingOrg != 304800.) )  // MTM does not need zone letters
    {
    alert("You must enter a zone number and letter");
    ++bulkErrors;
    return;
    }
  if (ellipsoid.axis == 0)
    {
    alert("Ellipsoid must be entered");
    ++bulkErrors;
    return;
    }
  if (mrm == 0 && ellipsoid.scaleTm == 0.9999 && (zone < 1 || zone > 32))
      alert("MTM zone numbers only confirmed for 1-32, in Canada\nContinuing anyway");

  var saveMrm = document.myform3.mtmRefMeridian.value;
  document.myform3.reset();  //clear form and show entered values
  document.myform3.mtmRefMeridian.value = saveMrm;
  document.myform3.zone.value = zone;
  document.myform3.north.value = northing;
  document.myform3.east.value = easting;
  document.myform3.ellipsoid.selectedIndex = d;
  if (xtm)
     document.myform3.utmmtm[1].checked = true;
  document.myform3.zletter.selectedIndex = zl;
  //document.myform3.locc.selectedIndex = locres;

  // reuse precise values if available (a very "boff" feature)
  // if (northing == floor(preciseNorthing + .5) && easting == floor(preciseEasting + .5))
  // {
  //   northing = preciseNorthing;
  //   easting = preciseEasting;
  // }
  // but only once, see later

  var axis = ellipsoid.axis;
  var eccent = ellipsoid.eccentricity;
  var scaleTm = ellipsoid.scaleTm;
  var eastingOrg = ellipsoid.eastingOrg;
  var k0 = scaleTm;

  var e1 = (1 - sqrt(1 - eccent)) / (1 + sqrt(1 - eccent));
  var x = easting - eastingOrg; //remove 500,000 meter offset for longitude
  var y = northing;

  // correlate index with letter
  var cx ="1C2D3E4F5G6H7J8K9L10M11N12P13Q14R15S16T17U18V19W20X";
  var cxl = String(zl);
  var cxi = cx.indexOf(cxl,0);
  var zletter = cx.charAt(cxi + cxl.length);

  var nhemisphere = 0;
  if (zletter >= "N" || scaleTm == 0.9999)  // MTM in north hemisphere only
    nhemishere = 1;
  else
    y -= 10000000.0; //remove 10,000,000 meter offset used for southern hemisphere

  var longorig = (zone - 1) * 6 - 180 + 3;  //+3 puts origin in middle of zone
  // @dc 180 - (7+76) * 3 - 1.5
  if (scaleTm == 0.9999)
  {
      // longorig = 180 - (zone*1 + 76) * 3 - 1.5;  // without hack, did string concat !!!
      if (mrm == 0)
      {
         zonerResult = gsrugZoner(0., 0., zone);
         longorig = zonerResult.refMeridian;
      }
      else
         longorig = mrm;
  }

  // alert("zone = " + (zone*1 + 76));
  // alert("longorig = " + longorig);

  var eccPrimeSquared = (eccent) / (1-eccent);
  var M = y / k0;
  var mu = M / (axis * (1 - eccent / 4 - 3 * eccent * eccent / 64 - 5 * eccent * eccent * eccent / 256));
  var phi1Rad = mu + (3 * e1 / 2 - 27 * e1 * e1 * e1 / 32) * sin(2 * mu) + (21 * e1 * e1 / 16 - 55 * e1 * e1 * e1 * e1 / 32) * sin(4 * mu) + (151 * e1 * e1 * e1 / 96) * sin(6 * mu);
  var phi1 = phi1Rad * rad2deg;
  var N1 = axis / sqrt(1 - eccent * sin(phi1Rad) * sin(phi1Rad));

  var T1 = tan(phi1Rad) * tan(phi1Rad);
  var C1 = eccPrimeSquared * cos(phi1Rad) * cos(phi1Rad);
  var R1 = axis * (1 - eccent) / pow(1-eccent * sin(phi1Rad) * sin(phi1Rad), 1.5);
  var D = x / (N1 * k0);
  var lat = phi1Rad - (N1 * 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 = lat * rad2deg;
  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) / cos(phi1Rad);
  lon = longorig + lon * rad2deg;
  todms3(lat, lon);
  SetLatLong(lat,lon);
  return eccent;
}




//===================================================================
function get_zoneletter(lat)
{
  //This routine determines the correct UTM letter designator for the given latitude
  //returns 'Z' if latitude is outside the UTM limits of 84N to 80S
  var zoneletter;

  if (scaleTm == 0.9999)
     return ' ';

  if ((84 >= lat) && (lat >= 72)) zoneletter = 'X';
  else if ((72 > lat) && (lat >= 64)) zoneletter = 'W';
  else if ((64 > lat) && (lat >= 56)) zoneletter = 'V';
  else if ((56 > lat) && (lat >= 48)) zoneletter = 'U';
  else if ((48 > lat) && (lat >= 40)) zoneletter = 'T';
  else if ((40 > lat) && (lat >= 32)) zoneletter = 'S';
  else if ((32 > lat) && (lat >= 24)) zoneletter = 'R';
  else if ((24 > lat) && (lat >= 16)) zoneletter = 'Q';
  else if ((16 > lat) && (lat >= 8)) zoneletter = 'P';
  else if (( 8 > lat) && (lat >= 0)) zoneletter = 'N';
  else if (( 0 > lat) && (lat >= -8)) zoneletter = 'M';
  else if ((-8> lat) && (lat >= -16)) zoneletter = 'L';
  else if ((-16 > lat) && (lat >= -24)) zoneletter = 'K';
  else if ((-24 > lat) && (lat >= -32)) zoneletter = 'J';
  else if ((-32 > lat) && (lat >= -40)) zoneletter = 'H';
  else if ((-40 > lat) && (lat >= -48)) zoneletter = 'G';
  else if ((-48 > lat) && (lat >= -56)) zoneletter = 'F';
  else if ((-56 > lat) && (lat >= -64)) zoneletter = 'E';
  else if ((-64 > lat) && (lat >= -72)) zoneletter = 'D';
  else if ((-72 > lat) && (lat >= -80)) zoneletter = 'C';
  else zoneletter = chr(32 + 66); //This is here as an error flag to show that the Latitude is outside the UTM limits
  return zoneletter;
}

//===================================================================
function todms3(lat, lon)
// convert decimal degrees to dms
{
  var latbrg = 1;
  var lonbrg = 2;
  if (lat < 0)
    latbrg = 2
  if (lon < 0)
    lonbrg = 1;
  // LEW: have to round here, else could end up with 60 seconds :-)
  var tlat = Math.abs(lat) + 0.5 / 360000;  // round up 0.005 seconds (1/100th)
  var tlon = Math.abs(lon) + 0.5 / 360000;

  var tlatdm = Math.abs(lat) + 0.5 / 60000;  // round up 0.0005 minutes (1/1000th)
  var tlondm = Math.abs(lon) + 0.5 / 60000;

  var deglat = floor(tlat);

  var t = (tlat - deglat) * 60;
  var minlat = floor(t);

  var minlatdm = floor((tlatdm - floor(tlatdm)) * 60 * 1000) / 1000;

  var seclat = (t - minlat) * 60;
  seclat = floor(seclat * 100) / 100;  //  works in js 1.4
  // seclat = seclat.toFixed(2);  // 2 decimal places js 1.5 and later

  var deglon = floor(tlon);

  t = (tlon - deglon) * 60;
  var minlon = floor(t);

  var minlondm = floor((tlondm - floor(tlondm)) * 60 * 1000) / 1000;

  var seclon = (t - minlon) * 60;
  seclon = floor(seclon * 100) / 100;  // js 1.4
  // seclon = seclon.toFixed(2);  // js 1.5 and later

  document.myform3.latdms.value = deglat + "° " + minlat + "' " + seclat + "\"";
  document.myform3.latb.selectedIndex = latbrg;
  document.myform3.londms.value = deglon + "° " + minlon + "' " + seclon + "\"";
  document.myform3.lonb.selectedIndex = lonbrg;

}


//-------------------------------------------------------------------
function validate_dms(latd, latm, lats, latb, lonm, lond, lons, lonb)
{
  var valid = 1;
  if (abs(Number(latd)) >= 90)
   valid = 0;
  if (Number(latm) >= 60)
   valid = 0;
  if (Number(lats) >= 60)
   valid = 0;
  if (abs(Number(lond)) >= 180)
   valid = 0;
  if (Number(lonm) >= 60)
   valid = 0;
  if (Number(lons) >= 60)
   valid = 0;

  return(valid);
}
//-------------------------------------------------------------------

function validate(locator)
{
  if (locator.length != 10)
    return(0);

  // check locator format
  var myRegExp = /[A-R]{2}[0-9]{2}[A-X]{2}[0-9]{2}[A-X]{2}/;
  if (! myRegExp.test(locator))
  return(0);
}
//-------------------------------------------------------------------


//===================================================================
function usage3()
{
  window.open('http://www.carabus.co.uk/utmusage.htm', 'utmusage', "resizable=yes, menubar=no, scrollbars=yes, width=600, height=600");
}

//===================================================================

//end of myform3
//-------------------------------------------------------------------
// Maths functions

function mod(y, x)
{
  if (y >= 0)
    return y - x * floor(y / x);
  else
    return y + x * (floor(-y / x) + 1.0);
}

function atan2(y, x)
{
  return Math.atan2(y, x);
}

function sqrt(x)
{
  return Math.sqrt(x);
}

function tan(x)
{
  return Math.tan(x);
}

function sin(x)
{
  return Math.sin(x);
}

function cos(x)
{
  return Math.cos(x);
}

function acos(x)
{
  return Math.acos(x);
}

function floor(x)
{
  return Math.floor(x);
}

function round(x)
{
  return Math.round(x);
}

function ln(x)
{
  return Math.log(x);
}

function abs(x)
{
  return Math.abs(x);
}

function pow(x, y)
{
  return Math.pow(x, y);
}

function atan(x)
{
  return Math.atan(x);
}

function chr(x)
{
  return String.fromCharCode(x);
}

function round(x)
{
  return Math.round(x);
}
