aboutsummaryrefslogtreecommitdiffstats
path: root/perllib/FixMyStreet/Map/WMXBase.pm
diff options
context:
space:
mode:
Diffstat (limited to 'perllib/FixMyStreet/Map/WMXBase.pm')
-rw-r--r--perllib/FixMyStreet/Map/WMXBase.pm199
1 files changed, 199 insertions, 0 deletions
diff --git a/perllib/FixMyStreet/Map/WMXBase.pm b/perllib/FixMyStreet/Map/WMXBase.pm
new file mode 100644
index 000000000..bc529817e
--- /dev/null
+++ b/perllib/FixMyStreet/Map/WMXBase.pm
@@ -0,0 +1,199 @@
+# FixMyStreet:Map::WMXBase
+# Common methods for WMS and WMTS maps
+
+package FixMyStreet::Map::WMXBase;
+
+use strict;
+use Math::Trig;
+use Utils;
+use JSON::MaybeXS;
+
+sub scales {
+ my $self = shift;
+ my @scales = (
+ # A list of scales corresponding to zoom levels, e.g.
+ # '192000',
+ # '96000',
+ # '48000',
+ # etc...
+ );
+ return @scales;
+}
+
+# The copyright string to display in the corner of the map.
+sub copyright {
+ return '';
+}
+
+# A hash of parameters that control the zoom options for the map
+sub zoom_parameters {
+ my $self = shift;
+ my $params = {
+ zoom_levels => scalar $self->scales,
+ default_zoom => 0,
+ min_zoom_level => 0,
+ id_offset => 0,
+ };
+ return $params;
+}
+
+# This is used to determine which template to render the map with
+sub map_template { 'fms' }
+
+# Reproject a WGS84 lat/lon into an x/y coordinate in this map's CRS.
+# Subclasses will want to override this.
+sub reproject_from_latlon($$$) {
+ my ($self, $lat, $lon) = @_;
+ return (0.0, 0.0);
+}
+
+# Reproject a x/y coordinate from this map's CRS into WGS84 lat/lon
+# Subclasses will want to override this.
+sub reproject_to_latlon($$$) {
+ my ($self, $x, $y) = @_;
+ return (0.0, 0.0);
+}
+
+sub _get_tile_size {
+ return shift->tile_parameters->{size};
+}
+
+sub map_tiles {
+ my ($self, %params) = @_;
+ my ($left_col, $top_row, $z) = @params{'x_left_tile', 'y_top_tile', 'matrix_id'};
+ my $tile_url = $self->tile_base_url;
+ my $cols = $params{cols};
+ my $rows = $params{rows};
+
+ my @col_offsets = (0.. ($cols-1) );
+ my @row_offsets = (0.. ($rows-1) );
+
+ my $size = $self->_get_tile_size(\%params);
+ my @params = $self->_get_tile_params(\%params, $left_col, $top_row, $z, $tile_url, $size);
+
+ return [
+ map {
+ my $row_offset = $_;
+ [
+ map {
+ my $col_offset = $_;
+ my $row = $self->_get_row($top_row, $row_offset, $size);
+ my $col = $self->_get_col($left_col, $col_offset, $size);
+ my $src = $self->_get_tile_src(@params, $col, $row);
+ my $dotted_id = $self->_get_tile_id(@params, $col, $row);
+
+ # return the data structure for the cell
+ +{
+ src => $src,
+ row_offset => $row_offset,
+ col_offset => $col_offset,
+ dotted_id => $dotted_id,
+ alt => "Map tile $dotted_id",
+ }
+ }
+ @col_offsets
+ ]
+ }
+ @row_offsets
+ ];
+}
+
+# display_map C PARAMS
+# PARAMS include:
+# latitude, longitude for the centre point of the map
+# CLICKABLE is set if the map is clickable
+# PINS is array of pins to show, location and colour
+sub display_map {
+ my ($self, $c, %params) = @_;
+
+ # Map centre may be overridden in the query string
+ $params{latitude} = Utils::truncate_coordinate($c->get_param('lat') + 0)
+ if defined $c->get_param('lat');
+ $params{longitude} = Utils::truncate_coordinate($c->get_param('lon') + 0)
+ if defined $c->get_param('lon');
+
+ $params{rows} //= 2; # 2x2 square is default
+ $params{cols} //= 2;
+
+ my $zoom_params = $self->zoom_parameters;
+
+ $params{zoom} = do {
+ my $zoom = defined $c->get_param('zoom')
+ ? $c->get_param('zoom') + 0
+ : $c->stash->{page} eq 'report'
+ ? $zoom_params->{default_zoom}+1
+ : $zoom_params->{default_zoom};
+ $zoom = $zoom_params->{zoom_levels} - 1
+ if $zoom >= $zoom_params->{zoom_levels};
+ $zoom = 0 if $zoom < 0;
+ $zoom;
+ };
+
+ $c->stash->{map} = $self->get_map_hash( %params );
+
+ if ($params{print_report}) {
+ $params{zoom}++ unless $params{zoom} >= $zoom_params->{zoom_levels};
+ $c->stash->{print_report_map}
+ = $self->get_map_hash(
+ %params,
+ img_type => 'img',
+ cols => 4, rows => 4,
+ );
+ }
+}
+
+sub _map_hash_extras { return {} }
+
+sub get_map_hash {
+ my ($self, %params) = @_;
+
+ @params{'x_centre_tile', 'y_centre_tile', 'matrix_id'}
+ = $self->latlon_to_tile_with_adjust(
+ @params{'latitude', 'longitude', 'zoom', 'rows', 'cols'});
+
+ $params{x_left_tile} = $params{x_centre_tile} - int($params{cols} / 2);
+ $params{y_top_tile} = $params{y_centre_tile} - int($params{rows} / 2);
+
+ $params{pins} = [
+ map {
+ my $pin = { %$_ }; # shallow clone
+ ($pin->{px}, $pin->{py})
+ = $self->latlon_to_px($pin->{latitude}, $pin->{longitude},
+ @params{'x_left_tile', 'y_top_tile', 'zoom'});
+ $pin;
+ } @{ $params{pins} }
+ ];
+
+ my @scales = $self->scales;
+ return {
+ %params,
+ type => $self->map_template,
+ map_type => $self->map_type,
+ tiles => $self->map_tiles( %params ),
+ copyright => $self->copyright(),
+ zoom => $params{zoom},
+ zoomOffset => $self->zoom_parameters->{min_zoom_level},
+ numZoomLevels => $self->zoom_parameters->{zoom_levels},
+ tile_size => $self->tile_parameters->{size},
+ tile_dpi => $self->tile_parameters->{dpi},
+ tile_urls => encode_json( $self->tile_parameters->{urls} ),
+ layer_names => encode_json( $self->tile_parameters->{layer_names} ),
+ map_projection => $self->tile_parameters->{projection},
+ scales => encode_json( \@scales ),
+ compass => $self->compass( $params{x_centre_tile}, $params{y_centre_tile}, $params{zoom} ),
+ %{ $self->_map_hash_extras },
+ };
+}
+
+sub compass {
+ my ( $self, $x, $y, $z ) = @_;
+ return {
+ north => [ map { Utils::truncate_coordinate($_) } $self->tile_to_latlon( $x, $y-1, $z ) ],
+ south => [ map { Utils::truncate_coordinate($_) } $self->tile_to_latlon( $x, $y+1, $z ) ],
+ west => [ map { Utils::truncate_coordinate($_) } $self->tile_to_latlon( $x-1, $y, $z ) ],
+ east => [ map { Utils::truncate_coordinate($_) } $self->tile_to_latlon( $x+1, $y, $z ) ],
+ here => [ map { Utils::truncate_coordinate($_) } $self->tile_to_latlon( $x, $y, $z ) ],
+ };
+}
+
+1;