File Coverage

blib/lib/Imager/Bing/MapLayer.pm
Criterion Covered Total %
statement 4 6 66.6
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 6 8 75.0


line stmt bran cond sub pod time code
1             package Imager::Bing::MapLayer;
2              
3 1     1   111110 use v5.10.1;
  1         4  
  1         46  
4              
5 1     1   502 use Moose;
  0            
  0            
6             with 'Imager::Bing::MapLayer::Role::TileClass';
7             with 'Imager::Bing::MapLayer::Role::FileHandling';
8             with 'Imager::Bing::MapLayer::Role::Centroid';
9             with 'Imager::Bing::MapLayer::Role::Misc';
10              
11             use Carp qw/ confess /;
12             use Class::MOP::Method;
13             use Const::Fast;
14             use Moose::Util::TypeConstraints;
15             use MooseX::StrictConstructor;
16              
17             use Imager::Bing::MapLayer::Utils qw/
18             $MIN_ZOOM_LEVEL $MAX_ZOOM_LEVEL
19             /;
20              
21             use Imager::Bing::MapLayer::Level;
22              
23             =head1 NAME
24              
25             Imager::Bing::MapLayer - create a map layer for Bing Maps
26              
27             =cut
28              
29             use version 0.77; our $VERSION = version->declare('v0.1.5');
30              
31             =head1 SYNOPSIS
32              
33             my $layer = Imager::Bing::MapLayer->new(
34             base_dir => $dir, # base directory (default '.')
35             overwrite => 1, # overwrite existing (default)
36             autosave => 1, # save on exit (default)
37             in_memory => 0, # keep tiles in memory (default false)
38             min_level => 1, # min zoom level (default)
39             max_level => 19, # max zoom level (default)
40             combine => 'darken', # tile composition method (default)
41             );
42              
43             # Plot polygons (e.g. geographic boundaries)
44              
45             $layer->polygon(
46             points => $points, # listref to [ lat, lon ] points
47             fill => Imager::Fill->new( ... ), #
48             );
49              
50             # Plot greyscale gradient circles for heatmaps
51              
52             $layer->radial_circle(
53             r => 100, # radius in meters
54             -min_r => 1, # minimum pixel radius for any zoom level
55             x => $longitude, # longitude (x = east-west)
56             y => $latitude, # latitude (y = north-south)
57             );
58              
59             # Blur filter
60              
61             $layer->filter( type => 'gaussian', stddev => 1 );
62              
63             # Colourise greyscale heatmaps
64              
65             $layer->colourise();
66              
67             =head1 DESCRIPTION
68              
69             This module is a wrapper around the L<Imager::Draw> module, which
70             allows you to create Bing map layers using longitude and latitude
71             coordinates.
72              
73             The module will automatically map them to the appropriate points on
74             tile files.
75              
76             =for readme stop
77              
78             =head1 ATTRIBUTES
79              
80             =head2 C<in_memory>
81              
82             The timeout for how many seconds a tile is kept in memory.
83              
84             When a tile is timed out, it is saved to disk after each L<Imager> drawing
85             operation, and reloaded if it is later needed.
86              
87             =head2 C<centroid_latitude>
88              
89             =head2 C<centroid_longitude>
90              
91             This is the centroid latitude and longitude for translating
92             points to pixels. It defaults to a point in London.
93              
94             You can probably get away with ignoring this, but if you are
95             generating maps for different regions of the world, then you may
96             consider changing this, or even maininging different map sets with
97             different centroids.
98              
99             =head2 C<overwrite>
100              
101             When true (default), existing tiles will be overwritten rather than
102             edited.
103              
104             Be wary of editing existing tiles, since antialiased lines and opaque
105             fills will darken existing points rather than drawing over them.
106              
107             =head2 C<autosave>
108              
109             When true (default), tiles will be automatically saved.
110              
111             Alternatively, you can use the L</save> method.
112              
113             =head2 C<combine>
114              
115             The tile combination method. It defaults to C<darken>.
116              
117             =head2 C<tile_class>
118              
119             The base class used for tiles.
120              
121             This can be used to subclass the tiles, for instance, to save tiles
122             with a different filename to use with something other than Bing maps,
123             e.g. Google Maps.
124              
125             You might use something like:
126              
127             package MyTile;
128              
129             use Moose;
130             extends 'Imager::Bing::MapLayer::Tile';
131              
132             use Path::Class;
133              
134             has 'filename' => (
135             is => 'ro',
136             isa => 'Str',
137             lazy => 1,
138             default => sub {
139             my ($self) = @_;
140             my $file = file($self->base_dir, $self->level,
141             join(',', @{ $self->tile_coords }) . '.png');
142             return $file->stringify;
143             },
144             );
145              
146              
147             =cut
148              
149             =head1 METHODS
150              
151             =head2 C<levels>
152              
153             my @levels = @{ $layer->levels };
154              
155             This returns a reference to a list of
156             L<Imager::Bing::MapLayer::Level> objects.
157              
158             =cut
159              
160             has 'levels' => (
161             is => 'ro',
162             isa => 'ArrayRef',
163             lazy => 1,
164             default => sub {
165             my ($self) = @_;
166              
167             confess "min_level > max_level"
168             if ( $self->min_level > $self->max_level );
169              
170             my @levels;
171              
172             foreach my $level ( $self->min_level .. $self->max_level ) {
173             push @levels,
174             Imager::Bing::MapLayer::Level->new(
175             level => $level,
176             base_dir => $self->base_dir,
177             centroid_latitude => $self->centroid_latitude,
178             centroid_longitude => $self->centroid_longitude,
179             overwrite => $self->overwrite,
180             autosave => $self->autosave,
181             in_memory => $self->in_memory,
182             combine => $self->combine,
183             tile_class => $self->tile_class,
184             );
185             }
186              
187             return \@levels;
188             },
189             init_arg => undef,
190             );
191              
192             =head2 C<min_level>
193              
194             The minimum zoom level to generate.
195              
196             =cut
197              
198             has 'min_level' => (
199             is => 'ro',
200             isa => subtype(
201             as 'Int',
202             where { ( $_ >= $MIN_ZOOM_LEVEL ) && ( $_ <= $MAX_ZOOM_LEVEL ) }
203             ),
204             default => sub {$MIN_ZOOM_LEVEL},
205             );
206              
207             =head2 C<max_level>
208              
209             The maximum zoom level to generate.
210              
211             =cut
212              
213             has 'max_level' => (
214             is => 'ro',
215             isa => subtype(
216             as 'Int',
217             where { ( $_ >= $MIN_ZOOM_LEVEL ) && ( $_ <= $MAX_ZOOM_LEVEL ) }
218             ),
219             default => sub {$MAX_ZOOM_LEVEL},
220             );
221              
222             =begin internal
223              
224             =head2 C<_make_imager_wrapper_method>
225              
226             __PACKAGE__->_make_imager_wrapper_method( { name => $method } );
227              
228             This is an I<internal> method for generating wrapper L<Imagers::Draw>
229             methods that are applied to every level.
230              
231             These methods use latitude and longitude in lieau of C<y> and C<x>
232             parameters. Note that C<points> parameters contain pairs of latitude
233             and longitude coordinates, I<not> longitude and latitude coordinates!
234              
235             See L<Imager::Draw> for documentation of the methods.
236              
237             We've added the following additional arguments:
238              
239             =over
240              
241             =item C<-min_level>
242              
243             The minimum zoom level to draw on.
244              
245             =item C<-max_level>
246              
247             The maximum zoom level to draw on.
248              
249             =back
250              
251             =end internal
252              
253             =cut
254              
255             sub _make_imager_wrapper_method {
256             my ( $class, $opts ) = @_;
257              
258             $opts->{args} //= [];
259              
260             $class->meta->add_method(
261              
262             $opts->{name} => sub {
263              
264             my ( $self, %args ) = @_;
265              
266             foreach my $level ( @{ $self->levels } ) {
267              
268             my $method = $level->can( $opts->{name} );
269              
270             $level->$method(%args);
271              
272             }
273              
274             }
275              
276             );
277             }
278              
279             =head2 C<radial_circle>
280              
281             $layer->radial_circle(
282             r => $radius_in_meters,
283             -min_r => $min_radius_in_pixels,
284             x => $longitude,
285             y => $latitude,
286             );
287              
288             This method plots "fuzzy" greyscale circles, which are intended to be
289             used for heatmaps. The radius is scaled appropriately for each zoom
290             level in the layer.
291              
292             If C<-min_r> is specified, then a circle will always be drawn with
293             that minimum radius: this ensures that lower zoom levels will always
294             have a point plotted.
295              
296             =head2 C<colourise>
297              
298             $layer->colourise();
299              
300             The method colourises greyscale layers. It is intended to be used for
301             heatmaps generated using the L</radial_circle> method.
302              
303             =head2 C<filter>
304              
305             $layer->filter( type => 'gaussian', stddev => 1 );
306              
307             This applies L<Imager::Filters> to every tile on every zoom level of the layer.
308              
309             Be aware that some filter effects may enhance the edges of tiles in
310             each zoom level.
311              
312             =head2 C<setpixel>
313              
314             Draw a pixel at a specific latitude and longitude coordinate.
315              
316             See the corresponding method in L<Imager::Draw> for more information.
317              
318             =head2 C<line>
319              
320             Draw a line between two coordinates.
321              
322             See the corresponding method in L<Imager::Draw> for more information.
323              
324             =head2 C<box>
325              
326             Draw a box bounded by northwest and southeast coordinates.
327              
328             See the corresponding method in L<Imager::Draw> for more information.
329              
330             =head2 C<polyline>
331              
332             Draw a polyline for a set of coordinates.
333              
334             Note that a polyline is not closed. To draw a closed area, use the
335             L</polygon> method.
336              
337             See the corresponding method in L<Imager::Draw> for more information.
338              
339             =head2 C<polygon>
340              
341             Draw a closed polygon for a set of coordinates.
342              
343             See the corresponding method in L<Imager::Draw> for more information.
344              
345             =head2 C<arc>
346              
347             Draw an arc.
348              
349             See the corresponding method in L<Imager::Draw> for more information.
350              
351             =head2 C<circle>
352              
353             Draw a circle.
354              
355             See the corresponding method in L<Imager::Draw> for more information.
356              
357             =head2 C<string>
358              
359             Draw a text string.
360              
361             TODO - the size is not scaled.
362              
363             See the corresponding method in L<Imager::Draw> for more information.
364              
365             =head2 C<align_string>
366              
367             Draw an aligned text string.
368              
369             TODO - the size is not scaled.
370              
371             See the corresponding method in L<Imager::Draw> for more information.
372              
373             =cut
374              
375             foreach my $method (
376             qw/
377             radial_circle colourise
378             filter setpixel line box polyline polygon arc circle flood_fill
379             string align_string
380             /
381             )
382             {
383              
384             __PACKAGE__->_make_imager_wrapper_method( { name => $method } );
385              
386             }
387              
388             =head2 C<save>
389              
390             Save the tiles.
391              
392             =cut
393              
394             sub save {
395             my ( $self, @args ) = @_;
396              
397             foreach my $level ( @{ $self->levels } ) {
398             $level->save(@args);
399             }
400             }
401              
402             =head1 KNOWN ISSUES
403              
404             For plotting very large polylines and polygons, the system will die
405             with no error message.
406              
407             =for readme continue
408              
409             =head1 SEE ALSO
410              
411             =over
412              
413             * Bing Maps Tile System
414              
415             L<http://msdn.microsoft.com/en-us/library/bb259689.aspx>
416              
417             =back
418              
419             =head1 AUTHOR
420              
421             Robert Rothenberg, C<< <rrwo at cpan.org> >>
422              
423             =head1 BUGS
424              
425             Please report any bugs or feature requests to the author, or through
426             the web interface at
427             L<https://github.com/robrwo/Imager-Bing-MapLayer/issues>.
428              
429             =head1 SUPPORT
430              
431             You can find documentation for this module with the perldoc command.
432              
433             perldoc Imager::Bing::MapLayer
434              
435             You can also look for information at:
436              
437             =over 4
438              
439             =item * GitHub
440              
441             L<https://github.com/robrwo/Imager-Bing-MapLayer>
442              
443             =back
444              
445             =head1 ACKNOWLEDGEMENTS
446              
447             =over
448              
449             =item *
450              
451             Foxtons, Ltd.
452              
453             =back
454              
455             =head1 LICENSE AND COPYRIGHT
456              
457             Copyright 2013-2014 Robert Rothenberg.
458              
459             This program is released under the following license: atistic2
460              
461             =cut
462              
463             use namespace::autoclean;
464              
465             1; # End of Imager::Bing::MapLayer