aboutsummaryrefslogtreecommitdiffstats
path: root/perllib/FixMyStreet/Map/Zurich.pm
diff options
context:
space:
mode:
Diffstat (limited to 'perllib/FixMyStreet/Map/Zurich.pm')
-rw-r--r--perllib/FixMyStreet/Map/Zurich.pm296
1 files changed, 63 insertions, 233 deletions
diff --git a/perllib/FixMyStreet/Map/Zurich.pm b/perllib/FixMyStreet/Map/Zurich.pm
index 4c597c30b..3b97f947f 100644
--- a/perllib/FixMyStreet/Map/Zurich.pm
+++ b/perllib/FixMyStreet/Map/Zurich.pm
@@ -1,259 +1,89 @@
# FixMyStreet:Map::Zurich
# Zurich have their own tileserver.
-#
-# Copyright (c) 2012 UK Citizens Online Democracy. All rights reserved.
-# Email: steve@mysociety.org; WWW: http://www.mysociety.org/
package FixMyStreet::Map::Zurich;
+use base 'FixMyStreet::Map::WMTSBase';
use strict;
-use Geo::Coordinates::CH1903;
-use Math::Trig;
-use Utils;
-
-use constant ZOOM_LEVELS => 9;
-use constant DEFAULT_ZOOM => 5;
-use constant MIN_ZOOM_LEVEL => 0;
-use constant ID_OFFSET => 2;
-use constant TILE_SIZE => 512;
-
-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->base_tile_url();
- my $cols = $params{cols};
- my $rows = $params{rows};
-
- my @col_offsets = (0.. ($cols-1) );
- my @row_offsets = (0.. ($rows-1) );
-
- return [
- map {
- my $row_offset = $_;
- [
- map {
- my $col_offset = $_;
- my $row = $top_row + $row_offset;
- my $col = $left_col + $col_offset;
- my $src = sprintf '%s/%d/%d/%d.jpg',
- $tile_url, $z, $row, $col;
- my $dotted_id = sprintf '%d.%d', $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", # TODO "NW map tile"?
- }
- }
- @col_offsets
- ]
- }
- @row_offsets
- ];
-}
-
-sub base_tile_url {
- # use the new 512px maps as used by Javascript
- return '//www.gis.stadt-zuerich.ch/maps/rest/services/tiled/LuftbildHybrid/MapServer/WMTS/tile/1.0.0/tiled_LuftbildHybrid/default/default028mm';
-}
-
-sub copyright {
- return '© Stadt Zürich';
-}
-
-# 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;
-
- $params{zoom} = do {
- my $zoom = defined $c->get_param('zoom')
- ? $c->get_param('zoom') + 0
- : $c->stash->{page} eq 'report'
- ? DEFAULT_ZOOM+1
- : DEFAULT_ZOOM;
- $zoom = ZOOM_LEVELS - 1 if $zoom >= ZOOM_LEVELS;
- $zoom = 0 if $zoom < 0;
- $zoom;
+use Geo::Coordinates::CH1903Plus;
+
+sub zoom_parameters {
+ my $self = shift;
+ my $params = {
+ zoom_levels => scalar $self->scales,
+ default_zoom => 5,
+ min_zoom_level => 0,
+ id_offset => 0,
};
-
- $c->stash->{map} = $self->get_map_hash( %params );
-
- if ($params{print_report}) {
- $params{zoom}++ unless $params{zoom} >= ZOOM_LEVELS;
- $c->stash->{print_report_map}
- = $self->get_map_hash(
- %params,
- img_type => 'img',
- cols => 4, rows => 4,
- );
- # NB: we can passthrough img_type as literal here, as only designed for print
-
- # NB we can do arbitrary size, including non-squares, however we'd have
- # to modify .square-map style with padding-bottom percentage calculated in
- # an inline style:
- # <zarino> in which case, the only change that'd be required is
- # removing { padding-bottom: 100% } from .square-map__outer, putting
- # the percentage into an inline style on the element itself, and then
- # probably renaming .square-map__* to .fixed-aspect-map__* or something
- # since it's no longer necessarily square
- }
+ return $params;
}
-sub get_map_hash {
- my ($self, %params) = @_;
-
- @params{'x_centre_tile', 'y_centre_tile', 'matrix_id'}
- = latlon_to_tile_with_adjust(
- @params{'latitude', 'longitude', 'zoom', 'rows', 'cols'});
-
- # centre_(row|col) is either in middle, or just to right.
- # e.g. if centre is the number in parens:
- # 1 (2) 3 => 2 - int( 3/2 ) = 1
- # 1 2 (3) 4 => 3 - int( 4/2 ) = 1
- $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})
- = latlon_to_px($pin->{latitude}, $pin->{longitude},
- @params{'x_left_tile', 'y_top_tile', 'zoom'});
- $pin;
- } @{ $params{pins} }
- ];
-
- return {
- %params,
- type => 'zurich',
- map_type => 'OpenLayers.Layer.WMTS',
- tiles => $self->map_tiles( %params ),
- copyright => $self->copyright(),
- zoom => $params{zoom},,
- zoomOffset => MIN_ZOOM_LEVEL,
- numZoomLevels => ZOOM_LEVELS,
- tile_size => TILE_SIZE,
+sub tile_parameters {
+ my $self = shift;
+ my $params = {
+ urls => [
+ 'https://www.gis.stadt-zuerich.ch/maps/rest/services/tiled95/LuftbildHybrid/MapServer/WMTS/tile',
+ 'https://www.gis.stadt-zuerich.ch/maps/rest/services/tiled95/Stadtplan3D/MapServer/WMTS/tile'
+ ],
+ layer_names => [ 'LuftbildHybrid', 'Stadtplan3D' ],
+ wmts_version => '1.0.0',
+ layer_style => 'default',
+ matrix_set => 'default028mm',
+ suffix => '', # appended to tile URLs
+ size => 512, # pixels
+ dpi => 96,
+ inches_per_unit => 39.3701, # BNG uses metres
+ projection => 'EPSG:2056',
+ # The original tile origin values from the getCapabilities call are
+ # -27386400.0/31814500.0, but this results in the map tile being offset
+ # slightly. These corrected values were figured out manually by
+ # trial and error...
+ origin_x => -27386322.5,
+ origin_y => 31814423.0,
};
+ return $params;
}
-# Given a lat/lon, convert it to Zurch tile co-ordinates (precise).
-sub latlon_to_tile($$$) {
- my ($lat, $lon, $zoom) = @_;
-
- my ($x, $y) = Geo::Coordinates::CH1903::from_latlon($lat, $lon);
-
- my $matrix_id = $zoom + ID_OFFSET;
+sub scales {
+ my $self = shift;
my @scales = (
- '250000', '125000',
- '64000', '32000',
- '16000', '8000',
- '4000', '2000',
- '1000', '500',
- '250'
+ # The two highest zoom levels are pretty much useless so they're disabled.
+ # '256000', # resolution 67.73346880027094
+ # '128000', # resolution 33.86673440013547
+ '64000', # resolution 16.933367200067735
+ '32000', # resolution 8.466683600033868
+ '16000', # resolution 4.233341800016934
+ '8000', # resolution 2.116670900008467
+ '4000', # resolution 1.0583354500042335
+ '2000', # resolution 0.5291677250021167
+ '1000', # resolution 0.26458386250105836
+ '500', # resolution 0.13229193125052918
+ '250', # resolution 0.06614596562526459
);
- my $tileOrigin = { lat => 30814423, lon => -29386322 };
- my $res = $scales[$matrix_id] / (39.3701 * 96);
- # OpenLayers.INCHES_PER_UNIT[units] * OpenLayers.DOTS_PER_INCH
-
- my $fx = ( $x - $tileOrigin->{lon} ) / ($res * TILE_SIZE);
- my $fy = ( $tileOrigin->{lat} - $y ) / ($res * TILE_SIZE);
-
- return ( $fx, $fy, $matrix_id );
+ return @scales;
}
-# Given a lat/lon, convert it to OSM tile co-ordinates (nearest actual tile,
-# adjusted so the point will be near the centre of a 2x2 tiled map).
-#
-# Takes parameter for rows/cols. For even sizes (2x2, 4x4 etc.) will
-# do adjustment, but simply returns actual for odd sizes.
-#
-sub latlon_to_tile_with_adjust {
- my ($lat, $lon, $zoom, $rows, $cols) = @_;
- my ($x_tile, $y_tile, $matrix_id)
- = my @ret
- = latlon_to_tile($lat, $lon, $zoom);
-
- # Try and have point near centre of map, passing through if odd
- unless ($cols % 2) {
- if ($x_tile - int($x_tile) > 0.5) {
- $x_tile += 1;
- }
- }
- unless ($rows % 2) {
- if ($y_tile - int($y_tile) > 0.5) {
- $y_tile += 1;
- }
- }
-
- return ( int($x_tile), int($y_tile), $matrix_id );
-}
-
-sub tile_to_latlon {
- my ($fx, $fy, $zoom) = @_;
-
- my $matrix_id = $zoom + ID_OFFSET;
- my @scales = ( '250000', '125000', '64000', '32000', '16000', '8000', '4000', '2000', '1000', '500', '250' );
- my $tileOrigin = { lat => 30814423, lon => -29386322 };
- my $res = $scales[$matrix_id] / (39.3701 * 96); # OpenLayers.INCHES_PER_UNIT[units] * OpenLayers.DOTS_PER_INCH
-
- my $x = $fx * $res * TILE_SIZE + $tileOrigin->{lon};
- my $y = $tileOrigin->{lat} - $fy * $res * TILE_SIZE;
-
- my ($lat, $lon) = Geo::Coordinates::CH1903::to_latlon($x, $y);
-
- return ( $lat, $lon );
+sub copyright {
+ return '&copy; Stadt Z&uuml;rich';
}
-# Given a lat/lon, convert it to pixel co-ordinates from the top left of the map
-sub latlon_to_px($$$$$) {
- my ($lat, $lon, $x_tile, $y_tile, $zoom) = @_;
- my ($pin_x_tile, $pin_y_tile) = latlon_to_tile($lat, $lon, $zoom);
- my $pin_x = tile_to_px($pin_x_tile, $x_tile);
- my $pin_y = tile_to_px($pin_y_tile, $y_tile);
- return ($pin_x, $pin_y);
+sub map_type {
+ return 'zurich';
}
-# Convert tile co-ordinates to pixel co-ordinates from top left of map
-# C is centre tile reference of displayed map
-sub tile_to_px {
- my ($p, $c) = @_;
- $p = TILE_SIZE * ($p - $c);
- $p = int($p + .5 * ($p <=> 0));
- return $p;
-}
-sub click_to_tile {
- my ($pin_tile, $pin) = @_;
- $pin -= TILE_SIZE while $pin > TILE_SIZE;
- $pin += TILE_SIZE while $pin < 0;
- return $pin_tile + $pin / TILE_SIZE;
+# Reproject a WGS84 lat/lon into Swiss easting/northing
+sub reproject_from_latlon($$$) {
+ my ($self, $lat, $lon) = @_;
+ my ($x, $y) = Geo::Coordinates::CH1903Plus::from_latlon($lat, $lon);
+ return ($x, $y);
}
-# 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 $tile_x = click_to_tile($pin_tile_x, $pin_x);
- my $tile_y = click_to_tile($pin_tile_y, $pin_y);
- my $zoom = (defined $c->get_param('zoom') ? $c->get_param('zoom') : DEFAULT_ZOOM);
- my ($lat, $lon) = tile_to_latlon($tile_x, $tile_y, $zoom);
- return ( $lat, $lon );
+# Reproject a Swiss easting/northing into WGS84 lat/lon
+sub reproject_to_latlon($$$) {
+ my ($self, $x, $y) = @_;
+ my ($lat, $lon) = Geo::Coordinates::CH1903Plus::to_latlon($x, $y);
+ return ($lat, $lon);
}
1;