diff options
-rw-r--r-- | perllib/FixMyStreet/Map/OSM.pm | 71 | ||||
-rw-r--r-- | perllib/FixMyStreet/Map/OSM/CycleMap.pm | 71 | ||||
-rw-r--r-- | perllib/FixMyStreet/Map/OSM/StreetView.pm | 70 | ||||
-rw-r--r-- | perllib/FixMyStreet/Map/Tilma/OL/1_10k.pm | 83 | ||||
-rw-r--r-- | perllib/FixMyStreet/Map/Tilma/OL/StreetView.pm | 81 | ||||
-rw-r--r-- | web/js/OpenLayers.Projection.OrdnanceSurvey.js | 489 | ||||
-rw-r--r-- | web/js/map-OpenStreetMap.js | 150 | ||||
-rw-r--r-- | web/js/map-streetview.js | 88 | ||||
-rw-r--r-- | web/js/map-tilma-ol.js | 42 |
9 files changed, 1145 insertions, 0 deletions
diff --git a/perllib/FixMyStreet/Map/OSM.pm b/perllib/FixMyStreet/Map/OSM.pm new file mode 100644 index 000000000..ccbb3ca53 --- /dev/null +++ b/perllib/FixMyStreet/Map/OSM.pm @@ -0,0 +1,71 @@ +#!/usr/bin/perl +# +# FixMyStreet:Map::OSM +# OSM maps on FixMyStreet. +# +# Copyright (c) 2010 UK Citizens Online Democracy. All rights reserved. +# Email: matthew@mysociety.org; WWW: http://www.mysociety.org/ + +package FixMyStreet::Map; + +use strict; +use mySociety::Web qw(ent); + +sub header_js { + return ' +<script type="text/javascript" src="http://openlayers.org/api/OpenLayers.js"></script> +<script type="text/javascript" src="/js/map-OpenStreetMap.js"></script> +<script type="text/javascript" src="/js/OpenLayers.Projection.OrdnanceSurvey.js"></script> +'; +} + +# display_map Q PARAMS +# PARAMS include: +# EASTING, NORTHING for the centre point of the map +# TYPE is 1 if the map is clickable, 2 if clickable and has a form upload, +# 0 if not clickable +# PINS is array of pins to show, location and colour +# PRE/POST are HTML to show above/below map +sub display_map { + my ($q, %params) = @_; + $params{pre} ||= ''; + $params{post} ||= ''; + + foreach my $pin (@{$params{pins}}) { + } + + my $out = FixMyStreet::Map::header($q, $params{type}); + my $copyright = _('Map © <a href="http://www.openstreetmap.org/">OpenStreetMap</a> and contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>'); + $out .= <<EOF; +<script type="text/javascript"> +var fixmystreet = { + 'easting': $params{easting}, + 'northing': $params{northing}, + 'map_type': OpenLayers.Layer.OSM.Mapnik +} +</script> +<div id="map_box"> + $params{pre} + <div id="map"></div> + <p id="copyright">$copyright</p> + $params{post} +</div> +<div id="side"> +EOF + return $out; +} + +sub display_map_end { + my ($type) = @_; + my $out = '</div>'; + $out .= '</form>' if ($type); + return $out; +} + +sub display_pin { +} + +sub map_pins { +} + +1; diff --git a/perllib/FixMyStreet/Map/OSM/CycleMap.pm b/perllib/FixMyStreet/Map/OSM/CycleMap.pm new file mode 100644 index 000000000..01c51acf4 --- /dev/null +++ b/perllib/FixMyStreet/Map/OSM/CycleMap.pm @@ -0,0 +1,71 @@ +#!/usr/bin/perl +# +# FixMyStreet:Map::OSM::CycleMap +# OSM CycleMap maps on FixMyStreet. +# +# Copyright (c) 2010 UK Citizens Online Democracy. All rights reserved. +# Email: matthew@mysociety.org; WWW: http://www.mysociety.org/ + +package FixMyStreet::Map; + +use strict; +use mySociety::Web qw(ent); + +sub header_js { + return ' +<script type="text/javascript" src="http://openlayers.org/api/OpenLayers.js"></script> +<script type="text/javascript" src="/js/map-OpenStreetMap.js"></script> +<script type="text/javascript" src="/js/OpenLayers.Projection.OrdnanceSurvey.js"></script> +'; +} + +# display_map Q PARAMS +# PARAMS include: +# EASTING, NORTHING for the centre point of the map +# TYPE is 1 if the map is clickable, 2 if clickable and has a form upload, +# 0 if not clickable +# PINS is array of pins to show, location and colour +# PRE/POST are HTML to show above/below map +sub display_map { + my ($q, %params) = @_; + $params{pre} ||= ''; + $params{post} ||= ''; + + foreach my $pin (@{$params{pins}}) { + } + + my $out = FixMyStreet::Map::header($q, $params{type}); + my $copyright = _('Map © <a href="http://www.openstreetmap.org/">OpenStreetMap</a> and contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>'); + $out .= <<EOF; +<script type="text/javascript"> +var fixmystreet = { + 'easting': $params{easting}, + 'northing': $params{northing}, + 'map_type': OpenLayers.Layer.OSM.CycleMap +} +</script> +<div id="map_box"> + $params{pre} + <div id="map"></div> + <p id="copyright">$copyright</p> + $params{post} +</div> +<div id="side"> +EOF + return $out; +} + +sub display_map_end { + my ($type) = @_; + my $out = '</div>'; + $out .= '</form>' if ($type); + return $out; +} + +sub display_pin { +} + +sub map_pins { +} + +1; diff --git a/perllib/FixMyStreet/Map/OSM/StreetView.pm b/perllib/FixMyStreet/Map/OSM/StreetView.pm new file mode 100644 index 000000000..08f677d25 --- /dev/null +++ b/perllib/FixMyStreet/Map/OSM/StreetView.pm @@ -0,0 +1,70 @@ +#!/usr/bin/perl +# +# FixMyStreet:Map::OSM::StreetView +# OSM StreetView maps on FixMyStreet. +# +# Copyright (c) 2010 UK Citizens Online Democracy. All rights reserved. +# Email: matthew@mysociety.org; WWW: http://www.mysociety.org/ + +package FixMyStreet::Map; + +use strict; +use mySociety::Web qw(ent); + +sub header_js { + return ' +<script type="text/javascript" src="http://openlayers.org/api/OpenLayers.js"></script> +<script type="text/javascript" src="/js/map-streetview.js"></script> +<script type="text/javascript" src="/js/OpenLayers.Projection.OrdnanceSurvey.js"></script> +'; +} + +# display_map Q PARAMS +# PARAMS include: +# EASTING, NORTHING for the centre point of the map +# TYPE is 1 if the map is clickable, 2 if clickable and has a form upload, +# 0 if not clickable +# PINS is array of pins to show, location and colour +# PRE/POST are HTML to show above/below map +sub display_map { + my ($q, %params) = @_; + $params{pre} ||= ''; + $params{post} ||= ''; + + foreach my $pin (@{$params{pins}}) { + } + + my $out = FixMyStreet::Map::header($q, $params{type}); + my $copyright = _('Map contains Ordnance Survey data © Crown copyright and database right 2010.'); + $out .= <<EOF; +<script type="text/javascript"> +var fixmystreet = { + 'easting': $params{easting}, + 'northing': $params{northing} +} +</script> +<div id="map_box"> + $params{pre} + <div id="map"></div> + <p id="copyright">$copyright</p> + $params{post} +</div> +<div id="side"> +EOF + return $out; +} + +sub display_map_end { + my ($type) = @_; + my $out = '</div>'; + $out .= '</form>' if ($type); + return $out; +} + +sub display_pin { +} + +sub map_pins { +} + +1; diff --git a/perllib/FixMyStreet/Map/Tilma/OL/1_10k.pm b/perllib/FixMyStreet/Map/Tilma/OL/1_10k.pm new file mode 100644 index 000000000..b1fe0126d --- /dev/null +++ b/perllib/FixMyStreet/Map/Tilma/OL/1_10k.pm @@ -0,0 +1,83 @@ +#!/usr/bin/perl +# +# FixMyStreet:Map::Tilma::1_10k_OL +# Using tilma.mysociety.org with OpenLayers +# +# Copyright (c) 2010 UK Citizens Online Democracy. All rights reserved. +# Email: matthew@mysociety.org; WWW: http://www.mysociety.org/ + +package FixMyStreet::Map; + +use strict; + +use constant TILE_WIDTH => 254; +use constant TIF_SIZE_M => 5000; +use constant TIF_SIZE_PX => 7874; +use constant SCALE_FACTOR => TIF_SIZE_M / (TIF_SIZE_PX / TILE_WIDTH); +use constant TILE_TYPE => '10k-full'; + +sub header_js { + return ' +<script type="text/javascript" src="http://openlayers.org/api/OpenLayers.js"></script> +<script type="text/javascript" src="/js/map-tilma-ol.js"></script> +'; +} + +# display_map Q PARAMS +# PARAMS include: +# EASTING, NORTHING for the centre point of the map +# TYPE is 1 if the map is clickable, 2 if clickable and has a form upload, +# 0 if not clickable +# PINS is array of pins to show, location and colour +# PRE/POST are HTML to show above/below map +sub display_map { + my ($q, %params) = @_; + $params{pre} ||= ''; + $params{post} ||= ''; + + foreach my $pin (@{$params{pins}}) { + } + + my $out = FixMyStreet::Map::header($q, $params{type}); + my $tile_width = TILE_WIDTH; + my $tile_type = TILE_TYPE; + my $sf = SCALE_FACTOR / TILE_WIDTH; + my $copyright = _('© Crown copyright. All rights reserved. Ministry of Justice 100037819 2008.'); + $out .= <<EOF; +<script type="text/javascript"> +var fixmystreet = { + 'tilewidth': $tile_width, + 'tileheight': $tile_width, + 'easting': $params{easting}, + 'northing': $params{northing}, + 'tile_type': '$tile_type', + 'maxResolution': $sf +}; +</script> +<div id="map_box"> + $params{pre} + <div id="map"> + <div id="watermark"></div> + </div> + <p id="copyright">$copyright</p> +$params{post} +</div> +<div id="side"> +EOF + return $out; +} + +sub display_map_end { + my ($type) = @_; + my $out = '</div>'; + $out .= '</form>' if ($type); + return $out; +} + +sub display_pin { +} + +sub map_pins { +} + +1; diff --git a/perllib/FixMyStreet/Map/Tilma/OL/StreetView.pm b/perllib/FixMyStreet/Map/Tilma/OL/StreetView.pm new file mode 100644 index 000000000..7ef372351 --- /dev/null +++ b/perllib/FixMyStreet/Map/Tilma/OL/StreetView.pm @@ -0,0 +1,81 @@ +#!/usr/bin/perl +# +# FixMyStreet:Map::TilmaXY +# Using tilma.mysociety.org but accessing images directly. +# +# Copyright (c) 2010 UK Citizens Online Democracy. All rights reserved. +# Email: matthew@mysociety.org; WWW: http://www.mysociety.org/ + +package FixMyStreet::Map; + +use strict; + +use constant TILE_WIDTH => 250; +use constant TIF_SIZE_M => 5000; +use constant TIF_SIZE_PX => 5000; +use constant SCALE_FACTOR => TIF_SIZE_M / (TIF_SIZE_PX / TILE_WIDTH); +use constant TILE_TYPE => 'streetview'; + +sub header_js { + return ' +<script type="text/javascript" src="http://openlayers.org/api/OpenLayers.js"></script> +<script type="text/javascript" src="/js/map-tilma-ol.js"></script> +'; +} + +# display_map Q PARAMS +# PARAMS include: +# EASTING, NORTHING for the centre point of the map +# TYPE is 1 if the map is clickable, 2 if clickable and has a form upload, +# 0 if not clickable +# PINS is array of pins to show, location and colour +# PRE/POST are HTML to show above/below map +sub display_map { + my ($q, %params) = @_; + $params{pre} ||= ''; + $params{post} ||= ''; + + foreach my $pin (@{$params{pins}}) { + } + + my $out = FixMyStreet::Map::header($q, $params{type}); + my $tile_width = TILE_WIDTH; + my $tile_type = TILE_TYPE; + my $sf = SCALE_FACTOR / TILE_WIDTH; + my $copyright = _('Map contains Ordnance Survey data © Crown copyright and database right 2010.'); + $out .= <<EOF; +<script type="text/javascript"> +var fixmystreet = { + 'tilewidth': $tile_width, + 'tileheight': $tile_width, + 'easting': $params{easting}, + 'northing': $params{northing}, + 'tile_type': '$tile_type', + 'maxResolution': $sf +}; +</script> +<div id="map_box"> + $params{pre} + <div id="map"></div> + <p id="copyright">$copyright</p> + $params{post} +</div> +<div id="side"> +EOF + return $out; +} + +sub display_map_end { + my ($type) = @_; + my $out = '</div>'; + $out .= '</form>' if ($type); + return $out; +} + +sub display_pin { +} + +sub map_pins { +} + +1; diff --git a/web/js/OpenLayers.Projection.OrdnanceSurvey.js b/web/js/OpenLayers.Projection.OrdnanceSurvey.js new file mode 100644 index 000000000..bb596d3bf --- /dev/null +++ b/web/js/OpenLayers.Projection.OrdnanceSurvey.js @@ -0,0 +1,489 @@ +/** + * OpenLayers OSGB Grid Projection Transformations + * + * Conversion to OpenLayers by Thomas Wood (grand.edgemaster@gmail.com) + * + * this program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * this program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * --------------------------------------------------------------------------- + * + * PLEASE DO NOT HOTLINK THIS, save this onto your own server + * - I cannot guarantee this file will remain here forever. + * + * --------------------------------------------------------------------------- + * + * Credits: + * Based from the geotools js library by Paul Dixon + * GeoTools javascript coordinate transformations + * http://files.dixo.net/geotools.html + * + * Portions of this file copyright (c)2005 Paul Dixon (paul@elphin.com) + * + * The algorithm used by the script for WGS84-OSGB36 conversions is derived + * from an OSGB spreadsheet (www.gps.gov.uk) with permission. This has been + * adapted into Perl by Ian Harris, and into PHP by Barry Hunter. Conversion + * accuracy is in the order of 7m for 90% of Great Britain, and should be + * be similar to the conversion made by a typical GPSr + * + */ + +OpenLayers.Projection.OS = { + + /** + * Method: projectForwardBritish + * Given an object with x and y properties in EPSG:4326, modify the x,y + * properties on the object to be the OSGB36 (transverse mercator) + * projected coordinates. + * + * Parameters: + * point - {Object} An object with x and y properties. + * + * Returns: + * {Object} The point, with the x and y properties transformed to spherical + * mercator. + */ + projectForwardBritish: function(point) { + var x1 = OpenLayers.Projection.OS.Lat_Long_H_to_X(point.y,point.x,0,6378137.00,6356752.313); + var y1 = OpenLayers.Projection.OS.Lat_Long_H_to_Y(point.y,point.x,0,6378137.00,6356752.313); + var z1 = OpenLayers.Projection.OS.Lat_H_to_Z (point.y, 0,6378137.00,6356752.313); + + var x2 = OpenLayers.Projection.OS.Helmert_X(x1,y1,z1,-446.448,-0.2470,-0.8421,20.4894); + var y2 = OpenLayers.Projection.OS.Helmert_Y(x1,y1,z1, 125.157,-0.1502,-0.8421,20.4894); + var z2 = OpenLayers.Projection.OS.Helmert_Z(x1,y1,z1,-542.060,-0.1502,-0.2470,20.4894); + + var lat2 = OpenLayers.Projection.OS.XYZ_to_Lat (x2,y2,z2,6377563.396,6356256.910); + var lon2 = OpenLayers.Projection.OS.XYZ_to_Long(x2,y2); + + point.x = OpenLayers.Projection.OS.Lat_Long_to_East (lat2,lon2,6377563.396,6356256.910,400000,0.999601272,49.00000,-2.00000); + point.y = OpenLayers.Projection.OS.Lat_Long_to_North(lat2,lon2,6377563.396,6356256.910,400000,-100000,0.999601272,49.00000,-2.00000); + + return point; + }, + + /** + * Method: projectInverseBritish + * Given an object with x and y properties in OSGB36 (transverse mercator), + * modify the x,y properties on the object to be the unprojected coordinates. + * + * Parameters: + * point - {Object} An object with x and y properties. + * + * Returns: + * {Object} The point, with the x and y properties transformed from + * OSGB36 to unprojected coordinates.. + */ + projectInverseBritish: function(point) { + var lat1 = OpenLayers.Projection.OS.E_N_to_Lat (point.x,point.y,6377563.396,6356256.910,400000,-100000,0.999601272,49.00000,-2.00000); + var lon1 = OpenLayers.Projection.OS.E_N_to_Long(point.x,point.y,6377563.396,6356256.910,400000,-100000,0.999601272,49.00000,-2.00000); + + var x1 = OpenLayers.Projection.OS.Lat_Long_H_to_X(lat1,lon1,0,6377563.396,6356256.910); + var y1 = OpenLayers.Projection.OS.Lat_Long_H_to_Y(lat1,lon1,0,6377563.396,6356256.910); + var z1 = OpenLayers.Projection.OS.Lat_H_to_Z (lat1, 0,6377563.396,6356256.910); + + var x2 = OpenLayers.Projection.OS.Helmert_X(x1,y1,z1,446.448 ,0.2470,0.8421,-20.4894); + var y2 = OpenLayers.Projection.OS.Helmert_Y(x1,y1,z1,-125.157,0.1502,0.8421,-20.4894); + var z2 = OpenLayers.Projection.OS.Helmert_Z(x1,y1,z1,542.060 ,0.1502,0.2470,-20.4894); + + var lat = OpenLayers.Projection.OS.XYZ_to_Lat(x2,y2,z2,6378137.000,6356752.313); + var lon = OpenLayers.Projection.OS.XYZ_to_Long(x2,y2); + + point.x = lon; + point.y = lat; + return point; + }, + + goog2osgb: function(point) { + return OpenLayers.Projection.OS.projectForwardBritish(OpenLayers.Layer.SphericalMercator.projectInverse(point)); + }, + + osgb2goog: function(point) { + return OpenLayers.Layer.SphericalMercator.projectForward(OpenLayers.Projection.OS.projectInverseBritish(point)); + }, + + /***** + * Mathematical functions + *****/ + E_N_to_Lat: function(East, North, a, b, e0, n0, f0, PHI0, LAM0) { + //Un-project Transverse Mercator eastings and northings back to latitude. + //eastings (East) and northings (North) in meters; _ + //ellipsoid axis dimensions (a & b) in meters; _ + //eastings (e0) and northings (n0) of false origin in meters; _ + //central meridian scale factor (f0) and _ + //latitude (PHI0) and longitude (LAM0) of false origin in decimal degrees. + + //Convert angle measures to radians + var Pi = 3.14159265358979; + var RadPHI0 = PHI0 * (Pi / 180); + var RadLAM0 = LAM0 * (Pi / 180); + + //Compute af0, bf0, e squared (e2), n and Et + var af0 = a * f0; + var bf0 = b * f0; + var e2 = (Math.pow(af0,2) - Math.pow(bf0,2)) / Math.pow(af0,2); + var n = (af0 - bf0) / (af0 + bf0); + var Et = East - e0; + + //Compute initial value for latitude (PHI) in radians + var PHId = OpenLayers.Projection.OS.InitialLat(North, n0, af0, RadPHI0, n, bf0); + + //Compute nu, rho and eta2 using value for PHId + var nu = af0 / (Math.sqrt(1 - (e2 * ( Math.pow(Math.sin(PHId),2))))); + var rho = (nu * (1 - e2)) / (1 - (e2 * Math.pow(Math.sin(PHId),2))); + var eta2 = (nu / rho) - 1; + + //Compute Latitude + var VII = (Math.tan(PHId)) / (2 * rho * nu); + var VIII = ((Math.tan(PHId)) / (24 * rho * Math.pow(nu,3))) * (5 + (3 * (Math.pow(Math.tan(PHId),2))) + eta2 - (9 * eta2 * (Math.pow(Math.tan(PHId),2)))); + var IX = ((Math.tan(PHId)) / (720 * rho * Math.pow(nu,5))) * (61 + (90 * ((Math.tan(PHId)) ^ 2)) + (45 * (Math.pow(Math.tan(PHId),4)))); + + var E_N_to_Lat = (180 / Pi) * (PHId - (Math.pow(Et,2) * VII) + (Math.pow(Et,4) * VIII) - ((Et ^ 6) * IX)); + + return (E_N_to_Lat); + }, + + E_N_to_Long: function(East, North, a, b, e0, n0, f0, PHI0, LAM0) { + //Un-project Transverse Mercator eastings and northings back to longitude. + //eastings (East) and northings (North) in meters; _ + //ellipsoid axis dimensions (a & b) in meters; _ + //eastings (e0) and northings (n0) of false origin in meters; _ + //central meridian scale factor (f0) and _ + //latitude (PHI0) and longitude (LAM0) of false origin in decimal degrees. + + //Convert angle measures to radians + var Pi = 3.14159265358979; + var RadPHI0 = PHI0 * (Pi / 180); + var RadLAM0 = LAM0 * (Pi / 180); + + //Compute af0, bf0, e squared (e2), n and Et + var af0 = a * f0; + var bf0 = b * f0; + var e2 = (Math.pow(af0,2) - Math.pow(bf0,2)) / Math.pow(af0,2); + var n = (af0 - bf0) / (af0 + bf0); + var Et = East - e0; + + //Compute initial value for latitude (PHI) in radians + var PHId = OpenLayers.Projection.OS.InitialLat(North, n0, af0, RadPHI0, n, bf0); + + //Compute nu, rho and eta2 using value for PHId + var nu = af0 / (Math.sqrt(1 - (e2 * (Math.pow(Math.sin(PHId),2))))); + var rho = (nu * (1 - e2)) / (1 - (e2 * Math.pow(Math.sin(PHId),2))); + var eta2 = (nu / rho) - 1; + + //Compute Longitude + var X = (Math.pow(Math.cos(PHId),-1)) / nu; + var XI = ((Math.pow(Math.cos(PHId),-1)) / (6 * Math.pow(nu,3))) * ((nu / rho) + (2 * (Math.pow(Math.tan(PHId),2)))); + var XII = ((Math.pow(Math.cos(PHId),-1)) / (120 * Math.pow(nu,5))) * (5 + (28 * (Math.pow(Math.tan(PHId),2))) + (24 * (Math.pow(Math.tan(PHId),4)))); + var XIIA = ((Math.pow(Math.cos(PHId),-1)) / (5040 * Math.pow(nu,7))) * (61 + (662 * (Math.pow(Math.tan(PHId),2))) + (1320 * (Math.pow(Math.tan(PHId),4))) + (720 * (Math.pow(Math.tan(PHId),6)))); + + var E_N_to_Long = (180 / Pi) * (RadLAM0 + (Et * X) - (Math.pow(Et,3) * XI) + (Math.pow(Et,5) * XII) - (Math.pow(Et,7) * XIIA)); + + return E_N_to_Long; + }, + + InitialLat: function(North, n0, afo, PHI0, n, bfo) { + //Compute initial value for Latitude (PHI) IN RADIANS. + //northing of point (North) and northing of false origin (n0) in meters; _ + //semi major axis multiplied by central meridian scale factor (af0) in meters; _ + //latitude of false origin (PHI0) IN RADIANS; _ + //n (computed from a, b and f0) and _ + //ellipsoid semi major axis multiplied by central meridian scale factor (bf0) in meters. + + //First PHI value (PHI1) + var PHI1 = ((North - n0) / afo) + PHI0; + + //Calculate M + var M = OpenLayers.Projection.OS.Marc(bfo, n, PHI0, PHI1); + + //Calculate new PHI value (PHI2) + var PHI2 = ((North - n0 - M) / afo) + PHI1; + + //Iterate to get final value for InitialLat + while (Math.abs(North - n0 - M) > 0.00001) + { + PHI2 = ((North - n0 - M) / afo) + PHI1; + M = OpenLayers.Projection.OS.Marc(bfo, n, PHI0, PHI2); + PHI1 = PHI2; + } + return PHI2; + }, + + Lat_Long_H_to_X: function(PHI, LAM, H, a, b) { + // Convert geodetic coords lat (PHI), long (LAM) and height (H) to cartesian X coordinate. + // Input: - _ + // Latitude (PHI)& Longitude (LAM) both in decimal degrees; _ + // Ellipsoidal height (H) and ellipsoid axis dimensions (a & b) all in meters. + + // Convert angle measures to radians + var Pi = 3.14159265358979; + var RadPHI = PHI * (Pi / 180); + var RadLAM = LAM * (Pi / 180); + + // Compute eccentricity squared and nu + var e2 = (Math.pow(a,2) - Math.pow(b,2)) / Math.pow(a,2); + var V = a / (Math.sqrt(1 - (e2 * ( Math.pow(Math.sin(RadPHI),2))))); + + // Compute X + return (V + H) * (Math.cos(RadPHI)) * (Math.cos(RadLAM)); + }, + + + Lat_Long_H_to_Y: function(PHI, LAM, H, a, b) { + // Convert geodetic coords lat (PHI), long (LAM) and height (H) to cartesian Y coordinate. + // Input: - _ + // Latitude (PHI)& Longitude (LAM) both in decimal degrees; _ + // Ellipsoidal height (H) and ellipsoid axis dimensions (a & b) all in meters. + + // Convert angle measures to radians + var Pi = 3.14159265358979; + var RadPHI = PHI * (Pi / 180); + var RadLAM = LAM * (Pi / 180); + + // Compute eccentricity squared and nu + var e2 = (Math.pow(a,2) - Math.pow(b,2)) / Math.pow(a,2); + var V = a / (Math.sqrt(1 - (e2 * ( Math.pow(Math.sin(RadPHI),2))) )); + + // Compute Y + return (V + H) * (Math.cos(RadPHI)) * (Math.sin(RadLAM)); + }, + + + Lat_H_to_Z: function(PHI, H, a, b) { + // Convert geodetic coord components latitude (PHI) and height (H) to cartesian Z coordinate. + // Input: - _ + // Latitude (PHI) decimal degrees; _ + // Ellipsoidal height (H) and ellipsoid axis dimensions (a & b) all in meters. + + // Convert angle measures to radians + var Pi = 3.14159265358979; + var RadPHI = PHI * (Pi / 180); + + // Compute eccentricity squared and nu + var e2 = (Math.pow(a,2) - Math.pow(b,2)) / Math.pow(a,2); + var V = a / (Math.sqrt(1 - (e2 * ( Math.pow(Math.sin(RadPHI),2)) ))); + + // Compute X + return ((V * (1 - e2)) + H) * (Math.sin(RadPHI)); + }, + + + Helmert_X: function(X,Y,Z,DX,Y_Rot,Z_Rot,s) { + + // (X, Y, Z, DX, Y_Rot, Z_Rot, s) + // Computed Helmert transformed X coordinate. + // Input: - _ + // cartesian XYZ coords (X,Y,Z), X translation (DX) all in meters ; _ + // Y and Z rotations in seconds of arc (Y_Rot, Z_Rot) and scale in ppm (s). + + // Convert rotations to radians and ppm scale to a factor + var Pi = 3.14159265358979; + var sfactor = s * 0.000001; + + var RadY_Rot = (Y_Rot / 3600) * (Pi / 180); + + var RadZ_Rot = (Z_Rot / 3600) * (Pi / 180); + + //Compute transformed X coord + return (X + (X * sfactor) - (Y * RadZ_Rot) + (Z * RadY_Rot) + DX); + }, + + + Helmert_Y: function(X,Y,Z,DY,X_Rot,Z_Rot,s) { + // Computed Helmert transformed Y coordinate. + // Input: - _ + // cartesian XYZ coords (X,Y,Z), Y translation (DY) all in meters ; _ + // X and Z rotations in seconds of arc (X_Rot, Z_Rot) and scale in ppm (s). + + // Convert rotations to radians and ppm scale to a factor + var Pi = 3.14159265358979; + var sfactor = s * 0.000001; + var RadX_Rot = (X_Rot / 3600) * (Pi / 180); + var RadZ_Rot = (Z_Rot / 3600) * (Pi / 180); + + // Compute transformed Y coord + return (X * RadZ_Rot) + Y + (Y * sfactor) - (Z * RadX_Rot) + DY; + }, + + + + Helmert_Z: function(X, Y, Z, DZ, X_Rot, Y_Rot, s) { + // Computed Helmert transformed Z coordinate. + // Input: - _ + // cartesian XYZ coords (X,Y,Z), Z translation (DZ) all in meters ; _ + // X and Y rotations in seconds of arc (X_Rot, Y_Rot) and scale in ppm (s). + // + // Convert rotations to radians and ppm scale to a factor + var Pi = 3.14159265358979; + var sfactor = s * 0.000001; + var RadX_Rot = (X_Rot / 3600) * (Pi / 180); + var RadY_Rot = (Y_Rot / 3600) * (Pi / 180); + + // Compute transformed Z coord + return (-1 * X * RadY_Rot) + (Y * RadX_Rot) + Z + (Z * sfactor) + DZ; + } , + + XYZ_to_Lat: function(X, Y, Z, a, b) { + // Convert XYZ to Latitude (PHI) in Dec Degrees. + // Input: - _ + // XYZ cartesian coords (X,Y,Z) and ellipsoid axis dimensions (a & b), all in meters. + + // this FUNCTION REQUIRES THE "Iterate_XYZ_to_Lat" FUNCTION + // this FUNCTION IS CALLED BY THE "XYZ_to_H" FUNCTION + + var RootXYSqr = Math.sqrt(Math.pow(X,2) + Math.pow(Y,2)); + var e2 = (Math.pow(a,2) - Math.pow(b,2)) / Math.pow(a,2); + var PHI1 = Math.atan2(Z , (RootXYSqr * (1 - e2)) ); + + var PHI = OpenLayers.Projection.OS.Iterate_XYZ_to_Lat(a, e2, PHI1, Z, RootXYSqr); + + var Pi = 3.14159265358979; + + return PHI * (180 / Pi); + }, + + + Iterate_XYZ_to_Lat: function(a, e2, PHI1, Z, RootXYSqr) { + // Iteratively computes Latitude (PHI). + // Input: - _ + // ellipsoid semi major axis (a) in meters; _ + // eta squared (e2); _ + // estimated value for latitude (PHI1) in radians; _ + // cartesian Z coordinate (Z) in meters; _ + // RootXYSqr computed from X & Y in meters. + + // this FUNCTION IS CALLED BY THE "XYZ_to_PHI" FUNCTION + // this FUNCTION IS ALSO USED ON IT'S OWN IN THE _ + // "Projection and Transformation Calculations.xls" SPREADSHEET + + + var V = a / (Math.sqrt(1 - (e2 * Math.pow(Math.sin(PHI1),2)))); + var PHI2 = Math.atan2((Z + (e2 * V * (Math.sin(PHI1)))) , RootXYSqr); + + while (Math.abs(PHI1 - PHI2) > 0.000000001) { + PHI1 = PHI2; + V = a / (Math.sqrt(1 - (e2 * Math.pow(Math.sin(PHI1),2)))); + PHI2 = Math.atan2((Z + (e2 * V * (Math.sin(PHI1)))) , RootXYSqr); + } + + return PHI2; + }, + + + XYZ_to_Long: function (X, Y) { + // Convert XYZ to Longitude (LAM) in Dec Degrees. + // Input: - _ + // X and Y cartesian coords in meters. + + var Pi = 3.14159265358979; + return Math.atan2(Y , X) * (180 / Pi); + }, + + Marc: function (bf0, n, PHI0, PHI) { + //Compute meridional arc. + //Input: - _ + // ellipsoid semi major axis multiplied by central meridian scale factor (bf0) in meters; _ + // n (computed from a, b and f0); _ + // lat of false origin (PHI0) and initial or final latitude of point (PHI) IN RADIANS. + + //this FUNCTION IS CALLED BY THE - _ + // "Lat_Long_to_North" and "InitialLat" FUNCTIONS + // this FUNCTION IS ALSO USED ON IT'S OWN IN THE "Projection and Transformation Calculations.xls" SPREADSHEET + + return bf0 * (((1 + n + ((5 / 4) * Math.pow(n,2)) + ((5 / 4) * Math.pow(n,3))) * (PHI - PHI0)) - (((3 * n) + (3 * Math.pow(n,2)) + ((21 / 8) * Math.pow(n,3))) * (Math.sin(PHI - PHI0)) * (Math.cos(PHI + PHI0))) + ((((15 / 8 + ) * Math.pow(n,2)) + ((15 / 8) * Math.pow(n,3))) * (Math.sin(2 * (PHI - PHI0))) * (Math.cos(2 * (PHI + PHI0)))) - (((35 / 24) * Math.pow(n,3)) * (Math.sin(3 * (PHI - PHI0))) * (Math.cos(3 * (PHI + PHI0))))); + }, + + Lat_Long_to_East: function (PHI, LAM, a, b, e0, f0, PHI0, LAM0) { + //Project Latitude and longitude to Transverse Mercator eastings. + //Input: - _ + // Latitude (PHI) and Longitude (LAM) in decimal degrees; _ + // ellipsoid axis dimensions (a & b) in meters; _ + // eastings of false origin (e0) in meters; _ + // central meridian scale factor (f0); _ + // latitude (PHI0) and longitude (LAM0) of false origin in decimal degrees. + + // Convert angle measures to radians + var Pi = 3.14159265358979; + var RadPHI = PHI * (Pi / 180); + var RadLAM = LAM * (Pi / 180); + var RadPHI0 = PHI0 * (Pi / 180); + var RadLAM0 = LAM0 * (Pi / 180); + + var af0 = a * f0; + var bf0 = b * f0; + var e2 = (Math.pow(af0,2) - Math.pow(bf0,2)) / Math.pow(af0,2); + var n = (af0 - bf0) / (af0 + bf0); + var nu = af0 / (Math.sqrt(1 - (e2 * Math.pow(Math.sin(RadPHI),2) ))); + var rho = (nu * (1 - e2)) / (1 - (e2 * Math.pow(Math.sin(RadPHI),2) )); + var eta2 = (nu / rho) - 1; + var p = RadLAM - RadLAM0; + + var IV = nu * (Math.cos(RadPHI)); + var V = (nu / 6) * ( Math.pow(Math.cos(RadPHI),3)) * ((nu / rho) - (Math.pow(Math.tan(RadPHI),2))); + var VI = (nu / 120) * (Math.pow(Math.cos(RadPHI),5)) * (5 - (18 * (Math.pow(Math.tan(RadPHI),2))) + (Math.pow(Math.tan(RadPHI),4)) + (14 * eta2) - (58 * (Math.pow(Math.tan(RadPHI),2)) * eta2)); + + return e0 + (p * IV) + (Math.pow(p,3) * V) + (Math.pow(p,5) * VI); + }, + + Lat_Long_to_North: function (PHI, LAM, a, b, e0, n0, f0, PHI0, LAM0) { + // Project Latitude and longitude to Transverse Mercator northings + // Input: - _ + // Latitude (PHI) and Longitude (LAM) in decimal degrees; _ + // ellipsoid axis dimensions (a & b) in meters; _ + // eastings (e0) and northings (n0) of false origin in meters; _ + // central meridian scale factor (f0); _ + // latitude (PHI0) and longitude (LAM0) of false origin in decimal degrees. + + // REQUIRES THE "Marc" FUNCTION + + // Convert angle measures to radians + var Pi = 3.14159265358979; + var RadPHI = PHI * (Pi / 180); + var RadLAM = LAM * (Pi / 180); + var RadPHI0 = PHI0 * (Pi / 180); + var RadLAM0 = LAM0 * (Pi / 180); + + var af0 = a * f0; + var bf0 = b * f0; + var e2 = (Math.pow(af0,2) - Math.pow(bf0,2)) / Math.pow(af0,2); + var n = (af0 - bf0) / (af0 + bf0); + var nu = af0 / (Math.sqrt(1 - (e2 * Math.pow(Math.sin(RadPHI),2)))); + var rho = (nu * (1 - e2)) / (1 - (e2 * Math.pow(Math.sin(RadPHI),2))); + var eta2 = (nu / rho) - 1; + var p = RadLAM - RadLAM0; + var M = OpenLayers.Projection.OS.Marc(bf0, n, RadPHI0, RadPHI); + + var I = M + n0; + var II = (nu / 2) * (Math.sin(RadPHI)) * (Math.cos(RadPHI)); + var III = ((nu / 24) * (Math.sin(RadPHI)) * (Math.pow(Math.cos(RadPHI),3))) * (5 - (Math.pow(Math.tan(RadPHI),2)) + (9 * eta2)); + var IIIA = ((nu / 720) * (Math.sin(RadPHI)) * (Math.pow(Math.cos(RadPHI),5))) * (61 - (58 * (Math.pow(Math.tan(RadPHI),2))) + (Math.pow(Math.tan(RadPHI),4))); + + return I + (Math.pow(p,2) * II) + (Math.pow(p,4) * III) + (Math.pow(p,6) * IIIA); + } + +}; + +/** + * Note: Two transforms declared + * Transforms from EPSG:4326 to EPSG:27700 and from EPSG:27700 to EPSG:4326 + * are set by this class. + */ +OpenLayers.Projection.addTransform("EPSG:4326", "EPSG:27700", + OpenLayers.Projection.OS.projectForwardBritish); +OpenLayers.Projection.addTransform("EPSG:27700", "EPSG:4326", + OpenLayers.Projection.OS.projectInverseBritish); +OpenLayers.Projection.addTransform("EPSG:900913", "EPSG:27700", + OpenLayers.Projection.OS.goog2osgb); +OpenLayers.Projection.addTransform("EPSG:27700", "EPSG:900913", + OpenLayers.Projection.OS.osgb2goog); diff --git a/web/js/map-OpenStreetMap.js b/web/js/map-OpenStreetMap.js new file mode 100644 index 000000000..04237e075 --- /dev/null +++ b/web/js/map-OpenStreetMap.js @@ -0,0 +1,150 @@ +YAHOO.util.Event.onContentReady('map', function() { + var map = new OpenLayers.Map("map", { + controls: [ + new OpenLayers.Control.ArgParser(), + //new OpenLayers.Control.LayerSwitcher(), + new OpenLayers.Control.Navigation(), + new OpenLayers.Control.PanZoom() + ], + displayProjection: new OpenLayers.Projection("EPSG:4326") + }); + var streetview = new fixmystreet.map_type("", { + zoomOffset: 14, + numZoomLevels: 4 + }); + map.addLayer(streetview); + + var centre = new OpenLayers.LonLat( fixmystreet.easting, fixmystreet.northing ); + centre.transform( + new OpenLayers.Projection("EPSG:27700"), + map.getProjectionObject() + ); + map.setCenter(centre, 2); +}); + + +// http://www.openstreetmap.org/openlayers/OpenStreetMap.js (added maxResolution) + +/** + * Namespace: Util.OSM + */ +OpenLayers.Util.OSM = {}; + +/** + * Constant: MISSING_TILE_URL + * {String} URL of image to display for missing tiles + */ +OpenLayers.Util.OSM.MISSING_TILE_URL = "http://www.openstreetmap.org/openlayers/img/404.png"; + +/** + * Property: originalOnImageLoadError + * {Function} Original onImageLoadError function. + */ +OpenLayers.Util.OSM.originalOnImageLoadError = OpenLayers.Util.onImageLoadError; + +/** + * Function: onImageLoadError + */ +OpenLayers.Util.onImageLoadError = function() { + if (this.src.match(/^http:\/\/[abc]\.[a-z]+\.openstreetmap\.org\//)) { + this.src = OpenLayers.Util.OSM.MISSING_TILE_URL; + } else if (this.src.match(/^http:\/\/[def]\.tah\.openstreetmap\.org\//)) { + // do nothing - this layer is transparent + } else { + OpenLayers.Util.OSM.originalOnImageLoadError; + } +}; + +/** + * Class: OpenLayers.Layer.OSM.Mapnik + * + * Inherits from: + * - <OpenLayers.Layer.OSM> + */ +OpenLayers.Layer.OSM.Mapnik = OpenLayers.Class(OpenLayers.Layer.OSM, { + /** + * Constructor: OpenLayers.Layer.OSM.Mapnik + * + * Parameters: + * name - {String} + * options - {Object} Hashtable of extra options to tag onto the layer + */ + initialize: function(name, options) { + var url = [ + "http://a.tile.openstreetmap.org/${z}/${x}/${y}.png", + "http://b.tile.openstreetmap.org/${z}/${x}/${y}.png", + "http://c.tile.openstreetmap.org/${z}/${x}/${y}.png" + ]; + options = OpenLayers.Util.extend({ + /* Below line added to OSM's file in order to allow minimum zoom level */ + maxResolution: 156543.0339/Math.pow(2, options.zoomOffset || 0), + numZoomLevels: 19, + buffer: 0 + }, options); + var newArguments = [name, url, options]; + OpenLayers.Layer.OSM.prototype.initialize.apply(this, newArguments); + }, + + CLASS_NAME: "OpenLayers.Layer.OSM.Mapnik" +}); + +/** + * Class: OpenLayers.Layer.OSM.Osmarender + * + * Inherits from: + * - <OpenLayers.Layer.OSM> + */ +OpenLayers.Layer.OSM.Osmarender = OpenLayers.Class(OpenLayers.Layer.OSM, { + /** + * Constructor: OpenLayers.Layer.OSM.Osmarender + * + * Parameters: + * name - {String} + * options - {Object} Hashtable of extra options to tag onto the layer + */ + initialize: function(name, options) { + var url = [ + "http://a.tah.openstreetmap.org/Tiles/tile/${z}/${x}/${y}.png", + "http://b.tah.openstreetmap.org/Tiles/tile/${z}/${x}/${y}.png", + "http://c.tah.openstreetmap.org/Tiles/tile/${z}/${x}/${y}.png" + ]; + options = OpenLayers.Util.extend({ numZoomLevels: 18, buffer: 0 }, options); + var newArguments = [name, url, options]; + OpenLayers.Layer.OSM.prototype.initialize.apply(this, newArguments); + }, + + CLASS_NAME: "OpenLayers.Layer.OSM.Osmarender" +}); + +/** + * Class: OpenLayers.Layer.OSM.CycleMap + * + * Inherits from: + * - <OpenLayers.Layer.OSM> + */ +OpenLayers.Layer.OSM.CycleMap = OpenLayers.Class(OpenLayers.Layer.OSM, { + /** + * Constructor: OpenLayers.Layer.OSM.CycleMap + * + * Parameters: + * name - {String} + * options - {Object} Hashtable of extra options to tag onto the layer + */ + initialize: function(name, options) { + var url = [ + "http://a.tile.opencyclemap.org/cycle/${z}/${x}/${y}.png", + "http://b.tile.opencyclemap.org/cycle/${z}/${x}/${y}.png", + "http://c.tile.opencyclemap.org/cycle/${z}/${x}/${y}.png" + ]; + options = OpenLayers.Util.extend({ + /* Below line added to OSM's file in order to allow minimum zoom level */ + maxResolution: 156543.0339/Math.pow(2, options.zoomOffset || 0), + numZoomLevels: 19, + buffer: 0 + }, options); + var newArguments = [name, url, options]; + OpenLayers.Layer.OSM.prototype.initialize.apply(this, newArguments); + }, + + CLASS_NAME: "OpenLayers.Layer.OSM.CycleMap" +}); diff --git a/web/js/map-streetview.js b/web/js/map-streetview.js new file mode 100644 index 000000000..088e5b6a2 --- /dev/null +++ b/web/js/map-streetview.js @@ -0,0 +1,88 @@ +YAHOO.util.Event.onContentReady('map', function() { + var map = new OpenLayers.Map("map", { + controls: [ + new OpenLayers.Control.ArgParser(), + //new OpenLayers.Control.LayerSwitcher(), + new OpenLayers.Control.Navigation(), + new OpenLayers.Control.PanZoom() + ], + displayProjection: new OpenLayers.Projection("EPSG:4326") + }); + var streetview = new OpenLayers.Layer.StreetView("OS StreetView (1:10000)", { + zoomOffset: 14, + numZoomLevels: 4 + }); + map.addLayer(streetview); + + var centre = new OpenLayers.LonLat( fixmystreet.easting, fixmystreet.northing ); + centre.transform( + new OpenLayers.Projection("EPSG:27700"), + map.getProjectionObject() + ); + map.setCenter(centre, 2); +}); + + +// http://os.openstreetmap.org/openlayers/OS.js (added one line) + +/** + * Namespace: Util.OS + */ +OpenLayers.Util.OS = {}; + +/** + * Constant: MISSING_TILE_URL + * {String} URL of image to display for missing tiles + */ +OpenLayers.Util.OS.MISSING_TILE_URL = "http://openstreetmap.org/openlayers/img/404.png"; + +/** + * Property: originalOnImageLoadError + * {Function} Original onImageLoadError function. + */ +OpenLayers.Util.OS.originalOnImageLoadError = OpenLayers.Util.onImageLoadError; + +/** + * Function: onImageLoadError + */ +OpenLayers.Util.onImageLoadError = function() { + OpenLayers.Util.OS.originalOnImageLoadError; +}; + +/** + * @requires OpenLayers/Layer/XYZ.js + * + * Class: OpenLayers.Layer.StreetView + * + * Inherits from: + * - <OpenLayers.Layer.XYZ> + */ +OpenLayers.Layer.StreetView = OpenLayers.Class(OpenLayers.Layer.XYZ, { + /** + * Constructor: OpenLayers.Layer.StreetView + * + * Parameters: + * name - {String} + * url - {String} + * options - {Object} Hashtable of extra options to tag onto the layer + */ + initialize: function(name, options) { + var url = [ + "http://a.os.openstreetmap.org/sv/${z}/${x}/${y}.png", + "http://b.os.openstreetmap.org/sv/${z}/${x}/${y}.png", + "http://c.os.openstreetmap.org/sv/${z}/${x}/${y}.png" + ]; + options = OpenLayers.Util.extend({ + /* Below line added to OSM's file in order to allow minimum zoom level */ + maxResolution: 156543.0339/Math.pow(2, options.zoomOffset || 0), + numZoomLevels: 18, + transitionEffect: "resize", + sphericalMercator: true, + attribution: "Contains Ordnance Survey data © Crown copyright and database right 2010" + }, options); + var newArguments = [name, url, options]; + OpenLayers.Layer.XYZ.prototype.initialize.apply(this, newArguments); + }, + + CLASS_NAME: "OpenLayers.Layer.StreetView" +}); diff --git a/web/js/map-tilma-ol.js b/web/js/map-tilma-ol.js new file mode 100644 index 000000000..cfd196c1d --- /dev/null +++ b/web/js/map-tilma-ol.js @@ -0,0 +1,42 @@ +YAHOO.util.Event.onContentReady('map', function() { + var map = new OpenLayers.Map("map", { + controls: [ + new OpenLayers.Control.ArgParser(), + new OpenLayers.Control.Navigation(), + new OpenLayers.Control.PanPanel() + ] + }); + var tilma = new OpenLayers.Layer.Tilma("Tilma", { + maxResolution: fixmystreet.maxResolution, + tileSize: new OpenLayers.Size(fixmystreet.tilewidth, fixmystreet.tileheight), + map_type: fixmystreet.tile_type + }); + map.addLayer(tilma); + + var centre = new OpenLayers.LonLat( fixmystreet.easting, fixmystreet.northing ); + map.setCenter(centre); +}); + +OpenLayers.Layer.Tilma = OpenLayers.Class(OpenLayers.Layer.XYZ, { + initialize: function(name, options) { + var url = "http://tilma.mysociety.org/tileserver/${type}/${x},${y}/png"; + options = OpenLayers.Util.extend({ + transitionEffect: "resize", + numZoomLevels: 1, + units: "m", + maxExtent: new OpenLayers.Bounds(0, 0, 700000, 1300000), + }, options); + var newArguments = [name, url, options]; + OpenLayers.Layer.XYZ.prototype.initialize.apply(this, newArguments); + }, + + getURL: function (bounds) { + var res = this.map.getResolution(); + var x = Math.round(bounds.left / (res * this.tileSize.w)); + var y = Math.round(bounds.bottom / (res * this.tileSize.h)); + var path = OpenLayers.String.format(this.url, {'x': x, 'y': y, 'type': this.map_type}); + return path; + }, + + CLASS_NAME: "OpenLayers.Layer.Tilma" +}); |