diff options
Diffstat (limited to 'perllib/FixMyStreet/Map')
-rw-r--r-- | perllib/FixMyStreet/Map/Google.pm | 35 | ||||
-rw-r--r-- | perllib/FixMyStreet/Map/GoogleOL.pm | 22 | ||||
-rw-r--r-- | perllib/FixMyStreet/Map/OSM.pm | 31 | ||||
-rw-r--r-- | perllib/FixMyStreet/Map/OSM/MapQuest.pm | 6 | ||||
-rw-r--r-- | perllib/FixMyStreet/Map/Zurich.pm | 169 |
5 files changed, 234 insertions, 29 deletions
diff --git a/perllib/FixMyStreet/Map/Google.pm b/perllib/FixMyStreet/Map/Google.pm index c0d83e35a..9deefc033 100644 --- a/perllib/FixMyStreet/Map/Google.pm +++ b/perllib/FixMyStreet/Map/Google.pm @@ -3,12 +3,17 @@ # FixMyStreet:Map::Google # Google maps on FixMyStreet. # -# Copyright (c) 2010 UK Citizens Online Democracy. All rights reserved. +# Copyright (c) 2013 UK Citizens Online Democracy. All rights reserved. # Email: matthew@mysociety.org; WWW: http://www.mysociety.org/ package FixMyStreet::Map::Google; use strict; +use mySociety::Gaze; +use Utils; + +use constant ZOOM_LEVELS => 6; +use constant MIN_ZOOM_LEVEL => 13; # display_map C PARAMS # PARAMS include: @@ -17,9 +22,37 @@ use strict; # PINS is array of pins to show, location and colour sub display_map { my ($self, $c, %params) = @_; + + my $numZoomLevels = ZOOM_LEVELS; + my $zoomOffset = MIN_ZOOM_LEVEL; + if ($params{any_zoom}) { + $numZoomLevels = 19; + $zoomOffset = 0; + } + + # Adjust zoom level dependent upon population density + my $dist = $c->stash->{distance} + || mySociety::Gaze::get_radius_containing_population( $params{latitude}, $params{longitude}, 200_000 ); + my $default_zoom = $c->cobrand->default_map_zoom() ? $c->cobrand->default_map_zoom() : $numZoomLevels - 4; + $default_zoom = $numZoomLevels - 3 if $dist < 10; + + # Map centre may be overridden in the query string + $params{latitude} = Utils::truncate_coordinate($c->req->params->{lat} + 0) + if defined $c->req->params->{lat}; + $params{longitude} = Utils::truncate_coordinate($c->req->params->{lon} + 0) + if defined $c->req->params->{lon}; + + my $zoom = defined $c->req->params->{zoom} ? $c->req->params->{zoom} + 0 : $default_zoom; + $zoom = $numZoomLevels - 1 if $zoom >= $numZoomLevels; + $zoom = 0 if $zoom < 0; + $params{zoom_act} = $zoomOffset + $zoom; + $c->stash->{map} = { %params, type => 'google', + zoom => $zoom, + zoomOffset => $zoomOffset, + numZoomLevels => $numZoomLevels, }; } diff --git a/perllib/FixMyStreet/Map/GoogleOL.pm b/perllib/FixMyStreet/Map/GoogleOL.pm new file mode 100644 index 000000000..64baf8d36 --- /dev/null +++ b/perllib/FixMyStreet/Map/GoogleOL.pm @@ -0,0 +1,22 @@ +#!/usr/bin/perl +# +# FixMyStreet:Map::GoogleOL +# Google maps on FixMyStreet, using OpenLayers. +# +# Copyright (c) 2013 UK Citizens Online Democracy. All rights reserved. +# Email: matthew@mysociety.org; WWW: http://www.mysociety.org/ + +package FixMyStreet::Map::GoogleOL; +use parent 'FixMyStreet::Map::OSM'; + +use strict; + +sub map_type { + return '""'; +} + +sub map_template { + return 'google-ol'; +} + +1; diff --git a/perllib/FixMyStreet/Map/OSM.pm b/perllib/FixMyStreet/Map/OSM.pm index 6b3bebba2..74af0e9f3 100644 --- a/perllib/FixMyStreet/Map/OSM.pm +++ b/perllib/FixMyStreet/Map/OSM.pm @@ -13,7 +13,7 @@ use Math::Trig; use mySociety::Gaze; use Utils; -use constant ZOOM_LEVELS => 5; +use constant ZOOM_LEVELS => 6; use constant MIN_ZOOM_LEVEL => 13; sub map_type { @@ -55,15 +55,15 @@ sub display_map { my $numZoomLevels = ZOOM_LEVELS; my $zoomOffset = MIN_ZOOM_LEVEL; if ($params{any_zoom}) { - $numZoomLevels = 18; + $numZoomLevels = 19; $zoomOffset = 0; } # Adjust zoom level dependent upon population density my $dist = $c->stash->{distance} || mySociety::Gaze::get_radius_containing_population( $params{latitude}, $params{longitude}, 200_000 ); - my $default_zoom = $c->cobrand->default_map_zoom() ? $c->cobrand->default_map_zoom() : $numZoomLevels - 3; - $default_zoom = $numZoomLevels - 2 if $dist < 10; + my $default_zoom = $c->cobrand->default_map_zoom() ? $c->cobrand->default_map_zoom() : $numZoomLevels - 4; + $default_zoom = $numZoomLevels - 3 if $dist < 10; # Map centre may be overridden in the query string $params{latitude} = Utils::truncate_coordinate($c->req->params->{lat} + 0) @@ -94,29 +94,6 @@ sub display_map { }; } -sub map_pins { - my ($self, $c, $interval) = @_; - - my $bbox = $c->req->param('bbox'); - my ( $min_lon, $min_lat, $max_lon, $max_lat ) = split /,/, $bbox; - - my ( $around_map, $around_map_list, $nearby, $dist ) = - FixMyStreet::Map::map_features_bounds( $c, $min_lon, $min_lat, $max_lon, $max_lat, $interval ); - - # create a list of all the pins - my @pins = map { - # Here we might have a DB::Problem or a DB::Nearby, we always want the problem. - my $p = (ref $_ eq 'FixMyStreet::App::Model::DB::Nearby') ? $_->problem : $_; - my $colour = $c->cobrand->pin_colour( $p, 'around' ); - [ $p->latitude, $p->longitude, - $colour, - $p->id, $p->title - ] - } @$around_map, @$nearby; - - return (\@pins, $around_map_list, $nearby, $dist); -} - sub compass { my ( $x, $y, $z ) = @_; return { diff --git a/perllib/FixMyStreet/Map/OSM/MapQuest.pm b/perllib/FixMyStreet/Map/OSM/MapQuest.pm index 4751679f5..a7f1b334e 100644 --- a/perllib/FixMyStreet/Map/OSM/MapQuest.pm +++ b/perllib/FixMyStreet/Map/OSM/MapQuest.pm @@ -15,6 +15,10 @@ sub map_type { return 'OpenLayers.Layer.OSM.MapQuestOpen'; } +sub map_template { + return 'mapquest-attribution'; +} + sub map_tiles { my ( $self, %params ) = @_; my ( $x, $y, $z ) = ( $params{x_tile}, $params{y_tile}, $params{zoom_act} ); @@ -28,7 +32,7 @@ sub map_tiles { } sub base_tile_url { - return 'mqcdn.com/tiles/1.0.0/osm/'; + return 'mqcdn.com/tiles/1.0.0/map/'; } 1; diff --git a/perllib/FixMyStreet/Map/Zurich.pm b/perllib/FixMyStreet/Map/Zurich.pm new file mode 100644 index 000000000..e09f8c90f --- /dev/null +++ b/perllib/FixMyStreet/Map/Zurich.pm @@ -0,0 +1,169 @@ +#!/usr/bin/perl +# +# 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 strict; +use Geo::Coordinates::CH1903; +use Math::Trig; +use Utils; + +use constant ZOOM_LEVELS => 8; +use constant DEFAULT_ZOOM => 5; +use constant MIN_ZOOM_LEVEL => 0; +use constant ID_OFFSET => 2; + +sub map_tiles { + my ( $self, %params ) = @_; + my ( $col, $row, $z ) = ( $params{x_tile}, $params{y_tile}, $params{matrix_id} ); + my $tile_url = $self->base_tile_url(); + return [ + "$tile_url/$z/" . ($row - 1) . "/" . ($col - 1) . ".jpg", + "$tile_url/$z/" . ($row - 1) . "/$col.jpg", + "$tile_url/$z/$row/" . ($col - 1) . ".jpg", + "$tile_url/$z/$row/$col.jpg", + ]; +} + +sub base_tile_url { + return '/maps/Hybrid/1.0.0/Hybrid/default/nativeTileMatrixSet'; +} + +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->req->params->{lat} + 0) + if defined $c->req->params->{lat}; + $params{longitude} = Utils::truncate_coordinate($c->req->params->{lon} + 0) + if defined $c->req->params->{lon}; + + my $zoom = defined $c->req->params->{zoom} + ? $c->req->params->{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; + + ($params{x_tile}, $params{y_tile}, $params{matrix_id}) = latlon_to_tile_with_adjust($params{latitude}, $params{longitude}, $zoom); + + foreach my $pin (@{$params{pins}}) { + ($pin->{px}, $pin->{py}) = latlon_to_px($pin->{latitude}, $pin->{longitude}, $params{x_tile}, $params{y_tile}, $zoom); + } + + $c->stash->{map} = { + %params, + type => 'zurich', + map_type => 'OpenLayers.Layer.WMTS', + tiles => $self->map_tiles( %params ), + copyright => $self->copyright(), + zoom => $zoom, + zoomOffset => MIN_ZOOM_LEVEL, + numZoomLevels => ZOOM_LEVELS, + }; +} + +# 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; + my @scales = ( '250000', '125000', '64000', '32000', '16000', '8000', '4000', '2000', '1000', '500' ); + my $tileOrigin = { lat => 30814423, lon => -29386322 }; + my $tileSize = 256; + my $res = $scales[$matrix_id] / (39.3701 * 96); # OpenLayers.INCHES_PER_UNIT[units] * OpenLayers.DOTS_PER_INCH + + my $fx = ( $x - $tileOrigin->{lon} ) / ($res * $tileSize); + my $fy = ( $tileOrigin->{lat} - $y ) / ($res * $tileSize); + + return ( $fx, $fy, $matrix_id ); +} + +# 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). +sub latlon_to_tile_with_adjust($$$) { + my ($lat, $lon, $zoom) = @_; + my ($x_tile, $y_tile, $matrix_id) = latlon_to_tile($lat, $lon, $zoom); + + # Try and have point near centre of map + if ($x_tile - int($x_tile) > 0.5) { + $x_tile += 1; + } + 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' ); + my $tileOrigin = { lat => 30814423, lon => -29386322 }; + my $tileSize = 256; + my $res = $scales[$matrix_id] / (39.3701 * 96); # OpenLayers.INCHES_PER_UNIT[units] * OpenLayers.DOTS_PER_INCH + + my $x = $fx * $res * $tileSize + $tileOrigin->{lon}; + my $y = $tileOrigin->{lat} - $fy * $res * $tileSize; + + my ($lat, $lon) = Geo::Coordinates::CH1903::to_latlon($x, $y); + + 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 ($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); +} + +# 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 = 256 * ($p - $c + 1); + $p = int($p + .5 * ($p <=> 0)); + return $p; +} + +sub click_to_tile { + my ($pin_tile, $pin) = @_; + $pin -= 256 while $pin > 256; + $pin += 256 while $pin < 0; + return $pin_tile + $pin / 256; +} + +# 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->req->params->{zoom} ? $c->req->params->{zoom} : DEFAULT_ZOOM); + my ($lat, $lon) = tile_to_latlon($tile_x, $tile_y, $zoom); + return ( $lat, $lon ); +} + +1; |