﻿var lineColor = "#301566";
var fillColor = "#301566";
var map = null;
var myPoints = new Array();
var pgon = null;
var lhMouseMove = null;
var lhDrawPolymarkerClick = null;
var markerOptions = { draggable: true, clickable: false, bouncy: false};
var pntIndx = 0;
var myGeomType = null;
var DragOn = false;
var saveMark = null;
var markers = [];
var cMarker = null;

document.getElementsByClassName = function (cl) {
    var retnode = [];
    var myclass = new RegExp('\\b' + cl + '\\b');
    var elem = this.getElementsByTagName('*');
    for (var i = 0; i < elem.length; i++) {
        var classes = elem[i].className;
        if (myclass.test(classes)) retnode.push(elem[i]);
    }
    return retnode;
};

function map_load() {
    if (GBrowserIsCompatible()) {
        map = new GMap2($(".themap")[0]);
        var lat = parseFloat($(".themap-lat input")[0].value);
        var lon = parseFloat($(".themap-lon input")[0].value);
        var zoom = parseInt($(".themap-zoom input")[0].value);
        map.setCenter(new GLatLng(lat, lon), parseInt(zoom), G_HYBRID_MAP);
        addCenterMarker(lat, lon);
        addInitialOverlay();

        if ($(".themap-enable-controls input")[0].value == "true") {
            if ($(".themap-show-map-type input")[0].value == "true") {
                var mapTypeControl = new GMapTypeControl();
                var topRight = new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(10, 10));
                var bottomRight = new GControlPosition(G_ANCHOR_BOTTOM_RIGHT, new GSize(50, 50));
                map.addControl(mapTypeControl, topRight);
            }
            
            if ($(".themap-large-control input")[0].value == "true") {
                map.addControl(new GLargeMapControl());
            } else {
                map.addControl(new GSmallZoomControl3D());
            }
            
        }
    }
}

function addCenterMarker(lat, lon) {
    $(".themap-lat input")[0].value = lat;
    $(".themap-lon input")[0].value = lon;
    // Create our "tiny" marker icon
    var icon = new GIcon();
    //icon.image = "/images/map/mm_20_red.png";
    icon.image = "/images/map/you-are-here.png";
    icon.shadow = "/images/map/mm_20_shadow.png";
    icon.iconSize = new GSize(118, 90);
    icon.shadowSize = new GSize(118, 80);
    icon.iconAnchor = new GPoint(33, 66);
    //icon.iconAnchor = new GPoint(6, 20);
    icon.infoWindowAnchor = new GPoint(5, 1);
    //place the markers on the map
    var point = new GLatLng(lat, lon);

    var centerMarkerOptions = { draggable: true, clickable: false, bouncy: false, icon: icon };
    var centerMaker = new GMarker(point, centerMarkerOptions);

    GEvent.addListener(centerMaker, "dragstart", function () { startDragCenter(centerMaker); });
    GEvent.addListener(centerMaker, "dragend", function () { endDragCenter(centerMaker); });
    map.addOverlay(centerMaker);
    cMarker = centerMaker;
    
}

function addInfoWindow(point) {
    var infoWindow = map.getInfoWindow();
    map.openInfoWindowHtml(point, "<span style='color:#f00'>YOU ARE HERE!</span>", { onOpenFn: function () {
        infoWindow.reset(point, infoWindow.getTabs(), new GSize(100, 60), null, null);
    }});
}

function addInitialOverlay() {
    try {
        var points = $(".themap-points input")[0].value.split('|');
        myGeomType = $(".themap-type input")[0].value;
        if (myGeomType == "circle") {
            myPoints = new Array();
            var radiusPoint = new GLatLng($(".themap-click-lat input")[0].value, $(".themap-click-lon input")[0].value);
            myPoints.push(radiusPoint);
        }
        for (var i = 0; i < points.length; ++i) {
            var point = new GLatLng(points[i].split(':')[0], points[i].split(':')[1]);
            setMarker(point);
        }
        if (myGeomType == "circle") {
            drawCircle(new GLatLng($(".themap-click-lat input")[0].value, $(".themap-click-lon input")[0].value));
        } else {
            drawPoly();
        }
    }
    catch (ex) {
    }
}

// initialize the drawing of the polygon
function draw(geomType, lat, lon) {
    //make sure to reset everything back to starting point
    //  this allows the user to delete the polygon and start again
    if (pgon != null) {
        map.removeOverlay(pgon);
    }
    map.clearOverlays();
    markers = [];
    myPoints = new Array();
    pgon = null;
    myGeomType = geomType;
    $(".themap-type input")[0].value = myGeomType;
    var ac = map.getCenter();
    lat = ac.lat();
    lon = ac.lng();
    $(".themap-points input")[0].value = "";
    initMap();
    addCenterMarker(lat, lon);
    lhMouseMove = GEvent.addListener(map, "mousemove", mouseMove);
    if (myGeomType == "circle") {
        var point = new GLatLng(lat - 0.007, lon + 0.019);
        createCircle(null, point);
    } else {
        lhDrawPolymarkerClick = GEvent.addListener(map, "click", drawPolyMarkerClick);
    }
    return true;        //testing
}

function drawPolyMarkerClick(mark, point) {
    if (myGeomType == "circle") {
        createCircle(mark, point);
    }
    else {
        createPolygon(mark, point)
    }
}

function createPolygon(mark, point) {
    if (mark) {
        //map.removeOverlay(mark);  
    }
    else {
        setMarker(point);
        if (myPoints.length > 2) {
            drawPoly();
        }
    }
}

function createCircle(mark, point) {
    if (point == null) {
    }
    else {
        if (saveMark != null) {
            map.removeOverlay(saveMark);
            saveMark = null;
        }
        drawCircle(point);
        setMarker(point);
        GEvent.removeListener(lhDrawPolymarkerClick);
    }
}

function initMap() {
    if (lhDrawPolymarkerClick != null) {
        GEvent.removeListener(lhDrawPolymarkerClick);
    }
}

function clearMap() {
    map.clearOverlays();
    markers = [];
}

function centerMap(lat, lon) {
    map.setCenter(new GLatLng(lat, lon), parseInt(parseInt($(".themap-zoom input")[0].value)), G_HYBRID_MAP);
}

function setMarker(pntx) {
    var marker = null;
    if (myGeomType == "polygon") {
        marker = new GMarker(pntx, markerOptions);
        myPoints.push(pntx);
    }
    else {   /*circle */
        marker = new GMarker(myPoints[0], markerOptions);
        saveMark = marker;
    }
    GEvent.addListener(marker, "dragstart", function () { startDrag(marker); });
    GEvent.addListener(marker, "dragend", function () { endDrag(marker); });
    map.addOverlay(marker);
    markers[markers.length] = marker;
    
}

/* Before you send the polygon to draw on the map make sure
to close the polygon 
the first and last point must be equal */
function drawPoly() {
    if (pgon != null) {
        map.removeOverlay(pgon);
    }
    pPoints = new Array();
    var i = 0;
    for (i = 0; i < myPoints.length; i++) {
        pPoints[i] = myPoints[i];
    }
    pPoints[i] = myPoints[0];  /*Close the polygon*/
    pgon = new GPolygon(pPoints, lineColor, 2, .5, fillColor, .5);
    map.addOverlay(pgon);

    $(".themap").trigger('drawPoly');
}

function drawCircle(clickedPoint) {
    var ac = map.getCenter();
    var cpnt = new GLatLng(parseFloat($(".themap-lat input")[0].value), parseFloat($(".themap-lon input")[0].value));
    var mapNormalProj = G_NORMAL_MAP.getProjection();
    var mapZm = map.getZoom();
    var centerPixel = mapNormalProj.fromLatLngToPixel(cpnt, mapZm);
    var clickedPixel = mapNormalProj.fromLatLngToPixel(clickedPoint, mapZm);
    var rdis;
    var xdis = cpnt.distanceFrom(clickedPoint);

    var clickLat = clickedPoint.y;
    var clickLon = clickedPoint.x;

    $(".themap-click-lat input")[0].value = clickLat;
    $(".themap-click-lon input")[0].value = clickLon;
    switch (mapZm)         // set the radius based upon the current zoom level
    {
        case 0:
            rdis = parseInt(xdis / 94208);
            break;
        case 1:
            rdis = parseInt(xdis / 47104);
            break;
        case 2:
            rdis = parseInt(xdis / 23552);
            break;
        case 3:
            rdis = parseInt(xdis / 11776);
            break;
        case 4:
            rdis = parseIn(xdis / 5888);
            break;
        case 5:
            rdis = parseInt(xdis / 2944);
            break;
        case 6:
            rdis = parseInt(xdis / 1472);
            break;
        case 7:
            rdis = parseInt(xdis / 736);
            break;
        case 8:
            rdis = parseInt(xdis / 368);
            break;
        case 9:
            rdis = parseInt(xdis / 184);
            break;
        case 10:
            rdis = parseInt(xdis / 92);
            break;
        case 11:
            rdis = parseInt(xdis / 46);
            break;
        case 12:
            rdis = parseInt(xdis / 28);
            break;
        case 13:
            rdis = parseInt(xdis / 14);
            break;
        case 14:
            rdis = parseInt(xdis / 7);
            break;
        case 15:
            rdis = parseInt(xdis / 3.5);
            break;
        case 16:
            rdis = parseInt(xdis / 1.75);
            break;
        case 17:
            rdis = parseInt(xdis / .875);
            break;
        case 18:
            rdis = parseInt(xdis / .437);
            break;
        case 19:
            rdis = parseInt(xdis / .218);
            break;
        case 20:
            rdis = parseInt(xdis / .109);
            break;
    }
    myPoints = new Array();

    var polyNumSides = 20;
    var polySideLength = 18;
    for (var a = 0; a < (polyNumSides + 1); a++) {
        var aRad = polySideLength * a * (Math.PI / 180);
        var pixelX = centerPixel.x + rdis * Math.cos(aRad);
        var pixelY = centerPixel.y + rdis * Math.sin(aRad);
        var polyPixel = new GPoint(pixelX, pixelY);
        var polyPoint = mapNormalProj.fromPixelToLatLng(polyPixel, mapZm);
        myPoints.push(polyPoint);
    }
    // ok now go draw our circle
    
    $(".themap-points input")[0].value = myPoints;
    $(".themap").trigger('drawCircle');
    drawPoly();
}

function startDragCenter(marker) {
    centerMark = marker;
    var centerPoint = marker.getPoint();
}

function endDragCenter(marker) {
    var endPoint = marker.getPoint();

    var latDif = parseFloat($(".themap-lat input")[0].value) - parseFloat(endPoint.lat());
    var lngDif = parseFloat($(".themap-lon input")[0].value) - parseFloat(endPoint.lng());

    clearMap();
    map.setCenter(new GLatLng(endPoint.lat(), endPoint.lng()));
    var mapPointsString = "";
    for (var i = 0; i < myPoints.length; i++) {
        var lat = myPoints[i].lat();
        var lng = myPoints[i].lng();
        lat = parseFloat(lat) - parseFloat(latDif);
        lng = parseFloat(lng) - parseFloat(lngDif);
        myPoints[i] = new GLatLng(lat, lng);
        mapPointsString += lat + ":" + lng;
        if (i != myPoints.length - 1) {
            mapPointsString += "|";
        }
    }
    //drawPoly();
    $('.themap-points input')[0].value = mapPointsString;

    $(".themap-lat input")[0].value = endPoint.lat();
    $(".themap-lon input")[0].value = endPoint.lng();

    pgon = null;
    myPoints = new Array();
    addCenterMarker($(".themap-lat input")[0].value, $(".themap-lon input")[0].value);
    addInitialOverlay();
}

function startDrag(marker) {
    //saveMark = marker;
    DragOn = true;
    var x = marker.getPoint();
    var slat = x.lat();
    var slng = x.lng();
    for (var i = 0; i < myPoints.length; i++) {
        var lat = myPoints[i].lat();
        var lng = myPoints[i].lng();
        if (slat == lat) {
            if (slng == lng) {
                pntIndx = i;
            }
        }
    }
}

//  we have moved a polypoint
function endDrag(marker) {
    DragOn = false;
    var x = marker.getPoint();
    var lat = x.lat();
    var lng = x.lng();
    if (myGeomType == "circle") {
        drawCircle(new GLatLng(lat, lng));
    }
    else {
        myPoints[pntIndx] = new GLatLng(lat, lng);
        if (pgon != null) {
            drawPoly();
        }
    }
}

function mouseMove(e) {
    //document.getElementById("txtLat").value = e.lat();
    //document.getElementById("txtLon").value = e.lng();
    if (DragOn == false) {
        return true;        //testing
    }

    if (myGeomType == "circle") {
        if (pgon != null) {
            map.removeOverlay(pgon);
        }
    }
    else {
        // the user is moving a point
        if (pgon != null) {
            var lat = e.lat();
            var lng = e.lng();
            myPoints[pntIndx] = new GLatLng(lat, lng);
            drawPoly();
        }
    }
    return true;
}

function updateArea() {
    if ($(".themap-type input")[0].value == "circle") {
        var lat2 = parseFloat($(".themap-click-lat input")[0].value);
        var lon2 = parseFloat($(".themap-click-lon input")[0].value);
        var lat1 = parseFloat($(".themap-lat input")[0].value);
        var lon1 = parseFloat($(".themap-lon input")[0].value);
        $(".themap-radius input")[0].value = LatLon.distHaversine(lat2, lon2, lat1, lon1).toPrecision(4) / 1.61;
        var tlat = "";
        //Create a string with the latitude and longitude pairs embedded.
        for (aa = 0; myPoints.length > aa; aa++) {
            tlat = tlat + myPoints[aa].lat() + ":" + myPoints[aa].lng();
            if (myPoints.length - 1 > aa) {
                tlat += "|";
            }
        }
        // save the string in a hidden text box to be passed to the server side
        $(".themap-points input")[0].value = tlat;
        return true;
    }
    else {
        if (myPoints.length < 3) {
            alert("You must select at least 3 points");
            return false;
        }
        var tlat = "";
        //Create a string with the latitude and longitude pairs embedded.
        for (aa = 0; myPoints.length > aa; aa++) {
            tlat = tlat + myPoints[aa].lat() + ":" + myPoints[aa].lng();
            if (myPoints.length - 1 > aa) {
                tlat += "|";
            }
        }
        // save the string in a hidden text box to be passed to the server side
        $(".themap-points input")[0].value = tlat;

        return true;
    }
}

function getArea() {
    if ($(".themap-type input")[0].value == "circle") {
        var lat2 = parseFloat($(".themap-click-lat input")[0].value);
        var lon2 = parseFloat($(".themap-click-lon input")[0].value);
        var lat1 = parseFloat($(".themap-lat input")[0].value);
        var lon1 = parseFloat($(".themap-lon input")[0].value);
        $(".themap-radius input")[0].value = LatLon.distHaversine(lat2, lon2, lat1, lon1).toPrecision(4) / 1.61;
        return true;
    }
    else {
        if (myPoints.length < 3) {
            alert("You must select at least 3 points");
            return false;
        }
        var tlat = "";
        //Create a string with the latitude and longitude pairs embedded.
        for (aa = 0; myPoints.length > aa; aa++) {
            tlat = tlat + myPoints[aa].lat() + ":" + myPoints[aa].lng();
            if (myPoints.length - 1 > aa) {
                tlat += "|";
            }
        }
        // save the string in a hidden text box to be passed to the server side
        $(".themap-points input")[0].value = tlat;

        // remove the listener if it has been turned on. 
        if (lhMouseMove != null) {
            GEvent.removeListener(lhMouseMove);
            lhMouseMove = null;
        }
        if (lhDrawPolymarkerClick != null) {
            GEvent.removeListener(lhDrawPolymarkerClick);
            lhDrawPolymarkerClick = null;
        }

        GEvent.clearInstanceListeners(map);
        return true;
    }
}

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */

/*
* Use Haversine formula to Calculate distance (in km) between two points specified by 
* latitude/longitude (in numeric degrees)
*
* from: Haversine formula - R. W. Sinnott, "Virtues of the Haversine",
*       Sky and Telescope, vol 68, no 2, 1984
*       http://www.census.gov/cgi-bin/geo/gisfaq?Q5.1
*
* example usage from form:
*   result.value = LatLon.distHaversine(lat1.value.parseDeg(), long1.value.parseDeg(), 
*                                       lat2.value.parseDeg(), long2.value.parseDeg());
* where lat1, long1, lat2, long2, and result are form fields
*/

LatLon.distHaversine = function (lat1, lon1, lat2, lon2) {
    var R = 6371; // earth's mean radius in km
    var dLat = (lat2 - lat1).toRad();
    var dLon = (lon2 - lon1).toRad();
    lat1 = lat1.toRad(), lat2 = lat2.toRad();

    var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
          Math.cos(lat1) * Math.cos(lat2) *
          Math.sin(dLon / 2) * Math.sin(dLon / 2);
    var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    var d = R * c;
    return d;
}


/*
* Use Law of Cosines to calculate distance (in km) between two points specified by latitude/longitude 
* (in numeric degrees).
*/
LatLon.distCosineLaw = function (lat1, lon1, lat2, lon2) {
    var R = 6371; // earth's mean radius in km
    var d = Math.acos(Math.sin(lat1.toRad()) * Math.sin(lat2.toRad()) +
                    Math.cos(lat1.toRad()) * Math.cos(lat2.toRad()) * Math.cos((lon2 - lon1).toRad())) * R;
    return d;
}


/*
* calculate (initial) bearing between two points
*   see http://williams.best.vwh.net/avform.htm#Crs
*/
LatLon.bearing = function (lat1, lon1, lat2, lon2) {
    lat1 = lat1.toRad(); lat2 = lat2.toRad();
    var dLon = (lon2 - lon1).toRad();

    var y = Math.sin(dLon) * Math.cos(lat2);
    var x = Math.cos(lat1) * Math.sin(lat2) -
          Math.sin(lat1) * Math.cos(lat2) * Math.cos(dLon);
    return Math.atan2(y, x).toBrng();
}


/*
* calculate midpoint of great circle line between p1 & p2.
*   see http://mathforum.org/library/drmath/view/51822.html for derivation
*/
LatLon.midPoint = function (lat1, lon1, lat2, lon2) {
    lat1 = lat1.toRad();
    lat2 = lat2.toRad();
    var dLon = (lon2 - lon1).toRad();

    var Bx = Math.cos(lat2) * Math.cos(dLon);
    var By = Math.cos(lat2) * Math.sin(dLon);

    lat3 = Math.atan2(Math.sin(lat1) + Math.sin(lat2),
                    Math.sqrt((Math.cos(lat1) + Bx) * (Math.cos(lat1) + Bx) + By * By));
    lon3 = lon1.toRad() + Math.atan2(By, Math.cos(lat1) + Bx);

    if (isNaN(lat3) || isNaN(lon3)) return null;
    return new LatLon(lat3.toDeg(), lon3.toDeg());
}


/*
* calculate destination point given start point, initial bearing (deg) and distance (km)
*   see http://williams.best.vwh.net/avform.htm#LL
*/
LatLon.prototype.destPoint = function (brng, d) {
    var R = 6371; // earth's mean radius in km
    var lat1 = this.lat.toRad(), lon1 = this.lon.toRad();
    brng = brng.toRad();

    var lat2 = Math.asin(Math.sin(lat1) * Math.cos(d / R) +
                        Math.cos(lat1) * Math.sin(d / R) * Math.cos(brng));
    var lon2 = lon1 + Math.atan2(Math.sin(brng) * Math.sin(d / R) * Math.cos(lat1),
                               Math.cos(d / R) - Math.sin(lat1) * Math.sin(lat2));
    lon2 = (lon2 + Math.PI) % (2 * Math.PI) - Math.PI;  // normalise to -180...+180

    if (isNaN(lat2) || isNaN(lon2)) return null;
    return new LatLon(lat2.toDeg(), lon2.toDeg());
}


/*
* calculate final bearing arriving at destination point given start point, initial bearing and distance
*/
LatLon.prototype.finalBrng = function (brng, d) {
    var p1 = this, p2 = p1.destPoint(brng, d);
    // get reverse bearing point 2 to point 1
    var rev = LatLon.bearing(p2.lat, p2.lon, p1.lat, p1.lon);
    // & reverse it by adding 180°
    var brng = (rev + 180) % 360;
    return brng;
}


/*
* calculate distance, bearing, destination point on rhumb line
*   see http://williams.best.vwh.net/avform.htm#Rhumb
*/
LatLon.distRhumb = function (lat1, lon1, lat2, lon2) {
    var R = 6371; // earth's mean radius in km
    var dLat = (lat2 - lat1).toRad(), dLon = Math.abs(lon2 - lon1).toRad();
    var dPhi = Math.log(Math.tan(lat2.toRad() / 2 + Math.PI / 4) / Math.tan(lat1.toRad() / 2 + Math.PI / 4));
    var q = (Math.abs(dLat) > 1e-10) ? dLat / dPhi : Math.cos(lat1.toRad());
    // if dLon over 180° take shorter rhumb across 180° meridian:
    if (dLon > Math.PI) dLon = 2 * Math.PI - dLon;
    var d = Math.sqrt(dLat * dLat + q * q * dLon * dLon);
    return d * R;
}


LatLon.brngRhumb = function (lat1, lon1, lat2, lon2) {
    var dLon = (lon2 - lon1).toRad();
    var dPhi = Math.log(Math.tan(lat2.toRad() / 2 + Math.PI / 4) / Math.tan(lat1.toRad() / 2 + Math.PI / 4));
    if (Math.abs(dLon) > Math.PI) dLon = dLon > 0 ? -(2 * Math.PI - dLon) : (2 * Math.PI + dLon);
    return Math.atan2(dLon, dPhi).toBrng();
}


LatLon.prototype.destPointRhumb = function (brng, dist) {
    var R = 6371; // earth's mean radius in km
    var d = parseFloat(dist) / R;  // d = angular distance covered on earth's surface
    var lat1 = this.lat.toRad(), lon1 = this.lon.toRad();
    brng = brng.toRad();

    var lat2 = lat1 + d * Math.cos(brng);
    var dLat = lat2 - lat1;
    var dPhi = Math.log(Math.tan(lat2 / 2 + Math.PI / 4) / Math.tan(lat1 / 2 + Math.PI / 4));
    var q = (Math.abs(dLat) > 1e-10) ? dLat / dPhi : Math.cos(lat1);
    var dLon = d * Math.sin(brng) / q;
    // check for some daft bugger going past the pole
    if (Math.abs(lat2) > Math.PI / 2) lat2 = lat2 > 0 ? Math.PI - lat2 : -(Math.PI - lat2);
    lon2 = (lon1 + dLon + Math.PI) % (2 * Math.PI) - Math.PI;

    if (isNaN(lat2) || isNaN(lon2)) return null;
    return new LatLon(lat2.toDeg(), lon2.toDeg());
}


/*
* construct a LatLon object: arguments in numeric degrees
*
* note all LatLong methods expect & return numeric degrees (for lat/long & for bearings)
*/
function LatLon(lat, lon) {
    this.lat = lat;
    this.lon = lon;
}


/*
* represent point {lat, lon} in standard representation
*/
LatLon.prototype.toString = function () {
    return this.lat.toLat() + ', ' + this.lon.toLon();
}

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */

// extend String object with method for parsing degrees or lat/long values to numeric degrees
//
// this is very flexible on formats, allowing signed decimal degrees, or deg-min-sec suffixed by 
// compass direction (NSEW). A variety of separators are accepted (eg 3º 37' 09"W) or fixed-width 
// format without separators (eg 0033709W). Seconds and minutes may be omitted. (Minimal validation 
// is done).

String.prototype.parseDeg = function () {
    if (!isNaN(this)) return Number(this);                 // signed decimal degrees without NSEW

    var degLL = this.replace(/^-/, '').replace(/[NSEW]/i, '');  // strip off any sign or compass dir'n
    var dms = degLL.split(/[^0-9.,]+/);                     // split out separate d/m/s
    for (var i in dms) if (dms[i] == '') dms.splice(i, 1);    // remove empty elements (see note below)
    switch (dms.length) {                                  // convert to decimal degrees...
        case 3:                                              // interpret 3-part result as d/m/s
            var deg = dms[0] / 1 + dms[1] / 60 + dms[2] / 3600; break;
        case 2:                                              // interpret 2-part result as d/m
            var deg = dms[0] / 1 + dms[1] / 60; break;
        case 1:                                              // decimal or non-separated dddmmss
            if (/[NS]/i.test(this)) degLL = '0' + degLL;       // - normalise N/S to 3-digit degrees
            var deg = dms[0].slice(0, 3) / 1 + dms[0].slice(3, 5) / 60 + dms[0].slice(5) / 3600; break;
        default: return NaN;
    }
    if (/^-/.test(this) || /[WS]/i.test(this)) deg = -deg; // take '-', west and south as -ve
    return deg;
}
// note: whitespace at start/end will split() into empty elements (except in IE)


/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */

// extend Number object with methods for converting degrees/radians

Number.prototype.toRad = function () {

    // convert degrees to radians
    return this * Math.PI / 180;
}

Number.prototype.toDeg = function () {  // convert radians to degrees (signed)
    return this * 180 / Math.PI;
}

Number.prototype.toBrng = function () {  // convert radians to degrees (as bearing: 0...360)
    return (this.toDeg() + 360) % 360;
}


/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */

// extend Number object with methods for presenting bearings & lat/longs

Number.prototype.toDMS = function () {  // convert numeric degrees to deg/min/sec
    var d = Math.abs(this);  // (unsigned result ready for appending compass dir'n)
    d += 1 / 7200;  // add ½ second for rounding
    var deg = Math.floor(d);
    var min = Math.floor((d - deg) * 60);
    var sec = Math.floor((d - deg - min / 60) * 3600);
    // add leading zeros if required
    if (deg < 100) deg = '0' + deg; if (deg < 10) deg = '0' + deg;
    if (min < 10) min = '0' + min;
    if (sec < 10) sec = '0' + sec;
    return deg + '\u00B0' + min + '\u2032' + sec + '\u2033';
}

Number.prototype.toLat = function () {  // convert numeric degrees to deg/min/sec latitude
    return this.toDMS().slice(1) + (this < 0 ? 'S' : 'N');  // knock off initial '0' for lat!
}

Number.prototype.toLon = function () {  // convert numeric degrees to deg/min/sec longitude
    return this.toDMS() + (this > 0 ? 'E' : 'W');
}

Number.prototype.toPrecision = function (fig) {  // override toPrecision method with one which displays 
    if (this == 0) return 0;                      // trailing zeros in place of exponential notation
    var scale = Math.ceil(Math.log(this) * Math.LOG10E);
    var mult = Math.pow(10, fig - scale);
    return Math.round(this * mult) / mult;
}

window.onload = map_load;




