1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
|
# FixMyStreet::Geocode::Bing
# Geocoding with Bing for FixMyStreet.
#
# Copyright (c) 2011 UK Citizens Online Democracy. All rights reserved.
# Email: matthew@mysociety.org; WWW: http://www.mysociety.org/
package FixMyStreet::Geocode::Bing;
use strict;
use mySociety::Locale;
# string STRING CONTEXT
# Looks up on Bing Maps API, and caches, a user-inputted location.
# Returns array of (LAT, LON, ERROR), where ERROR is either undef, a string, or
# an array of matches if there are more than one. The information in the query
# may be used to disambiguate the location in cobranded versions of the site.
sub string {
my ( $s, $c ) = @_;
my $params = $c->cobrand->disambiguate_location($s);
$s = FixMyStreet::Geocode::escape($s);
$s .= '+' . $params->{town} if $params->{town} and $s !~ /$params->{town}/i;
my $url = "http://dev.virtualearth.net/REST/v1/Locations?q=$s";
$url .= '&userMapView=' . join(',', @{$params->{bounds}})
if $params->{bounds};
$url .= '&userLocation=' . $params->{centre} if $params->{centre};
$url .= '&c=' . $params->{bing_culture} if $params->{bing_culture};
my $js = FixMyStreet::Geocode::cache('bing', $url, 'key=' . FixMyStreet->config('BING_MAPS_API_KEY'));
if (!$js) {
return { error => _('Sorry, we could not parse that location. Please try again.') };
}
if ($js->{statusCode} ne '200') {
return { error => _('Sorry, we could not find that location.') };
}
my $results = $js->{resourceSets}->[0]->{resources};
my ( $error, @valid_locations, $latitude, $longitude );
foreach (@$results) {
my $address = $_->{name};
next if $params->{bing_country} && $_->{address}->{countryRegion} ne $params->{bing_country};
# Getting duplicate, yet different, results from Bing sometimes
next if @valid_locations
&& $_->{address}{postalCode} && $valid_locations[-1]{address}{postalCode} eq $_->{address}{postalCode}
&& ( $valid_locations[-1]{address}{locality} eq $_->{address}{adminDistrict2}
|| $valid_locations[-1]{address}{adminDistrict2} eq $_->{address}{locality}
|| $valid_locations[-1]{address}{locality} eq $_->{address}{locality}
);
( $latitude, $longitude ) = @{ $_->{point}->{coordinates} };
# These co-ordinates are output as query parameters in a URL, make sure they have a "."
mySociety::Locale::in_gb_locale {
push (@$error, {
address => $address,
latitude => sprintf('%0.6f', $latitude),
longitude => sprintf('%0.6f', $longitude)
});
};
push (@valid_locations, $_);
}
return { latitude => $latitude, longitude => $longitude } if scalar @valid_locations == 1;
return { error => $error };
}
sub reverse {
my ( $latitude, $longitude, $bing_culture ) = @_;
# 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?key=$key";
$url .= '&c=' . $bing_culture if $bing_culture;
my $j = FixMyStreet::Geocode::cache('bing', $url);
return $j if $j;
}
return undef;
}
1;
|