File Coverage

blib/lib/Imager/Bing/MapLayer/Tile.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             package Imager::Bing::MapLayer::Tile;
2              
3 1     1   97321 use Moose;
  0            
  0            
4             with 'Imager::Bing::MapLayer::Role::FileHandling';
5              
6             use MooseX::StrictConstructor;
7             use Moose::Util::TypeConstraints;
8              
9             extends 'Imager::Bing::MapLayer::Image';
10              
11             use Carp qw/ carp confess /;
12             use Class::MOP::Method;
13             use Imager;
14             use List::Util 1.30 qw/ pairmap /;
15             use Path::Class qw/ file /;
16              
17             use Imager::Bing::MapLayer::Utils qw/
18             $MIN_ZOOM_LEVEL $MAX_ZOOM_LEVEL
19             $TILE_WIDTH $TILE_HEIGHT
20             width_at_level
21             pixel_to_tile_coords tile_coords_to_pixel_origin
22             tile_coords_to_quad_key quad_key_to_tile_coords
23             /;
24              
25             use version 0.77; our $VERSION = version->declare('v0.1.5');
26              
27             =head1 SYNOPSIS
28              
29             my $tile = Imager::Bing::MapLayer::Tile->new(
30             quad_key => $key, # the "quad key" for the tile
31             base_dir => $base_dir, # the base directory for tiles (defaults to cwd)
32             overwrite => 1, # overwrite existing tile (default) vs load it
33             autosave => 1, # automatically save tile when done (default)
34             );
35              
36             =head1 ATTRIBUTES
37              
38             =head2 C<quad_key>
39              
40             The quadrant key of the tile.
41              
42             =cut
43              
44             has 'quad_key' => (
45             is => 'ro',
46             isa => subtype(
47             as 'Str', where {qr/^[0-3]{$MIN_ZOOM_LEVEL,$MAX_ZOOM_LEVEL}$/},
48             ),
49             required => 1,
50             );
51              
52              
53             =head2 C<level>
54              
55             The zoom level for this tile. It is determined by the L</quad_key>.
56              
57             =cut
58              
59             has 'level' => (
60             is => 'ro',
61             isa => 'Int',
62             default => sub {
63             my ($self) = @_;
64             return length( $self->quad_key );
65             },
66             lazy => 1,
67             init_arg => undef,
68             );
69              
70             =head2 C<tile_coords>
71              
72             The tile coordinates of this tile. They are determined by the
73             L</quad_key>.
74              
75             =cut
76              
77             has 'tile_coords' => (
78             is => 'ro',
79             isa => 'ArrayRef',
80             default => sub {
81             my ($self) = @_;
82             return [ ( quad_key_to_tile_coords( $self->quad_key ) )[ 0, 1 ] ],;
83             },
84             lazy => 1,
85             init_arg => undef,
86             );
87              
88             =head2 C<pixel_origin>
89              
90             The coordinates of the top-left point on the tile. They are determined
91             by the L</quad_key>.
92              
93             =cut
94              
95             has 'pixel_origin' => (
96             is => 'ro',
97             isa => 'ArrayRef',
98             default => sub {
99             my ($self) = @_;
100             my $tile_coords = $self->tile_coords;
101             return [ tile_coords_to_pixel_origin( @{$tile_coords} ) ],;
102             },
103             lazy => 1,
104             init_arg => undef,
105             );
106              
107             =head2 C<width>
108              
109             The width of the tile.
110              
111             =cut
112              
113             has 'width' => (
114             is => 'ro',
115             default => sub { return $TILE_WIDTH },
116             lazy => 1,
117             init_arg => undef,
118             );
119              
120             =head2 C<height>
121              
122             The height of the tile.
123              
124             =cut
125              
126             has 'height' => (
127             is => 'ro',
128             default => sub { return $TILE_HEIGHT },
129             lazy => 1,
130             init_arg => undef,
131             );
132              
133             =head2 C<image>
134              
135             The L<Imager> object.
136              
137             =cut
138              
139             has 'image' => (
140             is => 'ro',
141             isa => 'Imager',
142             lazy => 1,
143             default => sub {
144             my ($self) = @_;
145              
146             my $image = Imager->new(
147             xsize => $self->width,
148             ysize => $self->height,
149             channels => 4,
150             );
151              
152             my $file = $self->filename;
153              
154             if ( -e $file ) {
155              
156             if ( $self->overwrite ) {
157              
158             unlink $file
159             or carp
160             sprintf( "Could not remove file '%s': %s", $file, $! );
161              
162             } else {
163              
164             $image->read( file => $file )
165             or confess sprintf( "Cannot read file '%s': %s",
166             $file, $image->errstr );
167              
168             }
169              
170             }
171              
172             return $image;
173             },
174             init_arg => undef,
175             );
176              
177             =head2 C<filename>
178              
179             The full pathname of the tile, when saved.
180              
181             =cut
182              
183             has 'filename' => (
184             is => 'ro',
185             isa => 'Str',
186             lazy => 1,
187             default => sub {
188             my ($self) = @_;
189             return file( $self->base_dir, $self->quad_key . '.png' )->stringify;
190             },
191             init_arg => undef,
192             );
193              
194             =head1 METHODS
195              
196             =head2 C<latlon_to_pixel>
197              
198             Translate latitude and longitude to a pixel on this zoom level.
199              
200             =cut
201              
202             sub latlon_to_pixel {
203             my ( $self, @latlon ) = @_;
204             return Imager::Bing::MapLayer::Utils::latlon_to_pixel( $self->level,
205             @latlon );
206             }
207              
208             =head2 C<latlons_to_pixels>
209              
210             Translate a list reference of latitude and longitude coordinates to
211             pixels on this zoom level.
212              
213             =cut
214              
215             sub latlons_to_pixels {
216             my ( $self, $latlons ) = @_;
217             return [ map { [ $self->latlon_to_pixel( @{$_} ) ] } @{$latlons} ];
218             }
219              
220             =head2 C<save>
221              
222             Save this tile.
223              
224             =cut
225              
226             sub save {
227             my ($self) = @_;
228              
229             # Only save an image if there's something on it
230              
231             if ( $self->image->getcolorusage ) {
232             $self->image->write( file => $self->filename );
233             }
234             }
235              
236             =head2 C<DEMOLISH>
237              
238             This method auto-saves the tile, if L</autosave> is enabled.
239              
240             =cut
241              
242             sub DEMOLISH {
243             my ($self) = @_;
244             $self->save if ( $self->autosave );
245             }
246              
247             use namespace::autoclean;
248              
249             1;