File Coverage

blib/lib/Geo/OSM/Tiles.pm
Criterion Covered Total %
statement 31 31 100.0
branch 8 16 50.0
condition n/a
subroutine 9 9 100.0
pod 5 5 100.0
total 53 61 86.8


line stmt bran cond sub pod time code
1             package Geo::OSM::Tiles;
2              
3 1     1   27372 use 5.006001;
  1         3  
  1         33  
4 1     1   5 use strict;
  1         3  
  1         40  
5 1     1   5 use warnings;
  1         2  
  1         28  
6 1     1   9256 use Math::Trig;
  1         25871  
  1         526  
7              
8             =head1 NAME
9              
10             Geo::OSM::Tiles - Calculate tile numbers for OpenStreetMap
11              
12             =head1 SYNOPSIS
13              
14             use Geo::OSM::Tiles qw( :all );
15              
16             $zoom = 13;
17             $lat = 49.60055;
18             $lon = 11.01296;
19             $tilex = lon2tilex($lon, $zoom);
20             $tiley = lat2tiley($lat, $zoom);
21             $path = tile2path($tilex, $tiley, $zoom);
22             $tileurl = "http://tile.openstreetmap.org/$path";
23              
24             =head1 DESCRIPTION
25              
26             This module provides functions for calculating the path to a map tile
27             at OpenStreetMap out of geographic coordinates. The path of a tile at
28             OSM has the form C<$zoom/$tilex/$tiley.png>. The numbering scheme is
29             documented in the OSM wiki, see the link below.
30              
31             =cut
32              
33             require Exporter;
34              
35             our $VERSION = '0.04';
36              
37             our @ISA = qw(Exporter);
38              
39             our %EXPORT_TAGS = ( 'all' => [ qw(
40             lon2tilex lat2tiley tile2path
41             checklonrange checklatrange
42             ) ] );
43              
44             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
45              
46             our @EXPORT = qw();
47              
48             =head2 C
49              
50             Returns C<$tilex> for the tile at longitude C<$lon> and zoom level
51             C<$zoom>. The longitude must be in the range C<-180.0 <= $lon < 180.0>.
52             The zoom level must be a non-negative integer.
53              
54             =cut
55              
56             sub lon2tilex
57             {
58 37     37 1 9615 my ($lon, $zoom) = @_;
59              
60 37         153 return int( ($lon+180)/360 * 2**$zoom );
61             }
62              
63             =head2 C
64              
65             Returns C<$tiley> for the tile at latitude C<$lat> and zoom level
66             C<$zoom>. The latitude must be in the range C<-85.0511 <= $lat <= 85.0511>.
67             The zoom level must be a non-negative integer.
68              
69             =cut
70              
71             sub lat2tiley
72             {
73 37     37 1 12893 my ($lat, $zoom) = @_;
74 37         81 my $lata = $lat*pi/180;
75              
76 37         100 return int( (1 - log(tan($lata) + sec($lata))/pi)/2 * 2**$zoom );
77             }
78              
79             =head2 C
80              
81             Composes the path to the tile at C<$tilex>, C<$tiley>, and C<$zoom> at
82             the OSM server. C<$tilex> and C<$tiley> must be integers in the range
83             C<0..2**$zoom-1>. The supported range of zoom levels depends on the
84             tile server. The maximum zoom for the Osmarender layer is 17, it is
85             18 for the Mapnik layer.
86              
87             =cut
88              
89             sub tile2path
90             {
91 1     1 1 633 my ($tilex, $tiley, $zoom) = @_;
92              
93 1         7 return "$zoom/$tilex/$tiley.png";
94             }
95              
96             =head2 C
97              
98             Checks whether C<$lonmin> and C<$lonmax> are within the allowed range
99             of the longitude argument to C. Returns
100             C<($lonmin, $lonmax)> unchanged if they are ok or corrected values if
101             not.
102              
103             =cut
104              
105             sub checklonrange
106             {
107 9     9 1 9017 my ($lonmin, $lonmax) = @_;
108              
109             # The bounds are choosen such that they give the correct results up
110             # to zoom level 30 (zoom levels up to 18 actually make sense):
111             # lon2tilex(-180.0, 30) == 0
112             # lon2tilex(179.9999999, 30) == 1073741823 == 2**30 - 1
113 9 50       32 $lonmin = -180.0 if $lonmin < -180.0;
114 9 50       21 $lonmin = 179.9999999 if $lonmin > 179.9999999;
115 9 50       31 $lonmax = -180.0 if $lonmax < -180.0;
116 9 50       21 $lonmax = 179.9999999 if $lonmax > 179.9999999;
117              
118 9         25 return ($lonmin, $lonmax);
119             }
120              
121             =head2 C
122              
123             Checks whether C<$latmin> and C<$latmax> are within the allowed range
124             of the latitude argument to C. Returns
125             C<($latmin, $latmax)> unchanged if they are ok or corrected values if
126             not.
127              
128             =cut
129              
130             sub checklatrange
131             {
132 9     9 1 9219 my ($latmin, $latmax) = @_;
133              
134             # The bounds are choosen such that they give the correct results up
135             # to zoom level 30 (zoom levels up to 18 actually make sense):
136             # lat2tiley(85.0511287798, 30) == 0
137             # lat2tiley(-85.0511287798, 30) == 1073741823 == 2**30 - 1
138 9 50       29 $latmin = -85.0511287798 if $latmin < -85.0511287798;
139 9 50       22 $latmin = 85.0511287798 if $latmin > 85.0511287798;
140 9 50       21 $latmax = -85.0511287798 if $latmax < -85.0511287798;
141 9 50       18 $latmax = 85.0511287798 if $latmax > 85.0511287798;
142              
143 9         25 return ($latmin, $latmax);
144             }
145              
146             1;
147              
148             __END__