// UTM conversion functions, etc.
// taken from http://www.mccormick.uk.com/html/distancecalculator.html
//

var deg2rad = Math.PI / 180;
var rad2deg = 180.0 / Math.PI;
var pi = Math.PI;
var locres = 6; //locator characters


//===================================================================
function geo_constants(ellipsoid)
{
// returns ellipsoid values
var ellipsoid_axis = new Array();
var 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
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

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

//===================================================================
function calc_utm(lat, lon)
{
// DJS - hardcode ellipsoid to 21 (utm), and get the appropriate
// access and eccent
var ellipsoid = geo_constants(21);  
var axis = ellipsoid.axis;
var eccent = ellipsoid.eccentricity;

var k0 = 0.9996;
var latrad = lat * deg2rad;
var longrad = lon * deg2rad;
var zonenum = floor((lon + 180) / 6) + 1;
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
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) + 500000.0);
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

// return this as decimalCoord object plus zone
// perhaps should use mapCoord?
var ret = new decimalCoord(easting,northing);
ret.zone = zonenum;

return ret;
}

//===================================================================
function val_utm(northing, easting, zone)
{
if(!zone){zone=11;}// hardcode to SoCal
// DJS - hardcode to 21 (WGS-84)
ellipsoid = geo_constants(21);

var axis = ellipsoid.axis;
var eccent = ellipsoid.eccentricity;
var k0 = 0.9996;

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


// DJS - Have to be sure that we return the proper zone letter in the UTM bit
// how does MS handle this?  I don't remember seeing S in the url...
// -- doesn't seem to matter, interestingly.
// 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 = 1;
//if (zletter >= "N")
//  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

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;

return new decimalCoord(lon,lat);
}


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

//===================================================================
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 ((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;
}

//end of myform3

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);
}

