// Trigonometric and Great Circle Functions
function sgn(n){
  if ( n > 0 ) {return 1;}
     else {return -1;}
}

function radtodeg(rad){
return (rad / Math.PI) * 180.0 ;
}

function degtorad(deg){
return (deg / 180.0) * Math.PI;
}


function distorad(dis){
  return dis * Math.PI / (180.0  * 60.0);
}

function radtodis(rad){
return rad * 180.0  * 60.0  / Math.PI;
}

function Atn(X){
//  Equivalent of spreadsheet Asin(x)
return 2 * Math.atan(X / (1 + Math.sqrt(1 - X * X)));
}

function Acs(X){
//  Equivalent of spreadsheet Acos(x)
if (X >= 0)
     {return 2 * Math.atan(Math.sqrt((1 - X) / (1 + X)));}
else
    {return PI - 2 * Math.atan(Math.sqrt((1 + X) / (1 - X)));}
}

function md(Y , X ){
//  Equivalent of spreadsheet Mod(y,x)
//  Returns the remainder on dividing y by x in the range
//  0<=Md <x
return Y - X * parseInt(Y /X,10);
}

function modcrs(crs)
{
//  Return crs in range 0<crs<=2*pi
var twopi = 2 * Math.PI;
var mdval=md(twopi - crs, (twopi));
return mdval;
}

function modlon(lon){
//  Return lon in range -pi<=lon<pi
return md(lon + Math.PI, 2 * Math.PI) - Math.PI;
}

// great circle functions
// All arguments and results are in radians

function gcdist(lat1, lon1, lat2, lon2){

// Compute disMath.tance from [lat1,lon1] to [lat2,lon2]
a = 2 * Math.asin( Math.sqrt( Math.pow(Math.sin((lat1-lat2)/2),2) + (Math.cos(lat1)*Math.cos(lat2)*Math.pow(Math.sin((lon1-lon2)/2),2)) ) );
//var msg="<small>LAT1: "+lat1 +"<br \>LON1: "+lon1 + "<br /><br />LAT2: "+lat2 +"<br />LON2: "+lon2+"<br /><br />A: " + a +"</small>";
//document.getElementById('message').innerHTML=msg;
return a;
}

function atn2(Y, X){
    var PI2 = Math.PI / 2;
    if (Math.abs(Y) >= Math.abs(X)){
       atn2 = sgn(Y) * PI2 - Math.atan(X / Y);
    }
    else{
      if (X > 0){
        atn2 = Math.atan(Y / X);
      }
      else{
        if (Y >= 0){
          atn2 = Math.PI + Math.atan(Y / X);
        }
        else{
          atn2 = -PI + Math.atan(Y / X);
        }
      }
    }
    return atn2;
}

function gcbearing(lat1, lon1, lat2, lon2){
// Compute bearing from [lat1,lon1] to [lat2,lon2]
var a=0;
if (gcdist(lat1, lon1, lat2, lon2) < 1E-16)
  {return 0;} // same point
else if (Math.abs(Math.cos(lat1)) < 1E-16)
  {return (3 - Math.sin(lat1)) * Math.PI / 2;} // starting point at pole
else {
  a = Math.atan2(Math.sin(lon1 - lon2) * Math.cos(lat2), Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(lon1 - lon2));
}

return modcrs(a);
}

function gcdirectlat(lat1, lon1, d, tc){
// Compute latitude of point d from [lat1,lon1] on the tc bearing.
return Math.asin(Math.sin(lat1) * Math.cos(d) + Math.cos(lat1) * Math.sin(d) * Math.cos(tc));
}

function gcdirectlon(lat1, lon1, d, tc){
// Compute longitude of point d from [lat1,lon1] on the tc bearing.
lat = gcdirectlat(lat1, lon1, d, tc);
dlon = Math.atan2(Math.sin(tc) * Math.sin(d) * Math.cos(lat1), Math.cos(d) - Math.sin(lat1) * Math.sin(lat));
return modlon(lon1 - dlon);
}

