diff options
author | Dave Arter <davea@mysociety.org> | 2016-06-29 11:07:36 +0100 |
---|---|---|
committer | Dave Arter <davea@mysociety.org> | 2016-07-07 11:28:33 +0100 |
commit | 5b9670512542f54588cc89f2eefc943db26b9ee2 (patch) | |
tree | b929b12826b3a916e68003559a222bd62f4ac53f | |
parent | 6d3cbb5d58c0297959c541da50faaf39884ffe1c (diff) |
[Zurich] Use new LV95/CH1903+ geocoder and base map tiles
- Use new `getLocation95` method for geocoding addresses
- Replace Coordinates::CH1903 with Coordinates::CH1903Plus
- Refactor Map::Zurich to use WMTSBase instead of duplicating code
- Slightly refactor map templates to make using custom WMTS tiles easier
- Use correct sizes for marker pins on maps
Closes mysociety/FixMyStreet-Commercial#769.
Closes mysociety/FixMyStreet-Commercial#768.
-rw-r--r-- | perllib/FixMyStreet/DB/Result/Problem.pm | 2 | ||||
-rw-r--r-- | perllib/FixMyStreet/Geocode/Zurich.pm | 6 | ||||
-rw-r--r-- | perllib/FixMyStreet/Map/Bristol.pm | 8 | ||||
-rw-r--r-- | perllib/FixMyStreet/Map/WMTSBase.pm | 20 | ||||
-rw-r--r-- | perllib/FixMyStreet/Map/Zurich.pm | 296 | ||||
-rw-r--r-- | perllib/Geo/Coordinates/CH1903Plus.pm (renamed from perllib/Geo/Coordinates/CH1903.pm) | 29 | ||||
-rw-r--r-- | templates/web/base/maps/wmts_config.html | 15 | ||||
-rw-r--r-- | templates/web/bristol/maps/bristol.html (renamed from templates/web/bristol/maps/fms.html) | 6 | ||||
-rw-r--r-- | templates/web/bristol/maps/openlayers.html | 49 | ||||
-rw-r--r-- | templates/web/zurich/maps/zurich.html | 4 | ||||
-rw-r--r-- | web/js/OpenLayers.Projection.CH1903Plus.js (renamed from web/js/OpenLayers.Projection.CH1903.js) | 42 | ||||
-rw-r--r-- | web/js/map-wmts-base.js | 56 | ||||
-rw-r--r-- | web/js/map-wmts-bristol.js | 47 | ||||
-rw-r--r-- | web/js/map-wmts-zurich.js | 313 |
14 files changed, 330 insertions, 563 deletions
diff --git a/perllib/FixMyStreet/DB/Result/Problem.pm b/perllib/FixMyStreet/DB/Result/Problem.pm index b58294604..a2167032a 100644 --- a/perllib/FixMyStreet/DB/Result/Problem.pm +++ b/perllib/FixMyStreet/DB/Result/Problem.pm @@ -668,7 +668,7 @@ sub local_coords { my $self = shift; my $cobrand = FixMyStreet::Cobrand->get_class_for_moniker($self->cobrand)->new; if ($cobrand->moniker eq 'zurich') { - my ($x, $y) = Geo::Coordinates::CH1903::from_latlon($self->latitude, $self->longitude); + my ($x, $y) = Geo::Coordinates::CH1903Plus::from_latlon($self->latitude, $self->longitude); return ( int($x+0.5), int($y+0.5) ); } elsif ($cobrand->country eq 'GB') { my $coordsyst = 'G'; diff --git a/perllib/FixMyStreet/Geocode/Zurich.pm b/perllib/FixMyStreet/Geocode/Zurich.pm index 50a7c355e..ca893e9d6 100644 --- a/perllib/FixMyStreet/Geocode/Zurich.pm +++ b/perllib/FixMyStreet/Geocode/Zurich.pm @@ -13,7 +13,7 @@ package FixMyStreet::Geocode::Zurich; use strict; use Digest::MD5 qw(md5_hex); use File::Path (); -use Geo::Coordinates::CH1903; +use Geo::Coordinates::CH1903Plus; use Storable; use Utils; @@ -46,7 +46,7 @@ sub setup_soap { ) ); $soap = SOAP::Lite->on_action( sub { $action . $_[1]; } )->proxy($url); - $method = SOAP::Data->name('getLocation')->attr({ xmlns => $attr }); + $method = SOAP::Data->name('getLocation95')->attr({ xmlns => $attr }); } # string STRING CONTEXT @@ -95,7 +95,7 @@ sub string { foreach (@$results) { ($latitude, $longitude) = map { Utils::truncate_coordinate($_) } - Geo::Coordinates::CH1903::to_latlon($_->{easting}, $_->{northing}); + Geo::Coordinates::CH1903Plus::to_latlon($_->{easting}, $_->{northing}); push (@$error, { address => $_->{text}, latitude => $latitude, diff --git a/perllib/FixMyStreet/Map/Bristol.pm b/perllib/FixMyStreet/Map/Bristol.pm index 7098ceb40..3b60d1acf 100644 --- a/perllib/FixMyStreet/Map/Bristol.pm +++ b/perllib/FixMyStreet/Map/Bristol.pm @@ -20,9 +20,9 @@ sub zoom_parameters { sub tile_parameters { my $self = shift; my $params = { - url => 'https://maps.bristol.gov.uk/arcgis/rest/services/base/2015_BCC_96dpi/MapServer/WMTS/tile', + urls => [ 'https://maps.bristol.gov.uk/arcgis/rest/services/base/2015_BCC_96dpi/MapServer/WMTS/tile' ], + layer_names => [ '2015_BCC_96dpi' ], wmts_version => '1.0.0', - layer_name => '2015_BCC_96dpi', layer_style => 'default', matrix_set => 'default028mm', suffix => '.png', # appended to tile URLs @@ -60,6 +60,10 @@ sub copyright { return '© BCC'; } +sub map_type { + return 'bristol'; +} + # Reproject a WGS84 lat/lon into BNG easting/northing sub reproject_from_latlon($$$) { my ($self, $lat, $lon) = @_; diff --git a/perllib/FixMyStreet/Map/WMTSBase.pm b/perllib/FixMyStreet/Map/WMTSBase.pm index 13b6d8091..e35ae13c9 100644 --- a/perllib/FixMyStreet/Map/WMTSBase.pm +++ b/perllib/FixMyStreet/Map/WMTSBase.pm @@ -42,7 +42,8 @@ sub zoom_parameters { # A hash of parameters used in calculations for map tiles sub tile_parameters { my $params = { - url => '', # URL of the map tiles, up to the /{z}/{x}/{y} part + urls => [ '' ], # URL of the map tiles, up to the /{z}/{x}/{y} part + layer_names => [ '' ], wmts_version => '1.0.0', layer_style => '', matrix_set => '', @@ -206,14 +207,14 @@ sub get_map_hash { numZoomLevels => $self->zoom_parameters->{default_zoom}, tile_size => $self->tile_parameters->{size}, tile_dpi => $self->tile_parameters->{dpi}, - tile_url => $self->tile_parameters->{url}, + tile_urls => encode_json $self->tile_parameters->{urls}, tile_suffix => $self->tile_parameters->{suffix}, - layer_name => $self->tile_parameters->{layer_name}, + layer_names => encode_json $self->tile_parameters->{layer_names}, layer_style => $self->tile_parameters->{layer_style}, matrix_set => $self->tile_parameters->{matrix_set}, map_projection => $self->tile_parameters->{projection}, - origin_x => $self->tile_parameters->{origin_x}, - origin_y => $self->tile_parameters->{origin_y}, + origin_x => force_float_format($self->tile_parameters->{origin_x}), + origin_y => force_float_format($self->tile_parameters->{origin_y}), scales => encode_json \@scales, }; } @@ -222,7 +223,7 @@ sub tile_base_url { my $self = shift; my $params = $self->tile_parameters; return sprintf '%s/%s/%s/%s/%s', - $params->{url}, $params->{wmts_version}, $params->{layer_name}, + $params->{urls}[0], $params->{wmts_version}, $params->{layer_names}[0], $params->{layer_style}, $params->{matrix_set}; } @@ -336,4 +337,11 @@ sub click_to_wgs84 { return ( $lat, $lon ); } +sub force_float_format { + my $in = shift; + return mySociety::Locale::in_gb_locale { + sprintf( '%f', $in ); + }; +} + 1; 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 '© Stadt Zü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; diff --git a/perllib/Geo/Coordinates/CH1903.pm b/perllib/Geo/Coordinates/CH1903Plus.pm index 6611af9f2..8487dacbe 100644 --- a/perllib/Geo/Coordinates/CH1903.pm +++ b/perllib/Geo/Coordinates/CH1903Plus.pm @@ -1,5 +1,5 @@ -# Geo::Coordinates::CH1903 -# Conversion between WGS84 and Swiss CH1903. +# Geo::Coordinates::CH1903Plus +# Conversion between WGS84 and Swiss CH1903+ (aka LV95). # # Copyright (c) 2012 UK Citizens Online Democracy. This module is free # software; you can redistribute it and/or modify it under the same terms as @@ -7,15 +7,20 @@ # # WWW: http://www.mysociety.org/ -package Geo::Coordinates::CH1903; +package Geo::Coordinates::CH1903Plus; -$Geo::Coordinates::CH1903::VERSION = '1.00'; +$Geo::Coordinates::CH1903Plus::VERSION = '1.00'; use strict; +# Use the same calcs as CH1903 but with offset. +# Maximum distortion is 3M which should be sufficient for our purposes. +use constant LV95_X_OFFSET => 2000000; +use constant LV95_Y_OFFSET => 1000000; + =head1 NAME -Geo::Coordinates::CH1903 +Geo::Coordinates::CH1903Plus =head1 VERSION @@ -23,11 +28,11 @@ Geo::Coordinates::CH1903 =head1 SYNOPSIS - use Geo::Coordinates::CH1903; + use Geo::Coordinates::CH1903Plus; my ($lat, $lon) = ...; - my ($e, $n) = Geo::Coordinates::CH1903::from_latlon($lat, $lon); - my ($lat, $lon) = Geo::Coordinates::CH1903::to_latlon($e, $n); + my ($e, $n) = Geo::Coordinates::CH1903Plus::from_latlon($lat, $lon); + my ($lat, $lon) = Geo::Coordinates::CH1903Plus::to_latlon($e, $n); =head1 FUNCTIONS @@ -44,13 +49,13 @@ sub from_latlon($$) { my $lat_aux = ($lat - 169028.66) / 10000; my $lon_aux = ($lon - 26782.5) / 10000; - my $x = 600072.37 + my $x = 600072.37 + LV95_X_OFFSET + (211455.93 * $lon_aux) - (10938.51 * $lon_aux * $lat_aux) - (0.36 * $lon_aux * $lat_aux**2) - (44.54 * $lon_aux**3); - my $y = 200147.07 + my $y = 200147.07 + LV95_Y_OFFSET + (308807.95 * $lat_aux) + (3745.25 * $lon_aux**2) + (76.63 * $lat_aux**2) @@ -63,8 +68,8 @@ sub from_latlon($$) { sub to_latlon($$) { my ($x, $y) = @_; - my $x_aux = ($x - 600000) / 1000000; - my $y_aux = ($y - 200000) / 1000000; + my $x_aux = ($x - 600000 - LV95_X_OFFSET) / 1000000; + my $y_aux = ($y - 200000 - LV95_Y_OFFSET) / 1000000; my $lat = 16.9023892 + (3.238272 * $y_aux) diff --git a/templates/web/base/maps/wmts_config.html b/templates/web/base/maps/wmts_config.html new file mode 100644 index 000000000..333455605 --- /dev/null +++ b/templates/web/base/maps/wmts_config.html @@ -0,0 +1,15 @@ +<script type="text/javascript"> + var fixmystreet = window.fixmystreet || {}; + fixmystreet.wmts_config = { + 'map_projection': '[% map.map_projection %]', + 'tile_dpi': [% map.tile_dpi %], + 'tile_urls': [% map.tile_urls %], + 'tile_suffix': '[% map.tile_suffix %]', + 'layer_names': [% map.layer_names %], + 'layer_style': '[% map.layer_style %]', + 'matrix_set': '[% map.matrix_set %]', + 'scales': [% map.scales %], + 'origin_x': [% map.origin_x %], + 'origin_y': [% map.origin_y %] + }; +</script> diff --git a/templates/web/bristol/maps/fms.html b/templates/web/bristol/maps/bristol.html index fa3f01af4..c6e74022b 100644 --- a/templates/web/bristol/maps/fms.html +++ b/templates/web/bristol/maps/bristol.html @@ -2,8 +2,12 @@ <script type="text/javascript" src="[% version('/js/OpenLayers.2.11.zurich.js') %]"></script> <script type="text/javascript" src="[% version('/js/OpenLayers.Projection.OrdnanceSurvey.js') %]"></script> <script type="text/javascript" src="[% version('/js/map-OpenLayers.js') %]"></script> +<script type="text/javascript" src="[% version('/js/map-wmts-base.js') %]"></script> <script type="text/javascript" src="[% version('/js/map-wmts-bristol.js') %]"></script> <script type="text/javascript" src="[% version('/js/jquery.ba-hashchange.min.js') %]"></script> [% END %] -[% map_html = INCLUDE maps/openlayers.html %] +[% map_html = BLOCK %] +[% INCLUDE maps/openlayers.html %] +[% INCLUDE maps/wmts_config.html %] +[% END %]
\ No newline at end of file diff --git a/templates/web/bristol/maps/openlayers.html b/templates/web/bristol/maps/openlayers.html deleted file mode 100644 index 4b178e21a..000000000 --- a/templates/web/bristol/maps/openlayers.html +++ /dev/null @@ -1,49 +0,0 @@ -[% IF map.clickable %] - [% map.img_type = 'input type="image"' %] -[% ELSE %] - [% map.img_type = 'img' %] -[% END %] - -<input type="hidden" name="zoom" value="[% map.zoom %]"> -<script type="text/javascript"> -var fixmystreet = { - 'page': '[% page %]', - 'area': [ [% map.area.join(',') %] ], - 'all_pins': '[% all_pins %]', - 'latitude': [% map.latitude %], - 'longitude': [% map.longitude %], -[% IF map.any_zoom -%] - 'zoomToBounds': 1, -[%- END %] -[% IF map.zoom -%] - 'zoom': [% map.zoom %], -[%- END %] - 'pin_prefix': '[% c.cobrand.path_to_pin_icons %]', - 'numZoomLevels': [% map.numZoomLevels %], - 'zoomOffset': [% map.zoomOffset %], - 'map_type': [% map.map_type %], - 'pins': [% INCLUDE maps/pins_js.html %], - - 'wmts_config': { - 'map_projection': '[% map.map_projection %]', - 'tile_dpi': [% map.tile_dpi %], - 'tile_url': '[% map.tile_url %]', - 'tile_suffix': '[% map.tile_suffix %]', - 'layer_name': '[% map.layer_name %]', - 'layer_style': '[% map.layer_style %]', - 'matrix_set': '[% map.matrix_set %]', - 'scales': [% map.scales %], - 'origin_x': [% map.origin_x %], - 'origin_y': [% map.origin_y %] - } -} -</script> -<div id="map_box" aria-hidden="true"> - [% pre_map %] - <div id="map"> - [% INCLUDE 'maps/noscript_map.html' %] - </div> - [% IF map.copyright %] - <div class="olControlAttribution" style="position: absolute;">[% map.copyright %]</div> - [% END %] - diff --git a/templates/web/zurich/maps/zurich.html b/templates/web/zurich/maps/zurich.html index e0c258223..e0a3979ed 100644 --- a/templates/web/zurich/maps/zurich.html +++ b/templates/web/zurich/maps/zurich.html @@ -1,7 +1,8 @@ [% map_js = BLOCK %] <script type="text/javascript" src="[% version('/js/OpenLayers.2.11.zurich.js') %]"></script> -<script type="text/javascript" src="[% version('/js/OpenLayers.Projection.CH1903.js') %]"></script> +<script type="text/javascript" src="[% version('/js/OpenLayers.Projection.CH1903Plus.js') %]"></script> <script type="text/javascript" src="[% version('/js/map-OpenLayers.js') %]"></script> +<script type="text/javascript" src="[% version('/js/map-wmts-base.js') %]"></script> <script type="text/javascript" src="[% version('/js/map-wmts-zurich.js') %]"></script> <script type="text/javascript" src="[% version('/js/jquery.ba-hashchange.min.js') %]"></script> [% END %] @@ -12,6 +13,7 @@ [% map_html = BLOCK %] [% INCLUDE maps/openlayers.html %] +[% INCLUDE maps/wmts_config.html %] [% UNLESS around_page %] <p id="sub_map_links"> [% map_sub_links %] diff --git a/web/js/OpenLayers.Projection.CH1903.js b/web/js/OpenLayers.Projection.CH1903Plus.js index 34a0500fa..6cb888bf5 100644 --- a/web/js/OpenLayers.Projection.CH1903.js +++ b/web/js/OpenLayers.Projection.CH1903Plus.js @@ -1,14 +1,20 @@ /** - * OpenLayers Swiss (CH1903) grid projection transformations + * OpenLayers Swiss (CH1903+/LV95) grid projection transformations * - * Provides transform functions for WGS84<->CH1903 projections. + * Provides transform functions for WGS84<->CH1903+ projections. * * Maths courtesy of the Swiss Federal Office of Topography: * http://www.swisstopo.admin.ch/internet/swisstopo/en/home/products/software/products/skripts.html * Simplifed a bit, and with x/y swapped the normal way round. */ -OpenLayers.Projection.CH1903 = { +// Use the same calcs as CH1903 but with offset. +// Maximum distortion is 3M which should be sufficient for our purposes. +var LV95_X_OFFSET = 2000000; +var LV95_Y_OFFSET = 1000000; + + +OpenLayers.Projection.CH1903Plus = { // Convert WGS lat/long (° dec) to CH x WGStoCHx: function(lat, lng) { @@ -22,7 +28,7 @@ OpenLayers.Projection.CH1903 = { var lng_aux = (lng - 26782.5) / 10000; // Process X - var x = 600072.37; + var x = 600072.37 + LV95_X_OFFSET; x = x + (211455.93 * lng_aux); x = x - (10938.51 * lng_aux * lat_aux); x = x - (0.36 * lng_aux * Math.pow(lat_aux, 2)); @@ -43,7 +49,7 @@ OpenLayers.Projection.CH1903 = { var lng_aux = (lng - 26782.5)/10000; // Process Y - var y = 200147.07; + var y = 200147.07 + LV95_Y_OFFSET; y = y + (308807.95 * lat_aux); y = y + (3745.25 * Math.pow(lng_aux, 2)); y = y + (76.63 * Math.pow(lat_aux, 2)); @@ -59,8 +65,8 @@ OpenLayers.Projection.CH1903 = { // Converts militar to civil and to unit = 1000km // Axiliary values (% Bern) - var x_aux = (x - 600000) / 1000000; - var y_aux = (y - 200000) / 1000000; + var x_aux = (x - 600000 - LV95_X_OFFSET) / 1000000; + var y_aux = (y - 200000 - LV95_Y_OFFSET) / 1000000; // Process lat var lat = 16.9023892; @@ -82,8 +88,8 @@ OpenLayers.Projection.CH1903 = { // Converts militar to civil and to unit = 1000km // Axiliary values (% Bern) - var x_aux = (x - 600000) / 1000000; - var y_aux = (y - 200000) / 1000000; + var x_aux = (x - 600000 - LV95_X_OFFSET) / 1000000; + var y_aux = (y - 200000 - LV95_Y_OFFSET) / 1000000; // Process long var lng = 2.6779094; @@ -101,8 +107,8 @@ OpenLayers.Projection.CH1903 = { // Function to convert a WGS84 coordinate to a Swiss coordinate. projectForwardSwiss: function(point) { - var x = OpenLayers.Projection.CH1903.WGStoCHx(point.y, point.x), - y = OpenLayers.Projection.CH1903.WGStoCHy(point.y, point.x); + var x = OpenLayers.Projection.CH1903Plus.WGStoCHx(point.y, point.x), + y = OpenLayers.Projection.CH1903Plus.WGStoCHy(point.y, point.x); point.x = x; point.y = y; return point; @@ -110,8 +116,8 @@ OpenLayers.Projection.CH1903 = { // Function to convert a Swiss coordinate to a WGS84 coordinate. projectInverseSwiss: function(point) { - var lon = OpenLayers.Projection.CH1903.chToWGSlng(point.x, point.y); - var lat = OpenLayers.Projection.CH1903.chToWGSlat(point.x, point.y); + var lon = OpenLayers.Projection.CH1903Plus.chToWGSlng(point.x, point.y); + var lat = OpenLayers.Projection.CH1903Plus.chToWGSlat(point.x, point.y); point.x = lon; point.y = lat; return point; @@ -120,9 +126,9 @@ OpenLayers.Projection.CH1903 = { /** * Note: One transform declared - * Transforms from EPSG:4326 to EPSG:21781 + * Transforms from EPSG:4326 to EPSG:2056 */ - OpenLayers.Projection.addTransform("EPSG:4326", "EPSG:21781", - OpenLayers.Projection.CH1903.projectForwardSwiss); - OpenLayers.Projection.addTransform("EPSG:21781", "EPSG:4326", - OpenLayers.Projection.CH1903.projectInverseSwiss); + OpenLayers.Projection.addTransform("EPSG:4326", "EPSG:2056", + OpenLayers.Projection.CH1903Plus.projectForwardSwiss); + OpenLayers.Projection.addTransform("EPSG:2056", "EPSG:4326", + OpenLayers.Projection.CH1903Plus.projectInverseSwiss); diff --git a/web/js/map-wmts-base.js b/web/js/map-wmts-base.js new file mode 100644 index 000000000..c60afe4e1 --- /dev/null +++ b/web/js/map-wmts-base.js @@ -0,0 +1,56 @@ +// Functionality required by all OpenLayers WMTS base maps + +function setup_wmts_base_map() { + fixmystreet.map_type = OpenLayers.Layer.WMTS; + + // Set DPI - default is 72 + OpenLayers.DOTS_PER_INCH = fixmystreet.wmts_config.tile_dpi; + + fixmystreet.map_options = { + maxExtent: layer_bounds, + units: 'm', + scales: fixmystreet.wmts_config.scales + }; + + fixmystreet.layer_options = []; + fixmystreet.wmts_config.layer_names.forEach(function(v, i) { + fixmystreet.layer_options.push({ + projection: new OpenLayers.Projection(fixmystreet.wmts_config.map_projection), + name: fixmystreet.wmts_config.layer_names[i], + layer: fixmystreet.wmts_config.layer_names[i], + formatSuffix: fixmystreet.wmts_config.tile_suffix.replace(".", ""), + matrixSet: fixmystreet.wmts_config.matrix_set, + requestEncoding: "REST", + url: fixmystreet.wmts_config.tile_urls[i], + style: fixmystreet.wmts_config.layer_style, + matrixIds: matrix_ids, + tileOrigin: new OpenLayers.LonLat(fixmystreet.wmts_config.origin_x, fixmystreet.wmts_config.origin_y) + }); + }); + + // Give main code a new bbox_strategy that translates between + // lat/lon and our WMTS layer's coordinates + fixmystreet.bbox_strategy = new OpenLayers.Strategy.ReprojectBBOX({ + ratio: 1 + }); +} + +OpenLayers.Strategy.ReprojectBBOX = OpenLayers.Class(OpenLayers.Strategy.BBOX, { + getMapBounds: function() { + // Get the map bounds but return them in lat/lon, not + // local coordinates + if (this.layer.map === null) { + return null; + } + + var localBounds = this.layer.map.getExtent(); + // Transform bound corners into WGS84 + localBounds.transform( new OpenLayers.Projection(fixmystreet.wmts_config.map_projection), new OpenLayers.Projection("EPSG:4326") ); + return localBounds; + }, + + CLASS_NAME: "OpenLayers.Strategy.ReprojectBBOX" +}); + + +//
\ No newline at end of file diff --git a/web/js/map-wmts-bristol.js b/web/js/map-wmts-bristol.js index a1889beed..0fb664d76 100644 --- a/web/js/map-wmts-bristol.js +++ b/web/js/map-wmts-bristol.js @@ -118,53 +118,10 @@ var matrix_ids = [ if ( fixmystreet.page == 'report' ) { fixmystreet.controls.push( new OpenLayers.Control.PermalinkFMS('key-tool-problems-nearby', '/around') ); } - - fixmystreet.map_type = OpenLayers.Layer.WMTS; - - // Set DPI - default is 72 - OpenLayers.DOTS_PER_INCH = fixmystreet.wmts_config.tile_dpi; - - fixmystreet.map_options = { - maxExtent: layer_bounds, - units: 'm', - scales: fixmystreet.wmts_config.scales - }; - - fixmystreet.layer_options = [{ - projection: new OpenLayers.Projection(fixmystreet.wmts_config.map_projection), - name: fixmystreet.wmts_config.layer_name, - layer: fixmystreet.wmts_config.layer_name, - formatSuffix: fixmystreet.wmts_config.tile_suffix.replace(".", ""), - matrixSet: fixmystreet.wmts_config.matrix_set, - requestEncoding: "REST", - url: fixmystreet.wmts_config.tile_url, - style: fixmystreet.wmts_config.layer_style, - matrixIds: matrix_ids, - tileOrigin: new OpenLayers.LonLat(fixmystreet.wmts_config.origin_x, fixmystreet.wmts_config.origin_y) - }]; - - // Give main code a new bbox_strategy that translates between - // lat/lon and our WMTS layer's coordinates - fixmystreet.bbox_strategy = new OpenLayers.Strategy.ReprojectBBOX({ratio: 1}); + + setup_wmts_base_map(); } -OpenLayers.Strategy.ReprojectBBOX = OpenLayers.Class(OpenLayers.Strategy.BBOX, { - getMapBounds: function() { - // Get the map bounds but return them in lat/lon, not - // local coordinates - if (this.layer.map === null) { - return null; - } - - var localBounds = this.layer.map.getExtent(); - // Transform bound corners into WGS84 - localBounds.transform( new OpenLayers.Projection(fixmystreet.wmts_config.map_projection), new OpenLayers.Projection("EPSG:4326") ); - return localBounds; - }, - - CLASS_NAME: "OpenLayers.Strategy.ReprojectBBOX" -}); - function fms_marker_size_for_zoom(zoom) { if (zoom >= 7) { return 'normal'; diff --git a/web/js/map-wmts-zurich.js b/web/js/map-wmts-zurich.js index 9e0555079..aa673f52d 100644 --- a/web/js/map-wmts-zurich.js +++ b/web/js/map-wmts-zurich.js @@ -2,6 +2,117 @@ * Maps for FMZ using Zurich council's WMTS tile server */ +// From 'fullExtent' from http://www.gis.stadt-zuerich.ch/maps/rest/services/tiled95/LuftbildHybrid/MapServer?f=pjson +var layer_bounds = new OpenLayers.Bounds( + 2676000.9069999997, // W + 1241399.842, // S + 2689900.9069999997, // E + 1254599.842); // N + +var matrix_ids = [ + // The two highest zoom levels are pretty much useless so they're disabled. + // { + // "matrixHeight": 882, + // "scaleDenominator": 241905.24571522293, + // "identifier": "0", + // "tileWidth": 512, + // "supportedCRS": "urn:ogc:def:crs:EPSG::2056", + // "tileHeight": 512, + // "matrixWidth": 868 + // }, + // { + // "matrixHeight": 1764, + // "scaleDenominator": 120952.62285761147, + // "identifier": "1", + // "tileWidth": 512, + // "supportedCRS": "urn:ogc:def:crs:EPSG::2056", + // "tileHeight": 512, + // "matrixWidth": 1735 + // }, + + { + "matrixHeight": 3527, + "scaleDenominator": 60476.31142880573, + "identifier": "2", + "tileWidth": 512, + "supportedCRS": "urn:ogc:def:crs:EPSG::2056", + "tileHeight": 512, + "matrixWidth": 3470 + }, + { + "matrixHeight": 7053, + "scaleDenominator": 30238.155714402867, + "identifier": "3", + "tileWidth": 512, + "supportedCRS": "urn:ogc:def:crs:EPSG::2056", + "tileHeight": 512, + "matrixWidth": 6939 + }, + { + "matrixHeight": 14106, + "scaleDenominator": 15119.077857201433, + "identifier": "4", + "tileWidth": 512, + "supportedCRS": "urn:ogc:def:crs:EPSG::2056", + "tileHeight": 512, + "matrixWidth": 13877 + }, + { + "matrixHeight": 28211, + "scaleDenominator": 7559.538928600717, + "identifier": "5", + "tileWidth": 512, + "supportedCRS": "urn:ogc:def:crs:EPSG::2056", + "tileHeight": 512, + "matrixWidth": 27753 + }, + { + "matrixHeight": 56422, + "scaleDenominator": 3779.7694643003583, + "identifier": "6", + "tileWidth": 512, + "supportedCRS": "urn:ogc:def:crs:EPSG::2056", + "tileHeight": 512, + "matrixWidth": 55505 + }, + { + "matrixHeight": 112844, + "scaleDenominator": 1889.8847321501792, + "identifier": "7", + "tileWidth": 512, + "supportedCRS": "urn:ogc:def:crs:EPSG::2056", + "tileHeight": 512, + "matrixWidth": 111010 + }, + { + "matrixHeight": 225687, + "scaleDenominator": 944.9423660750896, + "identifier": "8", + "tileWidth": 512, + "supportedCRS": "urn:ogc:def:crs:EPSG::2056", + "tileHeight": 512, + "matrixWidth": 222020 + }, + { + "matrixHeight": 451374, + "scaleDenominator": 472.4711830375448, + "identifier": "9", + "tileWidth": 512, + "supportedCRS": "urn:ogc:def:crs:EPSG::2056", + "tileHeight": 512, + "matrixWidth": 444039 + }, + { + "matrixHeight": 902748, + "scaleDenominator": 236.2355915187724, + "identifier": "10", + "tileWidth": 512, + "supportedCRS": "urn:ogc:def:crs:EPSG::2056", + "tileHeight": 512, + "matrixWidth": 888078 + } +]; + function fixmystreet_zurich_admin_drag() { var admin_drag = new OpenLayers.Control.DragFeature( fixmystreet.markers, { onComplete: function(feature, e) { @@ -69,199 +180,17 @@ $(function(){ fixmystreet.controls.push( new OpenLayers.Control.PermalinkFMS('key-tool-problems-nearby', '/around') ); } - fixmystreet.map_type = OpenLayers.Layer.WMTS; - - // Set DPI - default is 72 - OpenLayers.DOTS_PER_INCH = 96; - - fixmystreet.map_options = { - maxExtent: new OpenLayers.Bounds(676000, 241402, 689896, 254596), - units: 'm', - scales: [ '64000', '32000', '16000', '8000', '4000', '2000', '1000', '500', '250' ] - }; - - var layer_options = { - projection: new OpenLayers.Projection("EPSG:21781"), - name: "tiled_LuftbildHybrid", - layer: "tiled_LuftbildHybrid", - matrixSet: "default028mm", - requestEncoding: "REST", - url: "//www.gis.stadt-zuerich.ch/maps/rest/services/tiled/LuftbildHybrid/MapServer/WMTS/tile/", - style: "default", - matrixIds: [ - // { - // "identifier": "0", - // "matrixHeight": 903, - // "matrixWidth": 889, - // "scaleDenominator": 236235.59151877242, - // "supportedCRS": "urn:ogc:def:crs:EPSG::21781", - // "tileHeight": 512, - // "tileWidth": 512, - // "topLeftCorner": { - // "lat": 30814423, - // "lon": -29386322 - // } - // }, - // { - // "identifier": "1", - // "matrixHeight": 1806, - // "matrixWidth": 1777, - // "scaleDenominator": 118117.79575938621, - // "supportedCRS": "urn:ogc:def:crs:EPSG::21781", - // "tileHeight": 512, - // "tileWidth": 512, - // "topLeftCorner": { - // "lat": 30814423, - // "lon": -29386322 - // } - // }, - { - "identifier": "2", - "matrixHeight": 3527, - "matrixWidth": 3470, - "scaleDenominator": 60476.31142880573, - "supportedCRS": "urn:ogc:def:crs:EPSG::21781", - "tileHeight": 512, - "tileWidth": 512, - "topLeftCorner": { - "lat": 30814423, - "lon": -29386322 - } - }, - { - "identifier": "3", - "matrixHeight": 7053, - "matrixWidth": 6939, - "scaleDenominator": 30238.155714402867, - "supportedCRS": "urn:ogc:def:crs:EPSG::21781", - "tileHeight": 512, - "tileWidth": 512, - "topLeftCorner": { - "lat": 30814423, - "lon": -29386322 - } - }, - { - "identifier": "4", - "matrixHeight": 14106, - "matrixWidth": 13877, - "scaleDenominator": 15119.077857201433, - "supportedCRS": "urn:ogc:def:crs:EPSG::21781", - "tileHeight": 512, - "tileWidth": 512, - "topLeftCorner": { - "lat": 30814423, - "lon": -29386322 - } - }, - { - "identifier": "5", - "matrixHeight": 28211, - "matrixWidth": 27753, - "scaleDenominator": 7559.538928600717, - "supportedCRS": "urn:ogc:def:crs:EPSG::21781", - "tileHeight": 512, - "tileWidth": 512, - "topLeftCorner": { - "lat": 30814423, - "lon": -29386322 - } - }, - { - "identifier": "6", - "matrixHeight": 56422, - "matrixWidth": 55505, - "scaleDenominator": 3779.7694643003583, - "supportedCRS": "urn:ogc:def:crs:EPSG::21781", - "tileHeight": 512, - "tileWidth": 512, - "topLeftCorner": { - "lat": 30814423, - "lon": -29386322 - } - }, - { - "identifier": "7", - "matrixHeight": 112844, - "matrixWidth": 111010, - "scaleDenominator": 1889.8847321501792, - "supportedCRS": "urn:ogc:def:crs:EPSG::21781", - "tileHeight": 512, - "tileWidth": 512, - "topLeftCorner": { - "lat": 30814423, - "lon": -29386322 - } - }, - { - "identifier": "8", - "matrixHeight": 225687, - "matrixWidth": 222020, - "scaleDenominator": 944.9423660750896, - "supportedCRS": "urn:ogc:def:crs:EPSG::21781", - "tileHeight": 512, - "tileWidth": 512, - "topLeftCorner": { - "lat": 30814423, - "lon": -29386322 - } - }, - { - "identifier": "9", - "matrixHeight": 451374, - "matrixWidth": 444039, - "scaleDenominator": 472.4711830375448, - "supportedCRS": "urn:ogc:def:crs:EPSG::21781", - "tileHeight": 512, - "tileWidth": 512, - "topLeftCorner": { - "lat": 30814423, - "lon": -29386322 - } - }, - { - "identifier": "10", - "matrixHeight": 902748, - "matrixWidth": 888078, - "scaleDenominator": 236.2355915187724, - "supportedCRS": "urn:ogc:def:crs:EPSG::21781", - "tileHeight": 512, - "tileWidth": 512, - "topLeftCorner": { - "lat": 30814423, - "lon": -29386322 - } - } - ] - }; - fixmystreet.layer_options = [ - layer_options, OpenLayers.Util.applyDefaults({ - name: "Stadtplan3D", - layer: "Stadtplan3D", - url: "//www.gis.stadt-zuerich.ch/maps/rest/services/tiled/Stadtplan3D/MapServer/WMTS/tile/" - }, layer_options) - ]; - - // Give main code a new bbox_strategy that translates between - // lat/lon and our swiss coordinates - fixmystreet.bbox_strategy = new OpenLayers.Strategy.ZurichBBOX({ratio: 1}); + setup_wmts_base_map(); fixmystreet.area_format = { fillColor: 'none', strokeWidth: 4, strokeColor: 'black' }; } -OpenLayers.Strategy.ZurichBBOX = OpenLayers.Class(OpenLayers.Strategy.BBOX, { - getMapBounds: function() { - // Get the map bounds but return them in lat/lon, not - // Swiss coordinates - if (this.layer.map === null) { - return null; - } - - var swissBounds = this.layer.map.getExtent(); - // Transform bound corners into WGS84 - swissBounds.transform( new OpenLayers.Projection("EPSG:21781"), new OpenLayers.Projection("EPSG:4326") ); - return swissBounds; - }, - - CLASS_NAME: "OpenLayers.Strategy.ZurichBBOX" -}); +function fms_marker_size_for_zoom(zoom) { + if (zoom >= 6) { + return 'normal'; + } else if (zoom >= 3) { + return 'small'; + } else { + return 'mini'; + } +} |