10
votes

I'm trying to develop a page in ASP.NET that will act as a tile-server for a Google Map

It will pull a collection of latitude/longitude points from the database, then render them as small red dots on a transparent background, given a zoom-level (default: 15).

It will then return the result as a GIF-type image.

Have any algorithms or libraries been developed that allow me to take this set of latitudes/longitudes and convert them to a set of 2D pixel co-ordinates, given a zoom level?

(This is all being done server-side, so I can't use the Google Maps API.)


Update: Found a code-sample in Perl that does something similar:

http://blog.barros.ws/2009/03/06/convert-lat-lng-and-zoom-values-to-pixel-xy-on-a-map/

Trouble is, I don't know Perl, and don't really have the time to crack open a book and learn it.

Can anyone help me to decipher what's going on in this function?

sub Google_Coord_to_Pix
{
    my $value   = shift ;
    my $lat = shift ;
    my $lng = shift ;
    my @d       = ( ) ; 
    my $e       = 0 ;

    $d[1] = sprintf("%0.0f", $$value{'bmO'} + $lng * $$value{'pixLngDeg'} ) ;

    $e = sin($lat * $$value{'Wa'}) ;

    if( $e > 0.99999 )
    {
        $e = 0.99999 ;
    }

    if( $e < -0.99999 )
    {
        $e = -0.99999 ;
    }

    $d[0] = sprintf("%0.0f", $$value{'bmO'} + 0.5 * log((1 + $e) / (1 - $e)) * (-1) * $$value{'pixLngRad'} ) ;

    return (@d) ;
}
2

2 Answers

10
votes

Here's some code I'm currently using. It's in PHP.

// Returns longitude in pixels at a certain zoom level
function lonToX($lon, $zoom) {
    $offset = 256 << ($zoom-1);
    return round($offset + ($offset * $lon / 180));
}
// Returns latitude in pixels at a certain zoom level
function latToY($lat, $zoom) {
    $offset = 256 << ($zoom-1);
    return round($offset - $offset/pi() * log((1 + sin($lat * pi() / 180)) / (1 - sin($lat * pi() / 180))) / 2);
}

Based on code from this page, written by this guy.

Good luck!

Update: This map is a great way to help understand how tiles work in Google Maps

Edit: Here's an equivalent set of functions in VB.NET:

Public Function LonToX(Lon As Double, Zoom as UInteger) As UInteger
    Dim Offset = 256 << (Zoom - 1)
    Return Math.Round(Offset + (Offset * Lon / 180))
End Function

Public Function LatToY(Lat As Double, Zoom as UInteger) As UInteger
    Dim Offset = 256 << (Zoom - 1)
    Return Math.Round(Offset - Offset / Math.Pi * Math.Log((1 + Math.Sin(Lat * Math.Pi / 180)) / (1 - Math.Sin(Lat * Math.Pi / 180))) / 2)
End Function

And in C#:

public uint lonToX(double lon, uint zoom) {
    uint offset = 256 << (zoom - 1);
    return Math.Round(offset + (offset * lon / 180));
}

public uint latToY(double lat, uint zoom) {
    uint offset = 256 << (zoom - 1);
    return Math.Round(offset - offset / Math.Pi * Math.Log((1 + Math.Sin(lat * Math.Pi / 180)) / (1 - Math.Sin(lat * Math.Pi / 180))) / 2);
}
2
votes

"If it is a Mercator projection, you shouldn't need to worry about the curvature of the earth since all of the lat/lon lines are at equal spacing"

Perhaps you're thinking of the Geographic (aka Plate Carree) projection? The Mercator projection does have equally spaced lines of longitude, but does not have equally spaced lines of latitude (lat = atan(sinh(y)), so 90° is at infinity).

BTW, the math for the Mercator projection on a sphere is here, but if Google Maps is using the WGS84 ellipsoid and you need to get it exact it gets more complicated. In that case, I'd look at this, but beware: it's not for the faint of heart.