// Reusable JavaScript code for offset maps
     function init_arrays()                                                                          // Instantiate OFFSET arrays
         {
         for (var i=0; i < pathcount; i++)  
	   {
	   offpts1.push(new GPoint(pathctr[i].x,pathctr[i].y));
	   offpts2.push(new GPoint(pathctr[i].x,pathctr[i].y));
           }
	 make_tracks();
         }

/*     ##########################
       #                        #
       #     CREATE OFFSETS     #
       #                        #
       ##########################     */
     function newoffset(form)                                                                       // User has entered a new offset value
       {
        if (offset == "")                                                                           // Make sure there is a value in the field
          {
            Alert ("No offset value provided.\n\nEnter kilometers as a value between 0.001 and 1000 for the offset lines.");
            form.input.focus();
          }
       var stuff = form.offset.value;
       offset = stuff * 1.00;                                                                        // to ensure float value
       if (isNaN(offset))                                                                            // trap non-numeric input
          {
            alert ("Offset value contains non-numeric characters.\n\nEnter offset numeric value in kilometers (equal to or greater than 0.001 but less than or equal to 1000).");
            form.input.focus();
          }
       if (offset > 1000.0 || offset < 0.001)                                                        // check to make sure value is not to small or too large
          {
            alert ("Offset value out of range.\n\nEnter offset value in kilometers equal to or greater than 0.001 but less than or equal to 1000.");
            form.input.focus();
          }
       var infoStr = '(' + "Offset lines are " + offset + " kilometres from path center." + ')';
       document.getElementById("message").innerHTML = infoStr;
       map.removeOverlay(polyline1);
       map.removeOverlay(polyline2);
       make_tracks();
       }	
     function make_tracks()
         {
         for (var i=0; i < pathcount; i++)
           {
           lonrad1 = deg2rad(pathctr[i].x);
           latrad1 = deg2rad(pathctr[i].y);
           lonrad2 = deg2rad(pathctr[i+1].x);
           latrad2 = deg2rad(pathctr[i+1].y);
           calc_bearing();                                                                           // calculate great circle bearing
           bearing = mod360(bearing + 90.0);
           calc_point();                                                                             // calculate point on great circle
           offpts1[i].x = rad2deg(lonrad2);
           offpts1[i].y = rad2deg(latrad2);
           bearing = mod360(bearing + 180.0); 
           calc_point();                                                                             // calculate point on great circle
           offpts2[i].x = rad2deg(lonrad2);
           offpts2[i].y = rad2deg(latrad2);
           }
	 polyline1 = new GPolyline(offpts1,"#000000", 2, 0.5);
	 map.addOverlay(polyline1);
	 polyline2 = new GPolyline(offpts2,"#000000", 2, 0.5);
         map.addOverlay(polyline2);
         } 

     function calc_bearing()                                                                         // calculate great circle bearing
         {     
         var w = lonrad2 - lonrad1; 
         var v = latrad1 - latrad2;
         var s = 2 * Math.asin(Math.sqrt((Math.sin(v / 2) * Math.sin(v / 2)) + (Math.cos(latrad1) * Math.cos(latrad2) * Math.sin(w / 2) * Math.sin(w / 2))));
         if (Math.cos(latrad1) < 0.000000000000001)
           {                                                                                        // initial point is pole
           if (latrad1 > 0) {var  x = pi;}                                                          // start from north pole
           else {var  x = 0;}                                                                       // start from south pole
           }
         else 
	   {                                                                                        // initial point isn't on pole
           if (Math.sin(lonrad1 - lonrad2) < 0)
             {var x = Math.acos((Math.sin(latrad2) - Math.sin(latrad1) * Math.cos(s)) / (Math.sin(s) * Math.cos(latrad1)));}
           else 
             {var x = 2 * pi - Math.acos((Math.sin(latrad2) - Math.sin(latrad1) * Math.cos(s)) / (Math.sin(s) * Math.cos(latrad1)));}
           }      
         bearing = rad2deg(x);
         }

     function calc_point()                                                                          // calculate point on great circle
         {   
         var x12 = deg2rad(bearing);                                                                // convert bearing to radians
         var s = offset * 1000.0;                                                                   // offset in meters
         s = s * pi /(180 * 60 * 1852);                                                             // convert to radians 
         latrad2 = Math.asin(Math.sin(latrad1) * Math.cos(s) + Math.cos(latrad1) * Math.sin(s) * Math.cos(x12));
         var w = Math.atan2(Math.sin(x12) * Math.sin(s) * Math.cos(latrad1), Math.cos(s) - Math.sin(latrad1) * Math.sin(latrad2));
         lonrad2 = modlon(lonrad1 + w);
         latrad2 = modlat(latrad2);
         }
   
     function handleErrors(errorMessage, url, line) 
         { 
         msg = "There was an error on this page.\n\n"; 
         msg += "An internal programming error may keep\n"; 
         msg += "this page from displaying properly.\n"; 
         msg += "Click OK to continue.\n\n"; 
         msg += "Error message: " + errorMessage + "\n"; 
         msg += "URL: " + url + "\n"; 
         msg += "Line #: " + line; 
         alert(msg); 
         return true 
         } 

     function deg2rad(x)                                                                            // convert decimal degrees to radians
         {                  
         x = x * pi / 180;
         return x;
         }

     function rad2deg(x)                                                                            // convert radians to decimal degrees
         {                                                   
         x = x * 180 / pi;
         return x;
         }

     function mod(x,y)                                                                              // Modulus of x to y
         {           
         return x-y*Math.floor(x/y);
         }

     function modlon(x)                                                                             // ensure longitude is +/-180
         {                                                     
         return mod(x+pi,2*pi)-pi;
         }

     function modcrs(x)                                                                             // ensure 0-360 (radians)
         {                                                   
         return mod(x,2*pi);
         }

     function mod360(x)                                                                             // ensure 0-360 (degrees)
         {                                                   
         return mod(x,360.0);
         }
   
     function modlat(x)                                                                             // ensure latitude is +/-90 
         {                                                   
         return mod(x+pi/2,2*pi)-pi/2;
         }

/*     ##################################
       #                                #
       #     EMPTY THE OFFSET FIELD     #
       #                                #
       ##################################     */
     function wipe(obj)
         {
         obj.value="";                                                                              // clear the form field
         obj.focus();                                                                               // reset the focus
         }
