aboutsummaryrefslogtreecommitdiffstats
path: root/perllib/Geo/Coordinates/CH1903Plus.pm
diff options
context:
space:
mode:
Diffstat (limited to 'perllib/Geo/Coordinates/CH1903Plus.pm')
-rw-r--r--perllib/Geo/Coordinates/CH1903Plus.pm108
1 files changed, 108 insertions, 0 deletions
diff --git a/perllib/Geo/Coordinates/CH1903Plus.pm b/perllib/Geo/Coordinates/CH1903Plus.pm
new file mode 100644
index 000000000..8487dacbe
--- /dev/null
+++ b/perllib/Geo/Coordinates/CH1903Plus.pm
@@ -0,0 +1,108 @@
+# 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
+# Perl itself.
+#
+# WWW: http://www.mysociety.org/
+
+package Geo::Coordinates::CH1903Plus;
+
+$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::CH1903Plus
+
+=head1 VERSION
+
+1.00
+
+=head1 SYNOPSIS
+
+ use Geo::Coordinates::CH1903Plus;
+
+ my ($lat, $lon) = ...;
+ my ($e, $n) = Geo::Coordinates::CH1903Plus::from_latlon($lat, $lon);
+ my ($lat, $lon) = Geo::Coordinates::CH1903Plus::to_latlon($e, $n);
+
+=head1 FUNCTIONS
+
+=over 4
+
+=cut
+
+sub from_latlon($$) {
+ my ($lat, $lon) = @_;
+
+ $lat *= 3600;
+ $lon *= 3600;
+
+ my $lat_aux = ($lat - 169028.66) / 10000;
+ my $lon_aux = ($lon - 26782.5) / 10000;
+
+ 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 + LV95_Y_OFFSET
+ + (308807.95 * $lat_aux)
+ + (3745.25 * $lon_aux**2)
+ + (76.63 * $lat_aux**2)
+ - (194.56 * $lon_aux**2 * $lat_aux)
+ + (119.79 * $lat_aux**3);
+
+ return ($x, $y);
+}
+
+sub to_latlon($$) {
+ my ($x, $y) = @_;
+
+ 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)
+ - (0.270978 * $x_aux**2)
+ - (0.002528 * $y_aux**2)
+ - (0.0447 * $x_aux**2 * $y_aux)
+ - (0.0140 * $y_aux**3);
+
+ my $lon = 2.6779094
+ + (4.728982 * $x_aux)
+ + (0.791484 * $x_aux * $y_aux)
+ + (0.1306 * $x_aux * $y_aux**2)
+ - (0.0436 * $x_aux**3);
+
+ $lat = $lat * 100 / 36;
+ $lon = $lon * 100 / 36;
+
+ return ($lat, $lon);
+}
+
+=head1 AUTHOR AND COPYRIGHT
+
+Maths courtesy of the Swiss Federal Office of Topography:
+http://www.swisstopo.admin.ch/internet/swisstopo/en/home/products/software/products/skripts.html
+
+Written by Matthew Somerville
+
+Copyright (c) UK Citizens Online Democracy.
+
+This module is free software; you can redistribute it and/or modify it
+under the same terms as Perl itself.
+
+=cut
+
+1;
+