Geo-OSM-Tiles-0.04/0000755000175000017500000000000011373514055012025 5ustar rolfrkGeo-OSM-Tiles-0.04/TODO0000644000175000017500000000104411372746270012521 0ustar rolfrk * Build: Support Module::Build as an alternative to ExtUtils::MakeMaker. * Feature: Allow on the fly rescaling of tiles. E.g. a tile for zoom level n will be zoomed by 200% (using Image::Magick or Graphics::Magick or something alike), cut into four, and stored as four tiles of zoom level n+1. Problem: Image::Magick or Graphics::Magick is quite a heavy prerequisite given that Geo::OSM::Tiles is also used on handheld devices. Consider to make this feature configurable at build time. # Local Variables: # mode: text # End: Geo-OSM-Tiles-0.04/downloadosmtiles.pl0000644000175000017500000002602011373511467015755 0ustar rolfrk#! perl use 5.006001; use strict; use warnings; use Geo::OSM::Tiles qw( :all ); use LWP::UserAgent; use YAML qw( DumpFile LoadFile ); use File::Path; use File::Basename; use File::Spec; use Cwd qw(cwd); use Getopt::Long; our $linkrgoffs = 350.0; our $usage = qq{Usage: $0 --latitude=d[:d] --longitude=d[:d] --zoom=z[:z] [--quiet] [--baseurl=url] [--destdir=dir] [--dumptilelist=filename] $0 --link=url [--latitude=d[:d]] [--longitude=d[:d]] [--zoom=z[:z]] [--quiet] [--baseurl=url] [--destdir=dir] [--dumptilelist=filename] $0 --loadtilelist=filename }; our %opt = ( latitude => undef, longitude => undef, zoom => undef, link => undef, quiet => undef, baseurl => "http://tile.openstreetmap.org", destdir => cwd, dumptilelist => undef, loadtilelist => undef, ); die "$usage\n" unless GetOptions(\%opt, "latitude=s", "longitude=s", "zoom=s", "link=s", "quiet", "baseurl=s", "destdir=s", "dumptilelist=s", "loadtilelist=s") && @ARGV == 0; sub selecttilescmdline; sub downloadtiles; sub parserealopt; sub parseintopt; sub downloadtile; # List of tiles scheduled for download. # Format: # $tilelist = { # zoomlevel => [ # { # xyz => [ tx, ty, tz ], # }, # { # xyz => [ tx, ty, tz ], # }, # ... # ], # zoomlevel => [ # { # xyz => [ tx, ty, tz ], # }, # { # xyz => [ tx, ty, tz ], # }, # ... # ], # ... # }; our $tilelist; # In the current version we keep things simple, the tiles have to be # selected either by the command line options --link, --lat, --lon, # and --zoom or read from the file as given by --loadtilelist. In a # future version, it might be possible to combine both ways. if ($opt{loadtilelist}) { $tilelist = LoadFile($opt{loadtilelist}); } else { $tilelist = selecttilescmdline; } our $baseurl = $opt{baseurl}; our $destdir = $opt{destdir}; if ($opt{dumptilelist}) { DumpFile($opt{dumptilelist}, $tilelist); } else { downloadtiles($tilelist); } # Select tiles from command line options sub selecttilescmdline { if ($opt{link}) { die "Invalid link: $opt{link}\n" unless $opt{link} =~ /^http:\/\/.*\/\?lat=(-?\d+(?:\.\d+)?)\&lon=(-?\d+(?:\.\d+)?)\&zoom=(\d+)/; my $lat = $1; my $lon = $2; my $zoom = $3; my $offs = $linkrgoffs / 2**$zoom; # Note that ($lat - $offs, $lat + $offs) or # ($lon - $offs, $lon + $offs) may get out of the acceptable # range of coordinates. This will eventually get corrected by # checklatrange or checklonrange later on. $opt{latitude} = [ $lat - $offs, $lat + $offs ] unless defined($opt{latitude}); $opt{longitude} = [ $lon - $offs, $lon + $offs ] unless defined($opt{longitude}); $opt{zoom} = $zoom unless defined($opt{zoom}); } my ($latmin, $latmax) = checklatrange(parserealopt("latitude")); my ($lonmin, $lonmax) = checklonrange(parserealopt("longitude")); my ($zoommin, $zoommax) = parseintopt("zoom"); my $tl = {}; for my $zoom ($zoommin..$zoommax) { my $txmin = lon2tilex($lonmin, $zoom); my $txmax = lon2tilex($lonmax, $zoom); # Note that y=0 is near lat=+85.0511 and y=max is near # lat=-85.0511, so lat2tiley is monotonically decreasing. my $tymin = lat2tiley($latmax, $zoom); my $tymax = lat2tiley($latmin, $zoom); my $ntx = $txmax - $txmin + 1; my $nty = $tymax - $tymin + 1; printf "Schedule %d (%d x %d) tiles for zoom level %d for download ...\n", $ntx*$nty, $ntx, $nty, $zoom unless $opt{quiet}; $tl->{$zoom} = []; for my $tx ($txmin..$txmax) { for my $ty ($tymin..$tymax) { push @{$tl->{$zoom}}, { xyz => [ $tx, $ty, $zoom ] }; } } } return $tl; } sub downloadtiles { my $tiles = shift; my $lwpua = LWP::UserAgent->new; $lwpua->env_proxy; for my $zoom (sort {$a <=> $b} keys %$tiles) { printf "Download %d tiles for zoom level %d ...\n", scalar(@{$tiles->{$zoom}}), $zoom unless $opt{quiet}; for my $t (@{$tiles->{$zoom}}) { downloadtile($lwpua, @{$t->{xyz}}); } } } sub parserealopt { my ($optname) = @_; die "$optname must be specified in the command line.\n" unless defined($opt{$optname}); if (ref($opt{$optname})) { return @{$opt{$optname}}; } else { die "Invalid $optname: $opt{$optname}\n" unless $opt{$optname} =~ /^(-?\d+(?:\.\d+)?)(?::(-?\d+(?:\.\d+)?))?$/; my ($min, $max) = ($1, $2); $max = $min unless defined($max); return ($min, $max); } } sub parseintopt { my ($optname) = @_; die "$optname must be specified in the command line.\n" unless defined($opt{$optname}); if (ref($opt{$optname})) { return @{$opt{$optname}}; } else { die "Invalid $optname: $opt{$optname}\n" unless $opt{$optname} =~ /^(\d+)(?::(\d+))?$/; my ($min, $max) = ($1, $2); $max = $min unless defined($max); return ($min, $max); } } sub downloadtile { my ($lwpua, $tilex, $tiley, $zoom) = @_; my $path = tile2path($tilex, $tiley, $zoom); my $url = "$baseurl/$path"; my @pathcomp = split /\//, $path; my $fname = File::Spec->catfile($destdir, @pathcomp); mkpath(dirname($fname)); my $res = $lwpua->get($url, ':content_file' => $fname); die $res->status_line unless $res->is_success; } __END__ =head1 NAME downloadosmtiles.pl - Download map tiles from OpenStreetMap =head1 SYNOPSIS downloadosmtiles.pl --lat=49.5611:49.6282 --lon=10.951:11.0574 --zoom=13:14 downloadosmtiles.pl --link='http://www.openstreetmap.org/?lat=-23.5872&lon=-46.6508&zoom=12&layers=B000FTF' downloadosmtiles.pl --loadtilelist=filename =head1 DESCRIPTION This script downloads all map tiles from an OpenStreetMap tile server for some geographic region in a range of zoom levels. The PNG images of the tiles are stored in a directory tree that mirrors the paths from the server. A bounding box of geographic coordinates and a range of zoom levels must be selected by command line options. =head1 COMMAND LINE OPTIONS Command line options may be abbreviated as long as they remain unambiguous. At least either C<--latitude>, C<--longitude>, and C<--zoom> or C<--link> must be specified. =head2 C<--latitude=latmin[:latmax]> Selects the latitude of the bounding box of coordinates to download. May be one single real value or two real values separated by a colon in the range C<-85.0511..85.0511>. If given only one value, just the tile (or row of tiles) at this latitude will be downloaded. Default: none =head2 C<--longitude=lonmin[:lonmax]> Selects the longitude of the bounding box of coordinates to download. May be one single real value or two real values separated by a colon in the range C<-180.0..180.0>. If given only one value, just the tile (or column of tiles) at this longitude will be downloaded. Default: none =head2 C<--zoom=zoommin[:zoommax]> Selects the range of zoom levels to download the map tiles for. May be one single integer value or two integer values separated by a colon. OpenStreetMap supports zoom levels in the range C<0..18>. (This depends on the base URL and is not enforced by this script.) Note that the number of tiles to download grows by a factor of up to four with each zoom level. Default: none =head2 C<--link=url> An URL selecting C<--latitude>, C<--longitude>, and C<--zoom> in one argument. The idea is to select the current view of OSM's slippy map by its permalink. The argument to C<--link> must be an URL containing the HTTP options C. (Actually, the base URL will be ignored.) The script chooses a box around the latitude and longitude options. The size of the box depends on the zoom option. If combined with C<--latitude>, C<--longitude>, or C<--zoom>, these explicitly specified values override the implicitly specified values from C<--link>. Default: none =head2 C<--baseurl=url> The base URL of the server to download the tiles from. Default: L (This is the base URL for the Mapnik tiles.) =head2 C<--destdir=dir> The directory where the tiles will be stored. The PNG files will be stored as C. Default: The current working directory. =head2 C<--quiet> Do not write any diagnostic messages. Only fatal errors will be reported. =head2 C<--dumptilelist=filename> Do not download any tiles at all, but write a list of tiles as selected by other command line options to the file named C. See L below. =head2 C<--loadtilelist=filename> Read a list of tiles to download from the file C. See L below. =head1 EXAMPLE Select the region of interest in OSM's slippy map and follow the permalink in the lower left of the window. Lets assume this permalink to be L. Then downloadosmtiles.pl --link='http://www.openstreetmap.org/?lat=49.5782&lon=11.0076&zoom=12&layers=B000FTF' --zoom=5:18 will download all tiles from zoom level 5 to 18 for this region. =head1 TILE LISTS A list of tiles may be stored to and retrieved from external files using the C<--dumptilelist> and C<--loadtilelist> command line options. A set of tiles may be selected using the command line options C<--latitude>, C<--longitude>, C<--zoom>, and C<--link> and written to a file specified with C<--dumptilelist>. This list may be read at a later date using the C<--loadtilelist> option. This may be useful to postpone the download of the tiles, to edit the list of tiles, or to use some external tool to generate this list. The tile lists are read and written in L format. Please note that this is an experimental feature in the current version. The file format is not considered stable yet. There is no guarantee that a list of tiles generated by one version of this script may be read in by a future version. =head1 ENVIRONMENT =over =item http_proxy =item ftp_proxy =item xxx_proxy =item no_proxy These environment variables can be set to enable communication through a proxy server. This is implemented by L. =back =head1 BUGS =over =item * Ranges in the command line options must always be increasing. While this is considered a feature for C<--latitude> and C<--zoom>, it means that it is impossible for a range in the C<--longitude> argument to cross the 180 degree line. A command line option like C<--longitude=179.5:-179.5> will not work as one should expect. =item * The bounding box selected by the C<--link> command line option does not always correspond to the current view in the slippy map. The problem is that the permalink from the slippy map only contains one position and not the bounds of the current view. The actual view of the slippy map depends on many factors, including the size of the browser window. Thus, there is not much that can be done about this issue. =back =head1 SEE ALSO L =head1 AUTHOR Rolf Krahl Erotkraut@cpan.orgE =head1 COPYRIGHT AND LICENCE Copyright (C) 2008-2010 by Rolf Krahl This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.8 or, at your option, any later version of Perl 5 you may have available. =cut Geo-OSM-Tiles-0.04/t/0000755000175000017500000000000011373514045012267 5ustar rolfrkGeo-OSM-Tiles-0.04/t/00-signature.t0000644000175000017500000000214411372746262014702 0ustar rolfrk#! /usr/bin/perl use strict; use warnings; use Test::More; # This test script was taken from Module::Signature version 0.63, see # http://search.cpan.org/dist/Module-Signature/ for details. if (!$ENV{TEST_SIGNATURE}) { plan skip_all => "Set the environment variable TEST_SIGNATURE to enable this test."; } elsif (!eval { require Module::Signature; 1 }) { plan skip_all => "Next time around, consider installing Module::Signature, ". "so you can verify the integrity of this distribution."; } elsif ( !-e 'SIGNATURE' ) { plan skip_all => "SIGNATURE not found"; } elsif ( -s 'SIGNATURE' == 0 ) { plan skip_all => "SIGNATURE file empty"; } elsif (!eval { require Socket; Socket::inet_aton('pool.sks-keyservers.net') }) { plan skip_all => "Cannot connect to the keyserver to check module ". "signature"; } else { plan tests => 1; } my $ret = Module::Signature::verify(); SKIP: { skip "Module::Signature cannot verify", 1 if $ret eq Module::Signature::CANNOT_VERIFY(); cmp_ok $ret, '==', Module::Signature::SIGNATURE_OK(), "Valid signature"; } Geo-OSM-Tiles-0.04/t/10-Geo-OSM-Tiles.t0000644000175000017500000000375111372746263015134 0ustar rolfrk#! /usr/bin/perl use strict; use warnings; use Test::More tests => 74; BEGIN { use_ok('Geo::OSM::Tiles', qw(:all)) }; # Simple tests of well known values. { # 2..4 my $zoom = 13; my $lat = 49.60055; my $lon = 11.01296; my $tilex = lon2tilex($lon, $zoom); is($tilex, 4346, "tile x at lon = $lon, zoom = $zoom"); my $tiley = lat2tiley($lat, $zoom); is($tiley, 2792, "tile y at lat = $lat, zoom = $zoom"); my $path = tile2path($tilex, $tiley, $zoom); is($path, '13/4346/2792.png', "path"); } # Simple consistency test for zooming: # tile numbers must get halved when zooming out one level. { # 5..38 # At this position we get all possible combinations of even and # odd tile numbers throughout the different zoom levels. my $lat = -33.84122; my $lon = 108.00000; my $zoom = 18; my $tilex = lon2tilex($lon, $zoom); my $tiley = lat2tiley($lat, $zoom); while ($zoom > 1) { my $otx = $tilex; my $oty = $tiley; $zoom--; $tilex = lon2tilex($lon, $zoom); is($tilex, int($otx / 2), "tile x at lon = $lon, zoom = $zoom"); $tiley = lat2tiley($lat, $zoom); is($tiley, int($oty / 2), "tile y at lat = $lat, zoom = $zoom"); } } # Check the bound checking in checklonrange and checklatrange. { # 39..74 # A range of coordinates that is out of bounds for sure. my @hugerange = (-1000.0, 1000.0); for my $zoom (0, 1, 2, 5, 10, 15, 18, 20, 30) { # 4 tests per zoom level my $max = 2**$zoom-1; my ($lonmin, $lonmax) = checklonrange(@hugerange); my ($xmin, $xmax) = map { lon2tilex($_, $zoom) } ($lonmin, $lonmax); is($xmin, 0, "\$xmin at zoom = $zoom"); is($xmax, $max, "\$xmax at zoom = $zoom"); # Note that lat2tiley is decreasing, # so $ymin = lat2tiley($latmax, $zoom). my ($latmin, $latmax) = checklatrange(@hugerange); my ($ymax, $ymin) = map { lat2tiley($_, $zoom) } ($latmin, $latmax); is($ymin, 0, "\$ymin at zoom = $zoom"); is($ymax, $max, "\$ymax at zoom = $zoom"); } } # Local Variables: # mode: perl # End: Geo-OSM-Tiles-0.04/t/20-downloadosmtiles.t0000644000175000017500000001413711373511535016271 0ustar rolfrk#! /usr/bin/perl use strict; use warnings; use Test::More; # Check whether we can reach the tile server first. Otherwise it # makes no sense to try testing the script. use LWP::UserAgent; eval { my $testurl = 'http://tile.openstreetmap.org/0/0/0.png'; my $lwpua = LWP::UserAgent->new; $lwpua->env_proxy; my $res = $lwpua->get($testurl); die $res->status_line unless $res->is_success; }; if ($@) { plan skip_all => "could not reach tile server: $@"; } else { plan tests => 3 * 3 + 19; } use Config; use Cwd qw(abs_path); use File::Temp qw(tempdir); use File::Spec; use File::Find; use YAML qw( DumpFile LoadFile ); # you may switch off $cleanup for debugging this test script. our $cleanup = 1; # Hack 1: # Problem in ExtUtils::Command::MM: the test_harness subroutine in # ExtUtils::Command::MM fails to put the @test_libs arguments into # $ENV{PERLLIB} in order to communicate this information to child # processes. Ugly, quick and dirty work around: Assume @test_libs to # be ('blib/lib', 'blib/arch'). $ENV{PERLLIB} = abs_path('blib/lib') . ":" . abs_path('blib/arch') . ( $ENV{PERLLIB} ? ":$ENV{PERLLIB}" : "" ); # Hack 2: # Is there any official way to know where the scripts will be placed # during the test phase? our $downloadosmtiles = abs_path('blib/script/downloadosmtiles.pl'); sub countpng; sub cleantmp; our $perl = $Config{perlpath}; our $testdir = tempdir( CLEANUP => $cleanup ); our $tilelistfile = File::Spec->catfile($testdir, "tilelist"); our $pngcount; our $dubiouscount; # check whether the script is properly placed where we expect it do be. # 1 test ok(-e $downloadosmtiles, "downloadosmtiles.pl is present"); # download single tiles for a bunch of positions # 3 * 3 + 1 tests { my $subtestdir = File::Spec->catdir($testdir, "t1"); ok( mkdir($subtestdir), "create subtestdir" ); my @positions = ( { LAT => "0", LON => "0", ZOOM => "0", }, { LAT => "5.0", LON => "-10.0", ZOOM => "2", }, { LAT => "-41.272", LON => "174.863", ZOOM => "9", }, ); for (@positions) { my $lat = $_->{LAT}; my $lon = $_->{LON}; my $zoom = $_->{ZOOM}; my @args = ( $downloadosmtiles, "--latitude=$lat", "--longitude=$lon", "--zoom=$zoom", "--quiet", "--destdir=$subtestdir" ); @args = map { "\"$_\"" } @args if $^O =~ /^mswin/i; my $res = system($perl, @args); is($res, 0, "return value from downloadosmtiles.pl"); $pngcount = 0; find(\&countpng, File::Spec->catdir($subtestdir, $zoom)); is($pngcount, 1, "number of dowloaded tiles"); $dubiouscount = 0; find({ wanted => \&cleantmp, bydepth => 1, no_chdir => 1 }, $subtestdir) if $cleanup; ok(!$dubiouscount, "dubious files found"); } } # test --link option # 9 tests { my $subtestdir = File::Spec->catdir($testdir, "t2"); ok( mkdir($subtestdir), "create subtestdir" ); my $link = 'http://openstreetmap.org/?lat=14.692&lon=-17.448&zoom=11&layers=B000FTF'; my @args = ( $downloadosmtiles, "--link=$link", "--zoom=11:13", "--quiet", "--destdir=$subtestdir" ); @args = map { "\"$_\"" } @args if $^O =~ /^mswin/i; my $res = system($perl, @args); is($res, 0, "return value from downloadosmtiles.pl"); $pngcount = 0; find(\&countpng, File::Spec->catdir($subtestdir, "11")); cmp_ok($pngcount, '>=', 9, "number of dowloaded tiles"); cmp_ok($pngcount, '<=', 16, "number of dowloaded tiles"); my $oldcount = $pngcount; $pngcount = 0; find(\&countpng, File::Spec->catdir($subtestdir, "12")); cmp_ok($pngcount, '>=', $oldcount, "number of dowloaded tiles"); cmp_ok($pngcount, '<=', 4*$oldcount, "number of dowloaded tiles"); $oldcount = $pngcount; $pngcount = 0; find(\&countpng, File::Spec->catdir($subtestdir, "13")); cmp_ok($pngcount, '>=', $oldcount, "number of dowloaded tiles"); cmp_ok($pngcount, '<=', 4*$oldcount, "number of dowloaded tiles"); $dubiouscount = 0; find({ wanted => \&cleantmp, bydepth => 1, no_chdir => 1 }, $subtestdir) if $cleanup; ok(!$dubiouscount, "dubious files found"); } # test --dumptilelist option # 3 tests { my @args = ( $downloadosmtiles, "--lat=51.5908:51.5974", "--lon=9.9537:9.9645", "--zoom=15:16", "--dumptilelist=$tilelistfile", "--quiet" ); @args = map { "\"$_\"" } @args if $^O =~ /^mswin/i; my $res = system($perl, @args); is($res, 0, "return value from downloadosmtiles.pl"); my $expectedtilelist = { 15 => [ { xyz => [ 17290, 10883, 15 ], }, ], 16 => [ { xyz => [ 34580, 21766, 16 ], }, { xyz => [ 34580, 21767, 16 ], }, { xyz => [ 34581, 21766, 16 ], }, { xyz => [ 34581, 21767, 16 ], }, ], }; my $tilelist = LoadFile($tilelistfile); isa_ok( $tilelist, 'HASH', "loaded tile list" ); is_deeply( $tilelist, $expectedtilelist, "loaded tile list" ); } # test --loadtilelist option # 5 tests { my $subtestdir = File::Spec->catdir($testdir, "t4"); ok( mkdir($subtestdir), "create subtestdir" ); my @args = ( $downloadosmtiles, "--loadtilelist=$tilelistfile", "--quiet", "--destdir=$subtestdir" ); @args = map { "\"$_\"" } @args if $^O =~ /^mswin/i; my $res = system($perl, @args); is($res, 0, "return value from downloadosmtiles.pl"); # We loaded the tile list created by the --dumptilelist test # above. We should find the tiles as listed in $expectedtilelist # downloaded to $subtestdir now. $pngcount = 0; find(\&countpng, File::Spec->catdir($subtestdir, 15)); is($pngcount, 1, "number of dowloaded tiles"); $pngcount = 0; find(\&countpng, File::Spec->catdir($subtestdir, 16)); is($pngcount, 4, "number of dowloaded tiles"); $dubiouscount = 0; find({ wanted => \&cleantmp, bydepth => 1, no_chdir => 1 }, $subtestdir) if $cleanup; ok(!$dubiouscount, "dubious files found"); } sub countpng { if ($_ =~ /^\d+\.png$/) { unlink($_) if $cleanup; $pngcount++; } } sub cleantmp { if (-d $_) { rmdir($_) if $_ ne $testdir; } else { diag("dubious file $File::Find::name"); $dubiouscount++; unlink($_); } } # Local Variables: # mode: perl # End: Geo-OSM-Tiles-0.04/README0000644000175000017500000000353111373513101012676 0ustar rolfrkGeo-OSM-Tiles ============= Geo::OSM::Tiles - Calculate tile numbers for OpenStreetMap This module provides functions for calculating the path to a map tile at OpenStreetMap out of geographic coordinates. It contains the script downloadosmtiles.pl that downloads all map tiles from an OpenStreetMap tile server for some geographic region in a range of zoom levels. PREREQUISITES This module requires these other modules and libraries: Math::Trig LWP Getopt::Long YAML File::Path File::Basename File::Spec Cwd Test::More File::Temp File::Find Note that all but LWP and YAML are core modules in Perl 5.8 and later. In order to verify the signature of the distribution, you furthermore need Module::Signature INSTALLATION You might want to verify the signature of the distribution first, see below. To install this module type the following: perl Makefile.PL make make test make install SIGNATURE This distribution is cryptographically signed using the following key: pub 1024D/FDCF7486 2010-04-03 Key fingerprint = 342E 56B5 F5B3 6A34 9BE3 82DD C1D4 D7E2 FDCF 7486 uid Rotkraut CPAN Package Signing Key To verify the signature type the following: cpansign -v See the instructions in the file SIGNATURE and the man page of cpansign for details. AUTHOR Rolf Krahl The latest release of this module can be found at CPAN, see http://search.cpan.org/dist/Geo-OSM-Tiles/. The project is hosted at BerliOS, see the project page at http://geo-osm-tiles.berlios.de/. COPYRIGHT AND LICENCE Copyright (C) 2008-2010 by Rolf Krahl This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.8 or, at your option, any later version of Perl 5 you may have available. Geo-OSM-Tiles-0.04/lib/0000755000175000017500000000000011373514045012572 5ustar rolfrkGeo-OSM-Tiles-0.04/lib/Geo/0000755000175000017500000000000011373514045013304 5ustar rolfrkGeo-OSM-Tiles-0.04/lib/Geo/OSM/0000755000175000017500000000000011373514045013742 5ustar rolfrkGeo-OSM-Tiles-0.04/lib/Geo/OSM/Tiles.pm0000644000175000017500000000777711373512151015376 0ustar rolfrkpackage Geo::OSM::Tiles; use 5.006001; use strict; use warnings; use Math::Trig; =head1 NAME Geo::OSM::Tiles - Calculate tile numbers for OpenStreetMap =head1 SYNOPSIS use Geo::OSM::Tiles qw( :all ); $zoom = 13; $lat = 49.60055; $lon = 11.01296; $tilex = lon2tilex($lon, $zoom); $tiley = lat2tiley($lat, $zoom); $path = tile2path($tilex, $tiley, $zoom); $tileurl = "http://tile.openstreetmap.org/$path"; =head1 DESCRIPTION This module provides functions for calculating the path to a map tile at OpenStreetMap out of geographic coordinates. The path of a tile at OSM has the form C<$zoom/$tilex/$tiley.png>. The numbering scheme is documented in the OSM wiki, see the link below. =cut require Exporter; our $VERSION = '0.04'; our @ISA = qw(Exporter); our %EXPORT_TAGS = ( 'all' => [ qw( lon2tilex lat2tiley tile2path checklonrange checklatrange ) ] ); our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); our @EXPORT = qw(); =head2 C Returns C<$tilex> for the tile at longitude C<$lon> and zoom level C<$zoom>. The longitude must be in the range C<-180.0 <= $lon < 180.0>. The zoom level must be a non-negative integer. =cut sub lon2tilex { my ($lon, $zoom) = @_; return int( ($lon+180)/360 * 2**$zoom ); } =head2 C Returns C<$tiley> for the tile at latitude C<$lat> and zoom level C<$zoom>. The latitude must be in the range C<-85.0511 <= $lat <= 85.0511>. The zoom level must be a non-negative integer. =cut sub lat2tiley { my ($lat, $zoom) = @_; my $lata = $lat*pi/180; return int( (1 - log(tan($lata) + sec($lata))/pi)/2 * 2**$zoom ); } =head2 C Composes the path to the tile at C<$tilex>, C<$tiley>, and C<$zoom> at the OSM server. C<$tilex> and C<$tiley> must be integers in the range C<0..2**$zoom-1>. The supported range of zoom levels depends on the tile server. The maximum zoom for the Osmarender layer is 17, it is 18 for the Mapnik layer. =cut sub tile2path { my ($tilex, $tiley, $zoom) = @_; return "$zoom/$tilex/$tiley.png"; } =head2 C Checks whether C<$lonmin> and C<$lonmax> are within the allowed range of the longitude argument to C. Returns C<($lonmin, $lonmax)> unchanged if they are ok or corrected values if not. =cut sub checklonrange { my ($lonmin, $lonmax) = @_; # The bounds are choosen such that they give the correct results up # to zoom level 30 (zoom levels up to 18 actually make sense): # lon2tilex(-180.0, 30) == 0 # lon2tilex(179.9999999, 30) == 1073741823 == 2**30 - 1 $lonmin = -180.0 if $lonmin < -180.0; $lonmin = 179.9999999 if $lonmin > 179.9999999; $lonmax = -180.0 if $lonmax < -180.0; $lonmax = 179.9999999 if $lonmax > 179.9999999; return ($lonmin, $lonmax); } =head2 C Checks whether C<$latmin> and C<$latmax> are within the allowed range of the latitude argument to C. Returns C<($latmin, $latmax)> unchanged if they are ok or corrected values if not. =cut sub checklatrange { my ($latmin, $latmax) = @_; # The bounds are choosen such that they give the correct results up # to zoom level 30 (zoom levels up to 18 actually make sense): # lat2tiley(85.0511287798, 30) == 0 # lat2tiley(-85.0511287798, 30) == 1073741823 == 2**30 - 1 $latmin = -85.0511287798 if $latmin < -85.0511287798; $latmin = 85.0511287798 if $latmin > 85.0511287798; $latmax = -85.0511287798 if $latmax < -85.0511287798; $latmax = 85.0511287798 if $latmax > 85.0511287798; return ($latmin, $latmax); } 1; __END__ =head1 SEE ALSO L =head1 AUTHOR Rolf Krahl Erotkraut@cpan.orgE =head1 COPYRIGHT AND LICENCE Copyright (C) 2008-2010 by Rolf Krahl This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.8 or, at your option, any later version of Perl 5 you may have available. =cut Geo-OSM-Tiles-0.04/MANIFEST0000644000175000017500000000046211373514046013160 0ustar rolfrkChanges MANIFEST Makefile.PL README TODO downloadosmtiles.pl lib/Geo/OSM/Tiles.pm t/00-signature.t t/10-Geo-OSM-Tiles.t t/20-downloadosmtiles.t META.yml Module meta-data (added by MakeMaker) SIGNATURE Public-key signature (added by MakeMaker) Geo-OSM-Tiles-0.04/Makefile.PL0000644000175000017500000000147511373014731014002 0ustar rolfrkuse 5.006001; use ExtUtils::MakeMaker; WriteMakefile( NAME => 'Geo::OSM::Tiles', ABSTRACT_FROM => 'lib/Geo/OSM/Tiles.pm', AUTHOR => 'Rolf Krahl ', VERSION_FROM => 'lib/Geo/OSM/Tiles.pm', LICENSE => 'perl', PREREQ_PM => { # Needed by the module Geo::OSM::Tiles Math::Trig => 0, # Needed by the script downloadosmtiles.pl LWP => 0, Getopt::Long => 0, YAML => 0, File::Path => 0, File::Basename => 0, File::Spec => 0, Cwd => 0, # Needed by the test suite Test::More => 0, File::Temp => 0, File::Find => 0, }, EXE_FILES => [ 'downloadosmtiles.pl' ], PM => { 'lib/Geo/OSM/Tiles.pm' => '$(INST_LIBDIR)/Tiles.pm'}, (MM->can('signature_target') ? (SIGN => 1) : ()), ); Geo-OSM-Tiles-0.04/SIGNATURE0000644000175000017500000000255611373514055013321 0ustar rolfrkThis file contains message digests of all files listed in MANIFEST, signed via the Module::Signature module, version 0.63. To verify the content in this distribution, first make sure you have Module::Signature installed, then type: % cpansign -v It will check each file's integrity, as well as the signature's validity. If "==> Signature verified OK! <==" is not displayed, the distribution may already have been compromised, and you should not run its Makefile.PL or Build.PL. -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 SHA1 b541077f3ba2d01da3a737ec408d8cf332d19171 Changes SHA1 914826745584ce387c3aaa00b3f9f554f2650690 MANIFEST SHA1 e33b3735b5d98b9e9be4689f5ec5085c6195d6de META.yml SHA1 616de6bb33aa5f77532989890a0b6ff696c76fab Makefile.PL SHA1 98ae5c4841a25f060f41f057b65f2a43d2e65c94 README SHA1 2e15ea693fd3c691b89e4ce420cad0d3ba466f5a TODO SHA1 8f15981715c05db306674acd29c8aa381a92f855 downloadosmtiles.pl SHA1 7f3166beafba2a33e4c8aea874b4998e5d4aef20 lib/Geo/OSM/Tiles.pm SHA1 c407042d589675d4d2444df9e09bc1ccd2421ef4 t/00-signature.t SHA1 2ee5cd034f1b77c97d9905a3f4da59f91ec4de15 t/10-Geo-OSM-Tiles.t SHA1 0ebffc67a63a30ff6c1335657c179ed7baf04fb6 t/20-downloadosmtiles.t -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.9 (GNU/Linux) iEYEARECAAYFAkvumC0ACgkQwdTX4v3PdIaaJACfUEc7lfyzMQN/plG27On13wlZ YhsAnAjdc40+6KfU/BCC7WvsfFgYfzO+ =AuLl -----END PGP SIGNATURE----- Geo-OSM-Tiles-0.04/META.yml0000644000175000017500000000146711373514046013306 0ustar rolfrk--- #YAML:1.0 name: Geo-OSM-Tiles version: 0.04 abstract: Calculate tile numbers for OpenStreetMap license: perl author: - Rolf Krahl generated_by: ExtUtils::MakeMaker version 6.42 distribution_type: module requires: Cwd: 0 File::Basename: 0 File::Find: 0 File::Path: 0 File::Spec: 0 File::Temp: 0 Getopt::Long: 0 LWP: 0 Math::Trig: 0 Test::More: 0 YAML: 0 meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.3.html version: 1.3 Geo-OSM-Tiles-0.04/Changes0000644000175000017500000000216211373512657013327 0ustar rolfrkRevision history for Perl extension Geo::OSM::Tiles. 0.04 2010-05-15 - Added command line options --dumptilelist and --loadtilelist to downloadosmtiles.pl to read and write the list of tiles selected for download. - Portability fix in the test scripts. 0.03 2010-04-05 - Portability fixes: use File::Spec to compose file names, fix passing of command line arguments to the script under MSWin32 (thanks to Ekkehard Horner for the hint). Note that i do not have access to other platforms then Linux for testing. I have to rely on the reports from CPAN testers for any portability issues. Thanks folks, your input is greatly appreciated! - Sign the distribution using Module::Signature. - Some minor fixes in the test scripts. - Some documentation fixes. 0.02 2008-12-30 - downloadosmtiles.pl: fixes in parsing command line options. - downloadosmtiles.pl: diagnostic messages about how many tiles are to be downloaded. May be switched off by new command line option --quiet. - More tests. - Cleanup in dependencies. - Some documentation fixes. 0.01 2008-11-30 - initial version.