I’m currently working on a project to convert an existing Flash map, which uses location data that’s been manually entered and maintained, to use data that comes from a database and uses latitude and longitude values. The original data is stored in an XML file so updating it dynamically is not a problem but as you’ll know if you’ve ever tried it, plotting latitude and longitude values on a map isn’t as simple as it might sound.
Briefly, the problem arises from the fact that the world is a sphere and representing it in two dimensions is not a straightforward task. There are various ‘projections’ to choose from, each of which uses a different method for mapping points — you can find out more in this Wikipedia article. The most common choice is the Mercator projection, where lines of latitude are spaced equally, and fortunately for me it’s the type of map used in the project I’m working on.
So, being somewhat mathematically inept, I decided that Google would save me from a day’s head-scratching. That turned out not to be the case, as I tried a good half-dozen different suggestions before finally stumbling across one that actually produced accurate results. To save others from the same fate I decided to reproduce here the code I ended up with, which is based heavily on code found in this newsgroup post. My implementation is PHP, but it shouldn’t be hard to convert it to another platform (see the original thread for a Javascript implementation). Apologies for the rubbish formatting, WordPress isn’t great at handling code:
function LongitudeToX( $lat, $lon, $map_zoom, $scale_value, $x_offset = 0 ) { $offset=16777216; $radius=$offset / pi(); return ( ( ($offset+$radius*$lon*pi()/180)>>$map_zoom ) * $scale_value ) + $x_offset; } function LatitudeToY( $lat, $lon, $map_zoom, $scale_value, $y_offset = 0 ) { $offset=16777216; $radius=$offset / pi(); return ( ( ($offset-$radius*log((1+sin($lat*pi()/180))/(1-sin($lat*pi()/180)))/2)>>$map_zoom ) * $scale_value ) + $y_offset; }
A few notes about using these functions:
- From what I can tell, the above code is based on Google Maps and the $map_zoom relates in some way to the ‘zoom level’ of the map. I set it at 15 and it seemed to work OK.
- Because the dimensions of your own map might not exactly match the assumed dimensions of the map used in the calculation, the $scale_value parameter allows you to adjust the output to fit more precisely. I had to specify two decimal places of scaling to get an exact fit.
- Finally, the calculation assumes that the ‘origin point’ of the map (x=0, y=0) will be at the top, left-hand corner. This isn’t the case on the map I’m working on (the origin is at the centre) so I included $x_offset and $y_offset parameters so that I could adjust the output values accordingly.
In order to find the best values for the above parameters, I manually placed three widely-spaced temporary markers on the Flash map marking points whose latitude and longitude I already knew. Then I had the code render these points and adjusted the various parameters until the position of the generated points exactly matched the manually-placed markers.
I hope this code helps someone avoid wasting the sort of time I did yesterday!
Image may be NSFW.Clik here to view.
