Neither one nor Many
Software engineering blog about my projects, geometry, visualization and music.
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]
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.
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
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])