aboutsummaryrefslogtreecommitdiffstats
path: root/perllib/FixMyStreet/Map/WMSBase.pm
diff options
context:
space:
mode:
Diffstat (limited to 'perllib/FixMyStreet/Map/WMSBase.pm')
-rw-r--r--perllib/FixMyStreet/Map/WMSBase.pm151
1 files changed, 151 insertions, 0 deletions
diff --git a/perllib/FixMyStreet/Map/WMSBase.pm b/perllib/FixMyStreet/Map/WMSBase.pm
new file mode 100644
index 000000000..ce8b6ab38
--- /dev/null
+++ b/perllib/FixMyStreet/Map/WMSBase.pm
@@ -0,0 +1,151 @@
+# FixMyStreet:Map::WMSBase
+# Makes it easier for cobrands to use their own WMS base map.
+# This cannot be used directly; you must subclass it and implement several
+# methods. See, e.g. FixMyStreet::Map::Northamptonshire.
+
+package FixMyStreet::Map::WMSBase;
+use parent FixMyStreet::Map::WMXBase;
+
+use strict;
+
+# A hash of parameters used in calculations for map tiles
+sub tile_parameters {
+ my $params = {
+ urls => [ '' ], # URL of the map tiles, up to the /{z}/{x}/{y} part
+ layer_names => [ '' ],
+ wms_version => '1.0.0',
+ size => 256, # pixels
+ dpi => 96,
+ inches_per_unit => 0, # See OpenLayers.INCHES_PER_UNIT for some options.
+ projection => 'EPSG:3857', # Passed through to OpenLayers.Projection
+ };
+ return $params;
+}
+
+# This is used to determine which template to render the map with
+sub map_template { 'wms' }
+
+sub get_res {
+ my ($self, $zoom) = @_;
+
+ my @scales = $self->scales;
+
+ my $res = $scales[$zoom] /
+ ($self->tile_parameters->{inches_per_unit} * $self->tile_parameters->{dpi});
+
+ return $res;
+}
+
+sub _get_tile_size {
+ my ($self, $params) = @_;
+
+ my $res = $self->get_res($params->{zoom});
+ return $res * $self->tile_parameters->{size};
+}
+
+sub _get_tile_params {
+ my ($self, $params, $left_col, $top_row, $z, $tile_url, $size) = @_;
+
+ my ($min_x, $min_y, $max_x, $max_y) = ($left_col, $top_row - $size, $left_col + $size, $top_row);
+
+ return ($tile_url, $min_x, $min_y, $max_x, $max_y);
+}
+
+sub _get_tile_src {
+ my ($self, $tile_url, $min_x, $min_y, $max_x, $max_y, $col, $row) = @_;
+
+ my $src = sprintf( '%s&bbox=%d,%d,%d,%d',
+ $tile_url, $min_x + $col, $min_y - $row, $max_x + $col, $max_y - $row);
+
+ return $src;
+}
+
+sub _get_tile_id {
+ my ($self, $tile_url, $min_x, $min_y, $max_x, $max_y, $col, $row) = @_;
+
+ return sprintf( '%d.%d', ($min_x + $col), ($min_y - $row) );
+}
+
+sub _get_row {
+ my ($self, $top_row, $row_offset, $size) = @_;
+ return $row_offset * $size;
+}
+
+sub _get_col {
+ my ($self, $left_col, $col_offset, $size) = @_;
+ return $col_offset * $size;
+}
+
+sub map_type { 'OpenLayers.Layer.WMS' }
+
+sub _map_hash_extras {
+ my $self = shift;
+
+ return {
+ wms_version => $self->tile_parameters->{wms_version},
+ format => $self->tile_parameters->{format},
+ };
+}
+
+sub tile_base_url {
+ my $self = shift;
+ my $params = $self->tile_parameters;
+ return sprintf '%s?version=%s&format=%s&size=%s&width=%s&height=%s&service=WMS&layers=%s&request=GetMap&srs=%s',
+ $params->{urls}[0], $params->{wms_version}, $params->{format}, $params->{size}, $params->{size},
+ $params->{size}, $params->{layer_names}[0], $params->{projection};
+}
+
+# Given a lat/lon, convert it to tile co-ordinates (nearest actual tile,
+# adjusted so the point will be near the centre of a 2x2 tiled map).
+sub latlon_to_tile_with_adjust {
+ my ($self, $lat, $lon, $zoom, $rows, $cols) = @_;
+ my ($x_tile, $y_tile)
+ = $self->reproject_from_latlon($lat, $lon, $zoom);
+
+ my $tile_params = $self->tile_parameters;
+ my $res = $self->get_res($zoom);
+
+ $x_tile = $x_tile - ($res * $tile_params->{size});
+ $y_tile = $y_tile + ($res * $tile_params->{size});
+
+ return ( int($x_tile), int($y_tile) );
+}
+
+sub tile_to_latlon {
+ my ($self, $fx, $fy, $zoom) = @_;
+ my ($lat, $lon) = $self->reproject_to_latlon($fx, $fy);
+
+ return ($lat, $lon);
+}
+
+# Given a lat/lon, convert it to pixel co-ordinates from the top left of the map
+sub latlon_to_px($$$$$$) {
+ my ($self, $lat, $lon, $x_tile, $y_tile, $zoom) = @_;
+ my ($pin_x_tile, $pin_y_tile) = $self->reproject_from_latlon($lat, $lon, $zoom);
+ my $res = $self->get_res($zoom);
+ my $pin_x = ( $pin_x_tile - $x_tile ) / $res;
+ my $pin_y = ( $y_tile - $pin_y_tile ) / $res;
+ return ($pin_x, $pin_y);
+}
+
+sub click_to_tile {
+ my ($self, $pin_tile, $pin, $zoom, $reverse) = @_;
+ my $tile_params = $self->tile_parameters;
+ my $size = $tile_params->{size};
+ my $res = $self->get_res($zoom);
+
+ return $reverse ? $pin_tile + ( ( $size - $pin ) * $res ) : $pin_tile + ( $pin * $res );
+}
+
+# Given some click co-ords (the tile they were on, and where in the
+# tile they were), convert to WGS84 and return.
+sub click_to_wgs84 {
+ my ($self, $c, $pin_tile_x, $pin_x, $pin_tile_y, $pin_y) = @_;
+ my $zoom = (defined $c->get_param('zoom') ? $c->get_param('zoom') : $self->zoom_parameters->{default_zoom});
+ my $tile_x = $self->click_to_tile($pin_tile_x, $pin_x, $zoom);
+ my $tile_y = $self->click_to_tile($pin_tile_y, $pin_y, $zoom, 1);
+ my ($lat, $lon) = $self->tile_to_latlon($tile_x, $tile_y, $zoom);
+ return ( $lat, $lon );
+}
+
+1;