The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

GD::Map::Mercator - Create Mercator projected map images using GD

SYNOPSIS

    use GD::Map::Mercator;
    #
    #    create a new basemap
    #
    my $newmap = GD::Map::Mercator->new(
        basemap_path => './basemaps',
        basemap_name => 'namer.gif',
        data_path => './WDB',
        min_lat => 15.5,
        min_long => -50,
        max_lat => 49.5,
        max_long => -26,
        width => 800,
        height => 500,
        background => '#FF0023',
        foreground => 'black',
        thickness => 3,
        silent => 1,
    );
    #
    #    or load an existing one
    #
    my $oldmap = GD::Map::Mercator->new(
        basemap_path => './basemaps',
        basemap_name => 'namer.gif'
    );
    #
    #    grab the image as an GD object
    #
    my $imager = $newmap->image();
    #
    #    draw some stuff on it
    #
    $imager->lineTo($here, $there);
    #
    #    compute some pixels from lat/long
    #
    my ($x,$y) = $newmap->project($lat, $long);
    #
    #    or compute lat/long from pixels
    #
    my ($lat, $long) = $newmap->translate($x, $y);
    #
    #    carve out a section of the map
    #
    my $submap = $newmap->extract($minlat, $minlong, $maxlat, $maxlong);
    #
    #    create a 1/2 size map
    #
    my $scaledmap = $newmap->scale(0.5);
    #
    #    and save it
    #
    $scaledmap->save('scaledmap.gif');

DESCRIPTION

Perl module for creating geographic map files with GD using a Mercator Projection.

Originally inspired by GD::Map, but significantly modified to

  • support the Mercator projection

  • optimize for performance (theres a lot of data to convert)

  • expose the map image for direct manipulation by the application

Geospatial Database

The geospatial data is sourced from the CIA World DataBank II repository at http://www.evl.uic.edu/pape/data/WDB/. Note that this database was created in the mid 1980's, so some of the political boundries are not current.

You'll need to download the WDB files and unpack them somewhere. The following files are contained in the archive:

    africa-bdy.txt
    africa-cil.txt
    africa-riv.txt
    asia-bdy.txt
    asia-cil.txt
    asia-riv.txt
    europe-bdy.txt
    europe-cil.txt
    europe-riv.txt
    namer-bdy.txt
    namer-cil.txt
    namer-pby.txt
    namer-riv.txt
    samer-bdy.txt
    samer-cil.txt
    samer-riv.txt

Once unpacked, the files need to be filtered and converted via the wdb2merc script included in this bundle. wdb2merc

  • filters out some noisy data

  • converts the latitude/longitude coordinates into Mercator projected distances (for faster loading/computation)

  • writes the results out as binary records which can be loaded much faster, and compresses the data approx. 35%

Creating Maps

Map images are rendered by specifying a bounding box defined by minimum and maximum latitude and longitudes, and the output image dimensions. The resulting image and associated configuration data can be saved for future use, avoiding the overhead of re-rendering by reloading the basemap image and its data.

To create a new basemap:

    use GD::Map::Mercator;

    my $map = GD::Map::Mercator->new(
        basemap_path => "/data/basemaps",
        basemap_name => "testing",
        data_path => "/usr/local/wdb",
        width => $width,
        height => $height,
        max_long => 162,
        min_long => 65,
        max_lat => 70,
        min_lat => 14,
        background => '#FF0023',
        foreground => 'black',
        thickness => 3,
    );

This will create testing.png and testing.conf files in /data/basemaps containing a map of the area bounded by 14 deg latitude, 65 deg longitude, and 70 deg latitude, 162 deg longitude. The resulting image will attempt a best fit for the specified $width and $height, but will adjust dimensions as needed to preserve the Mercator scaling. Note that negative latitude values are south of the equator, and negative longitude is west of the meridian (Greenwich, GB). If the maximum longitude is negative and the minimum is positive, the map is assumed to cross the antipodal meridian.

The testing.conf file contains the relevant data for the created map image.

The created base map can be reused later by using the alternate constructor:

    use GD::Map::Mercator;

    my $map = GD::Map::Mercator->new(
        basemap_path => "/data/basemaps",
        basemap_name => "testing",
    );

This constructor will attempt to initialize itself from the specified basemap file.

Using Map Images

After creating or loading a basemap image, you can extract portions of the image, rescale the image, or decorate the image directly by getting the GD::Image object (or rather, a copy of the basemap image):

    my $img = $map->image();
    

To compute pixel coordinates from latitude/longitude pairs:

    my ($x,$y) = $map->project($lat, $long);

If the specified latitude or longitude is outside the range of the map, it returns undef values. Otherwise, the results are a pixel coordinate.

As a shortcut, multiple sets of lat/long points may be specified:

    my @coords = $map->project($lat1, $long1, $lat2, $long2, $lat3, $long3, .. );

Once you have the map image, and coordinates, the usual GD methods can be used to manipulate the image.

Conversely, you can get the latitude/longitude and Mercator projected distances for given pixel coordinates:

    my ($lat,$long, $merclat, $merclong) = $map->translate($x, $y);

This might be useful for interactive mapping applications.

The basemap configuration data, including hte bounding box latitude/longitude coordiates, the Mercator projected lat/long distance (in meters), and the image dimensions can also be retrieved:

    my ($minlat, $minlong, $maxlat, $maxlong, 
        $minmerclat, $minmerclong, $maxmerclat, $maxmerclong, $width, $height) = $map->config();

The basemap can also be rescaled:

    my $newmap = $map->scale($scale);

This will create a new GD::Map::Mercator object zoomed in/out as needed, with updated configuration data.

Submaps can be extracted (and optionally scaled):

    my $newmap = $map->extract($minlat, $minlong, $maxlat, $maxlong [, $scale ]);

Once you've created a new map via scale or extract you can save it as a basemap using

    $newmap->save('mynewmap.png');

METHODS

Refer to the classdoc output for detailed method descriptions.

EXAMPLES

Some example maps can be viewed here.

SEE ALSO

This package was inspired by GD::Map, but this package uses a significantly different rendering technique, and exposes a different interface.

Geo::Mercator is used to compute the projections.

CIA World DataBank II datasets are at http://www.evl.uic.edu/pape/data/WDB/

US Zip Code Database: http://zips.sourceforge.net/

US Census TIGER/Line Data: http://www.census.gov/geo/www/tiger/

Geo::Coder::US and the several other Geo::Coder packages

AUTHOR, COPYRIGHT AND LICENSE

Dean Arnold mailto:darnold@presicient.com

Copyright(C) 2008, Dean Arnold, Presicient Corp., USA

Permission is granted to use, copy, modify, and redistribute this software under the terms of the Perl Artistic license.