Neither one nor Many

 
September 23 2012

I have an unfinished project with--in general--some really horrible sourcecode, but with some cool functions and solutions I came up with as well. One thing I needed for example was to calculate latitude and longitude coordinates from X and Y positions on a google maps canvas, taking zoom level into account. I could not find these conversion functions (around august 2011 anyway).

[Edit, now since May 21, 2015 Google Maps Api V3 was released, which makes it possible with the Google API. I also found an example gist here]

Aligning markers to a grid

The reason I needed these convertion functions in the first place was for creating an align feature for (custom) markers on a google maps canvas. This is how it works before/after aligning:

The (very simple) algorithm I came up with divides the map in slots. A grid with a width of 100 for example, only positions markers on 100, 200, 300, 400 pixels. In this example, the 'nearest' slot's width of a marker at position 220,50 pixels wouuld be 200.

The algorithm in pseudocode:

INITIALIZE GRID HEIGHT AND WIDTH ACCORDING TO MAP'S ZOOMLEVEL
    /* gridwidth = 100 << (21 - map.getZoom()) */
    /* gridheight = 30 << (21 - map.getZoom()) */

FOREACH MARKER

    CONVERT MARKER LAT,LON TO X,Y COORDINATES
        /* y = latToY(marker.getPosition().lat()); */
        /* x = lonToX(marker.getPosition().lng()); */

    CONVERT X,Y TO NEAREST SLOT X,Y
        /* slot_y = Math.round(y - (y % gridheight)) */
        /* slot_x = Math.round(x - (x % gridwidth)) */

    SET MARKER X,Y TO SLOT X,Y

    WHILE SLOT POSITION IS OCCUPIED BY ANOTHER MARKER

        MOVE TO NEXT SLOT POSITION
            /* Next slot position is according to a simple spiral movement [1] */

        SET MARKER X,Y TO SLOT X,Y

    ENDWHILE

    CONVERT MARKER X,Y TO LAT,LON
        /* marker.setPosition(new google.maps.LatLng(lat, lon)); */
        /* marker.setPosition(new google.maps.LatLng(lat, log)); */

    STORE SOMEWHERE THAT MARKER IS IN THIS SLOT POSITION

ENDFOREACH

[1]: The search for next slot position is according to this pattern:

up, right, down, down, left, left, up, up, up, right, right, right, etc.

  • The change of direction is continious (a spiral): {up, right, down, left, ..}
  • The number of 'steps' in each direction is {1, 1, 2, 2, .... n, n}

latToX() and lonToY()

I'm not an expert in math but I was able to find some expressions online that resolved lat+lon for x+y (the other way around). I simply replaced all the constants with their values and put them in a solver to solve them for the variables I was interested in (e.g. longitude for XtoLon). I probably have the sites bookmarked somewhere but I can't find them.

var glOffset = 268435456;
var glRadius = 85445659.4471;// offset / pi

function lonToX(lon) 
{
    var p = Math.PI / 180;
    var b = glRadius * lon;
    var c = b * p;
    return Math.round(glOffset + c);
}

function XtoLon(x) 
{
    return -180 + 0.0000006705522537 * x;
}

function latToY(lat)
{
    return Math.round(glOffset - glRadius *
            Math.log((1 + Math.sin(lat * Math.PI / 180)) /
                (1 - Math.sin(lat * Math.PI / 180))) / 2);
}

function YtoLat(y) 
{
    var e = 2.7182818284590452353602875;
    var a = 268435456;
    var b = 85445659.4471;
    var c = 0.017453292519943;

    return Math.asin(Math.pow(e,(2*a/b-2*y/b))/(Math.pow(e,(2*a/b-2*y/b))+1)-1/(Math.pow(e,(2*a/b-2*y/b))+1))/c;
}

They are not pretty but I like them because they work really well img1

Edit 10-AUG-2015: deltaLonPerDeltaX(), deltaLatPerDeltaY()

I found out somebody on Stackoverflow elaborated my functions with a deltaLonPerDeltaX() and deltaLatPerDeltaY(). The original poster's image is no longer available, so I'm not sure if I understand the question correctly, and therefore these additional functions. But there is a nice extra info cited from Google, which I will copy here:

At zoom level 1, the map consists of 4 256x256 pixels tiles, resulting in a pixel space from 512x512. At zoom level 19, each x and y pixel on the map can be referenced using a value between 0 and 256 * 2^19

(See [https://developers.google.com/maps/documentation/javascript/maptypes?hl=en#MapCoordinates][https://developers.google.com/maps/documentation/javascript/maptypes?hl=en#MapCoordinates])

Webdevelopment Comments (0)


Leave a Reply

Comment may not be visible immediately, because I process everything manually.**

**) I plan to automate this.., but it's on my ToDo since for ever..


Author:
Ray Burgemeestre
february 23th, 1984

Topics:
C++, Linux, Webdev

Other interests:
Music, Art, Zen