aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Somerville <matthew@mysociety.org>2011-07-12 19:09:45 +0100
committerMatthew Somerville <matthew@mysociety.org>2011-07-12 19:09:45 +0100
commitd2d54ea0d9844833ab8544c3df34f9043b21a6a7 (patch)
treeda892b606e08b798d0023683f18db4ca043ac779
parent42a92773a123d2b0fa1eaed93201fa45a8b7e436 (diff)
Factor out find_closest from send-reports, initial OSM.pm from osm_road_info branch, needs altering before it will work.
-rwxr-xr-xbin/send-reports33
-rw-r--r--perllib/FixMyStreet/Cobrand/Default.pm38
-rw-r--r--perllib/FixMyStreet/Cobrand/FiksGataMi.pm5
-rw-r--r--perllib/FixMyStreet/Geocode/OSM.pm143
4 files changed, 190 insertions, 29 deletions
diff --git a/bin/send-reports b/bin/send-reports
index b55447e8a..1af3ba1ea 100755
--- a/bin/send-reports
+++ b/bin/send-reports
@@ -88,7 +88,10 @@ while (my $row = $unsent->next) {
= "Easting: $h{easting}\n\n" #
. "Northing: $h{northing}\n\n";
- $h{closest_address} = find_closest($row, $h{latitude}, $h{longitude});
+ }
+
+ if ( $row->used_map ) {
+ $h{closest_address} = $cobrand->find_closest( $h{latitude}, $h{longitude} );
}
my (@to, @recips, $template, $areas_info);
@@ -422,34 +425,6 @@ sub post_london_report {
# Nearest things
-sub find_closest {
- my ($row, $latitude, $longitude) = @_;
- my $str = '';
-
- return '' unless $row->used_map;
-
- # Get nearest road-type thing from Bing
- my $url = "http://dev.virtualearth.net/REST/v1/Locations/$latitude,$longitude?c=en-GB&key=" . mySociety::Config::get('BING_MAPS_API_KEY');
- my $j = LWP::Simple::get($url);
- if ($j) {
- $j = JSON->new->utf8->allow_nonref->decode($j);
- if ($j->{resourceSets}[0]{resources}[0]{name}) {
- $str .= "Nearest road to the pin placed on the map (automatically generated by Bing Maps): $j->{resourceSets}[0]{resources}[0]{name}\n\n";
- }
- }
-
- # Get nearest postcode from Matthew's random gazetteer (put in MaPit? Or elsewhere?)
- $url = "http://gazetteer.dracos.vm.bytemark.co.uk/point/$latitude,$longitude.json";
- $j = LWP::Simple::get($url);
- if ($j) {
- $j = JSON->new->utf8->allow_nonref->decode($j);
- if ($j->{postcode}) {
- $str .= "Nearest postcode to the pin placed on the map (automatically generated): $j->{postcode}[0] ($j->{postcode}[1]m away)\n\n";
- }
- }
- return $str;
-}
-
sub london_lookup {
my $org = shift;
my $str = "Unknown ($org)";
diff --git a/perllib/FixMyStreet/Cobrand/Default.pm b/perllib/FixMyStreet/Cobrand/Default.pm
index 62c73761b..2ac1a81b8 100644
--- a/perllib/FixMyStreet/Cobrand/Default.pm
+++ b/perllib/FixMyStreet/Cobrand/Default.pm
@@ -537,6 +537,44 @@ string LOCATION passes the cobrands checks.
sub geocoded_string_check { return 1; }
+=head2 find_closest
+
+Used by send-reports to attach nearest things to the bottom of the report
+
+=cut
+
+sub find_closest {
+ my ( $self, $latitude, $longitude ) = @_;
+ my $str = '';
+
+ # Get nearest road-type thing from Bing
+ my $key = mySociety::Config::get('BING_MAPS_API_KEY', '');
+ if ($key) {
+ my $url = "http://dev.virtualearth.net/REST/v1/Locations/$latitude,$longitude?c=en-GB&key=$key";
+ my $j = LWP::Simple::get($url);
+ if ($j) {
+ $j = JSON->new->utf8->allow_nonref->decode($j);
+ if ($j->{resourceSets}[0]{resources}[0]{name}) {
+ $str .= sprintf(_("Nearest road to the pin placed on the map (automatically generated by Bing Maps): %s"),
+ $j->{resourceSets}[0]{resources}[0]{name}) . "\n\n";
+ }
+ }
+ }
+
+ # Get nearest postcode from Matthew's random gazetteer (put in MaPit? Or elsewhere?)
+ my $url = "http://gazetteer.dracos.vm.bytemark.co.uk/point/$latitude,$longitude.json";
+ my $j = LWP::Simple::get($url);
+ if ($j) {
+ $j = JSON->new->utf8->allow_nonref->decode($j);
+ if ($j->{postcode}) {
+ $str .= sprintf(_("Nearest postcode to the pin placed on the map (automatically generated): %s (%sm away)"),
+ $j->{postcode}[0], $j->{postcode}[1]) . "\n\n";
+ }
+ }
+
+ return $str;
+}
+
=head2 council_check
Paramters are COUNCILS, QUERY, CONTEXT. Return a boolean indicating whether
diff --git a/perllib/FixMyStreet/Cobrand/FiksGataMi.pm b/perllib/FixMyStreet/Cobrand/FiksGataMi.pm
index a606dc3b9..3ba449a33 100644
--- a/perllib/FixMyStreet/Cobrand/FiksGataMi.pm
+++ b/perllib/FixMyStreet/Cobrand/FiksGataMi.pm
@@ -87,6 +87,11 @@ sub geocoded_string_check {
return 0;
}
+sub find_closest {
+ my ( $self, $latitude, $longitude ) = @_;
+ return FixMyStreet::Geocode::OSM::closest_road_text( $self, $latitude, $longitude );
+}
+
sub remove_redundant_councils {
my $self = shift;
my $all_councils = shift;
diff --git a/perllib/FixMyStreet/Geocode/OSM.pm b/perllib/FixMyStreet/Geocode/OSM.pm
new file mode 100644
index 000000000..fad5baf45
--- /dev/null
+++ b/perllib/FixMyStreet/Geocode/OSM.pm
@@ -0,0 +1,143 @@
+#!/usr/bin/perl
+#
+# FixMyStreet:Geocode::OSM
+# OpenStreetmap forward and reverse geocoding for FixMyStreet.
+#
+# Copyright (c) 2011 Petter Reinholdtsen. Some rights reserved.
+# Email: pere@hungry.com
+
+package FixMyStreet::Geocode::OSM;
+
+use warnings;
+use strict;
+
+use Memcached;
+use mySociety::Config;
+use LWP::Simple;
+use XML::Simple;
+
+my $osmapibase = "http://www.openstreetmap.org/api/";
+my $nominatimbase = "http://nominatim.openstreetmap.org/";
+
+
+sub lookup_location {
+ my ($latitude, $longitude, $zoom) = @_;
+ my $url =
+ "${nominatimbase}reverse?format=xml&zoom=$zoom&lat=$latitude&lon=$longitude";
+ my $key = "OSM:lookup_location:$url";
+ my $result = Memcached::get($key);
+ unless ($result) {
+ my $j = LWP::Simple::get($url);
+ if ($j) {
+ Memcached::set($key, $j, 3600);
+ my $ref = XMLin($j);
+ return $ref;
+ } else {
+ print STDERR "No reply from $url\n";
+ }
+ return undef;
+ }
+ return XMLin($result);
+}
+
+sub _osmxml_to_hash {
+ my ($xml, $type) = @_;
+ my $ref = XMLin($xml);
+ my %tags;
+ if ('ARRAY' eq ref $ref->{$type}->{tag}) {
+ map { $tags{$_->{'k'}} = $_->{'v'} } @{$ref->{$type}->{tag}};
+ return \%tags;
+ } else {
+ return undef;
+ }
+}
+
+sub get_object_tags {
+ my ($type, $id) = @_;
+ my $url = "${osmapibase}0.6/$type/$id";
+ my $key = "OSM:get_object_tags:$url";
+ my $result = Memcached::get($key);
+ unless ($result) {
+ my $j = LWP::Simple::get($url);
+ if ($j) {
+ Memcached::set($key, $j, 3600);
+ return _osmxml_to_hash($j, $type);
+ } else {
+ print STDERR "No reply from $url\n";
+ }
+ return undef;
+ }
+ return _osmxml_to_hash($result, $type);
+}
+
+sub guess_road_operator {
+ my $inforef = shift;
+ my $highway = $inforef->{highway} || "unknown";
+ my $refs = $inforef->{ref} || "unknown";
+
+ my $operator;
+ if ( mySociety::Config::get('COUNTRY') eq 'NO' ) {
+ if ($highway eq "trunk"
+ || $highway eq "primary"
+ ) {
+ $operator = "Statens vegvesen";
+ }
+ unless (defined $operator) {
+ for my $ref (split(/;/, $refs)) {
+ if ($ref =~ m/E ?\d+/
+ || $ref =~ m/Fv\d+/i
+ ) {
+ $operator = "Statens vegvesen";
+ }
+ }
+ }
+ }
+ return $operator;
+}
+
+# A better alternative might be
+# http://www.geonames.org/maps/osm-reverse-geocoder.html#findNearbyStreetsOSM
+sub get_nearest_road_tags {
+ my ($latitude, $longitude) = @_;
+ my $inforef = lookup_location($latitude, $longitude, 16);
+ if (exists $inforef->{result}->{osm_type}
+ && 'way' eq $inforef->{result}->{osm_type}) {
+ my $osmtags = get_object_tags('way',
+ $inforef->{result}->{osm_id});
+ if (mySociety::Config::get('OSM_GUESS_OPERATOR')
+ && !exists $osmtags->{operator}) {
+ my $guess = guess_road_operator($osmtags);
+ $osmtags->{operatorguess} = $guess if $guess;
+ }
+ return $osmtags;
+ }
+ return undef;
+}
+
+sub closest_road_text {
+ my ($latitude, $longitude) = @_;
+ my $str = '';
+ my $osmtags = get_nearest_road_tags($latitude, $longitude);
+ if ($osmtags) {
+ my ($name, $ref) = ('','');
+ $name = $osmtags->{name} if exists $osmtags->{name};
+ $ref = " ($osmtags->{ref})" if exists $osmtags->{ref};
+ if ($name || $ref) {
+ $str .= _('The following information about the nearest road might be inaccurate or irrelevant, if the problem is close to several roads or close to a road without a name registered in OpenStreetmap.') . "\n\n";
+ $str .= sprintf(_("Nearest named road to the pin placed on the map (automatically generated using OpenStreetmap): %s%s"),
+ $name, $ref) . "\n\n";
+
+ if (my $operator = $osmtags->{operator}) {
+ $str .= sprintf(_("Road operator for this named road (from OpenStreetmap): %s"),
+ $operator) . "\n\n";
+ } elsif ($operator = $osmtags->{operatorguess}) {
+ $str .= sprintf(_("Road operator for this named road (derived from road reference number and type): %s"),
+ $operator) . "\n\n";
+ }
+ }
+ }
+ return $str;
+}
+
+1;
+