﻿

// converts coords from geomatic to google projection.
// geomatic uses
var GeographicTransformation = {


    pointsDenmark: [
                        [55.4040698270061, 8.31390380859375],
                        [55.547280698640805, 8.0419921875],
                        [55.815172308302344, 8.12713623046875],
                        [56.17461002531615, 8.03924560546875],
                        [56.66981125153264, 8.096923828125],
                        [57.022794415389725, 8.37982177734375],
                        [57.139220027750774, 8.59130859375],
                        [57.21663423091292, 9.4482421875],
                        [57.45677122453565, 9.73388671875],
                        [57.60569290323164, 9.92340087890625],
                        [57.63658047066351, 10.20355224609375],
                        [57.765728734885194, 10.59906005859375],
                        [57.752541524031415, 10.68145751953125],
                        [57.58214188935998, 10.48919677734375],
                        [57.49959318201404, 10.63751220703125],
                        [57.39762405500045, 10.8544921875],
                        [57.33541661439605, 11.2225341796875],
                        [57.20771009775018, 11.2060546875],
                        [57.1779474000072, 10.83251953125],
                        [57.124314084296195, 10.46722412109375],
                        [56.59881462643554, 10.38482666015625],
                        [56.53222856465471, 10.9698486328125],
                        [56.32110624718752, 10.96710205078125],
                        [56.090427143991526, 10.83251953125],
                        [55.68997171381322, 10.667724609375],
                        [56.02371555053354, 11.25274658203125],
                        [56.150904407174565, 12.448883056640625],
                        [56.04366444030844, 12.6507568359375],
                        [55.91612112354792, 12.731781005859375],
                        [55.60860840190929, 12.811431884765625],
                        [55.47885346331034, 12.41455078125],
                        [54.95554005461726, 12.5628662109375],
                        [54.55295156056188, 11.976470947265625],
                        [54.57206165565852, 11.5576171875],
                        [54.75078355095094, 10.993194580078125],
                        [54.71192884840614, 10.6787109375],
                        [54.814139757529865, 10.557861328125],
                        [54.803059585276394, 10.404052734375],
                        [54.83233630197033, 9.672088623046875],
                        [54.824425768387144, 9.4317626953125],
                        [54.78405793438326, 9.35211181640625],
                        [54.910566989613045, 8.60504150390625],
                        [55.13021935663458, 8.426513671875]
                    ],

    pointsBonholm: [
                    [55.10115902751222, 14.668121337890625],
                    [55.24390077966148, 14.698333740234375],
                    [55.311954016360275, 14.772491455078125],
                    [55.232155672018074, 14.942779541015625],
                    [55.141209644495056, 15.194091796875],
                    [55.05713560448017, 15.165252685546875],
                    [54.98234215326033, 15.093841552734375],
                    [54.983918190363234, 14.996337890625],
                    [55.03667968572116, 14.79583740234375],
                    [55.08937178977164, 14.679107666015625]
        ],

    isSquareWithinDK: function(latlong1, latlong2) {

        // checks wether the square (extend latlong1 to latlong2) any part is within denmark points.
        if (this.isSquareWithinSquare(latlong1, latlong2, this.pointsDenmark)) {
            return true;
        }
        if (this.isSquareWithinSquare(latlong1, latlong2, this.pointsBonholm)) {
            return true;
        }
        return false;
    },

    isSquareWithinSquare: function(latlong1, latlong2, pointSet) {

        // check the four corners of the square...
        if (this.isWithInPolygon({ lat: latlong1.lat(), lng: latlong1.lng() }, pointSet))
            return true;

        if (this.isWithInPolygon({ lat: latlong2.lat(), lng: latlong2.lng() }, pointSet))
            return true;

        if (this.isWithInPolygon({ lat: latlong1.lat(), lng: latlong2.lng() }, pointSet))
            return true;

        if (this.isWithInPolygon({ lat: latlong2.lat(), lng: latlong1.lng() }, pointSet))
            return true;

        // still here. ok. hmmm.
        // make polygon of the square.
        var points = new Array();
        points.push([latlong1.lat(), latlong1.lng()]);
        points.push([latlong2.lat(), latlong1.lng()]);
        points.push([latlong2.lat(), latlong2.lng()]);
        points.push([latlong1.lat(), latlong2.lng()]);
        points.push([latlong1.lat(), latlong1.lng()]);


        // each point of the polygon, check if its within my square
        for (var i = 0; i < pointSet.length; i++) {
            if (this.isWithInPolygon({ lat: pointSet[i][0], lng: pointSet[i][1] }, points))
                return true;
        }
        return false;
    },


    isWithInPolygon: function(latlong, points) {


        var i;
        var j = points.length - 1;
        var inPoly = false;
        var lat = latlong.lat;
        var lon = latlong.lng;

        for (i = 0; i < points.length; i++) {
            if (points[i][1] < lon && points[j][1] >= lon || points[j][1] < lon && points[i][1] >= lon) {
                if (points[i][0] + (lon - points[i][1]) / (points[j][1] - points[i][1]) * (points[j][0] - points[i][0]) < lat) {
                    inPoly = !inPoly;
                }
            }
            j = i;
        }
        return inPoly;
    },

    isWithInBounds: function(gLat, gLng, bounds) {
        if (bounds == null)
            return false;

        var p2 = GeographicTransformation.fromGMap(bounds[0].x, bounds[0].y);

        var p = GeographicTransformation.fromGMap(gLat, gLng);


        if (p.x >= p2.x && p.x < (p2.x + 100)) {
            if (p.y >= p2.y && p.y < (p2.y + 100)) {
                return true;
            }
        }
        return false;
    },
    getCenterPoint: function(gLat, gLng) {
        var p = GeographicTransformation.fromGMap(gLat, gLng);
        var x = (Math.floor(p.x / 100) * 100) + 50;
        var y = (Math.floor(p.y / 100) * 100) + 50;

        var p = GeographicTransformation.toGMap(x, y);

        return { "x": p.x, "y": p.y };

    },
    getCellBounds: function(glat, glng) {
        var p = GeographicTransformation.fromGMap(glat, glng);
        // have point.
        // round down to 100 x 100

        var x = Math.floor(p.x / 100) * 100;
        var y = Math.floor(p.y / 100) * 100;


        var sq = [[0, 0], [100, 0], [100, 100], [0, 100]];
        var points = new Array();

        for (var i = 0; i < sq.length; i++) {
            var p = [x + sq[i][0], y + sq[i][1]];

            points.push(GeographicTransformation.toGMap(p[0], p[1]));
        }

        return points;
        //console.debug(points);
        // now calc back;

    },

    fromGMap: function(lat, lng) {


        var k0 = 0.9996;
        var a = 6378137.0;
        var eccSquared = 0.00669438;

        var LongOrigin;
        var eccPrimeSquared;
        var N, T, C, A, M;
        var Lat = lat;
        var Long = lng;
        var deg2rad = Math.PI / 180;


        var LongTemp = (Long + 180) - (Math.floor(((Long + 180) / 360))) * 360 - 180; // -180.00 .. 179.9;


        var LatRad = Lat * deg2rad;
        var LongRad = LongTemp * deg2rad;
        var LongOriginRad;
        var ZoneNumber;

        ZoneNumber = 32; // (int)((LongTemp + 180) / 6) + 1;


        // Special zones for Svalbard
        if (Lat >= 72.0 && Lat < 84.0) {
            if (LongTemp >= 0.0 && LongTemp < 9.0) ZoneNumber = 31;
            else if (LongTemp >= 9.0 && LongTemp < 21.0) ZoneNumber = 33;
            else if (LongTemp >= 21.0 && LongTemp < 33.0) ZoneNumber = 35;
            else if (LongTemp >= 33.0 && LongTemp < 42.0) ZoneNumber = 37;
        }

        LongOrigin = (ZoneNumber - 1) * 6 - 180 + 3;  //+3 puts origin in middle of zone
        LongOriginRad = LongOrigin * deg2rad;

        //compute the UTM Zone from the latitude and longitude
        //sprintf(UTMZone, "%d%c", ZoneNumber, UTMLetterDesignator(Lat));

        eccPrimeSquared = (eccSquared) / (1 - eccSquared);

        N = a / Math.sqrt(1 - eccSquared * Math.sin(LatRad) * Math.sin(LatRad));
        T = Math.tan(LatRad) * Math.tan(LatRad);
        C = eccPrimeSquared * Math.cos(LatRad) * Math.cos(LatRad);
        A = Math.cos(LatRad) * (LongRad - LongOriginRad);

        M = a * ((1 - eccSquared / 4 - 3 * eccSquared * eccSquared / 64 - 5 * eccSquared * eccSquared * eccSquared / 256) * LatRad
                        - (3 * eccSquared / 8 + 3 * eccSquared * eccSquared / 32 + 45 * eccSquared * eccSquared * eccSquared / 1024) * Math.sin(2 * LatRad)
                                            + (15 * eccSquared * eccSquared / 256 + 45 * eccSquared * eccSquared * eccSquared / 1024) * Math.sin(4 * LatRad)
                                            - (35 * eccSquared * eccSquared * eccSquared / 3072) * Math.sin(6 * LatRad));


        var UTMEasting = (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 UTMNorthing = (k0 * (M + N * Math.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)
            UTMNorthing += 10000000.0; //10000000 meter offset for southern hemisphere

        return { x: Math.round(UTMEasting), y: Math.round(UTMNorthing) }; // new Point2d(UTMEasting, UTMNorthing, ProjectionAndDatum.utm32_wgs84);

    },

    toGMap: function(x, y) {

        var k0 = 0.9996;
        var a = 6378137.0;
        var eccSquared = 0.00669438;
        var eccPrimeSquared;
        var e1 = (1 - Math.sqrt(1 - eccSquared)) / (1 + Math.sqrt(1 - eccSquared));
        var N1, T1, C1, R1, D, M;
        var longOrigin;
        var mu, phi1, phi1Rad;
        //var x, y;
        var zoneNumber;
        x = x - 500000.0;
        //y = lng;


        zoneNumber = 32;
        longOrigin = (zoneNumber - 1) * 6 - 180 + 3;
        eccPrimeSquared = (eccSquared) / (1.0 - eccSquared);
        M = y / k0;
        mu = M / (a * (1.0 - eccSquared / 4 - 3 * eccSquared * eccSquared / 64 - 5 * eccSquared * eccSquared * eccSquared / 256));
        phi1Rad = mu + (3 * e1 / 2 - 27 * e1 * e1 * e1 / 32) * Math.sin(2 * mu) +
                (21 * e1 * e1 / 16 - 55 * e1 * e1 * e1 * e1 / 32) * Math.sin(4 * mu) + (151 * e1 * e1 * e1 / 96) * Math.sin(6 * mu);
        phi1 = phi1Rad * (180 / Math.PI);


        N1 = a / Math.sqrt(1 - eccSquared * Math.sin(phi1Rad) * Math.sin(phi1Rad));
        T1 = Math.tan(phi1Rad) * Math.tan(phi1Rad);
        C1 = eccPrimeSquared * Math.cos(phi1Rad) * Math.cos(phi1Rad);
        R1 = a * (1 - eccSquared) / Math.pow(1 - eccSquared * Math.sin(phi1Rad) * Math.sin(phi1Rad), 1.5);
        D = x / (N1 * k0);


        var GeoLat = phi1Rad - (N1 * Math.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);


        GeoLat = GeoLat * (180 / Math.PI);


        var GeoLong = (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) / Math.cos(phi1Rad);

        GeoLong = longOrigin + (GeoLong) * (180 / Math.PI);

        return { x: GeoLat, y: GeoLong };
    }

}
