diff options
author | Dave Arter <davea@mysociety.org> | 2018-06-14 16:55:07 +0100 |
---|---|---|
committer | Dave Arter <davea@mysociety.org> | 2018-08-17 09:43:09 +0100 |
commit | d0dd45e0280e33ffe018e579ab3d3605302a2a76 (patch) | |
tree | 32c118aa3d70675ba7294dee43424ca04d701818 /perllib | |
parent | 95b854b4ea5c42b9f527b2f161d25175347ea3c9 (diff) |
[Buckinghamshire] Factor lookup_site_code up into UKCouncils cobrand
Diffstat (limited to 'perllib')
-rw-r--r-- | perllib/FixMyStreet/Cobrand/Buckinghamshire.pm | 95 | ||||
-rw-r--r-- | perllib/FixMyStreet/Cobrand/UKCouncils.pm | 98 |
2 files changed, 112 insertions, 81 deletions
diff --git a/perllib/FixMyStreet/Cobrand/Buckinghamshire.pm b/perllib/FixMyStreet/Cobrand/Buckinghamshire.pm index f02ee9e51..783a565f1 100644 --- a/perllib/FixMyStreet/Cobrand/Buckinghamshire.pm +++ b/perllib/FixMyStreet/Cobrand/Buckinghamshire.pm @@ -4,11 +4,6 @@ use parent 'FixMyStreet::Cobrand::UKCouncils'; use strict; use warnings; -use LWP::Simple; -use URI; -use Try::Tiny; -use JSON::MaybeXS; - sub council_area_id { return 2217; } sub council_area { return 'Buckinghamshire'; } sub council_name { return 'Buckinghamshire County Council'; } @@ -336,85 +331,23 @@ sub categories_restriction { return $rs->search( [ { 'body_areas.area_id' => 2217 }, { category => 'Flytipping' } ], { join => { body => 'body_areas' } }); } -sub lookup_site_code { - my $self = shift; - my $row = shift; - my $buffer = shift || 200; # metres - - my ($x, $y) = $row->local_coords; - my ($w, $s, $e, $n) = ($x-$buffer, $y-$buffer, $x+$buffer, $y+$buffer); - - my $uri = URI->new("https://tilma.mysociety.org/mapserver/bucks"); - $uri->query_form( - REQUEST => "GetFeature", - SERVICE => "WFS", - SRSNAME => "urn:ogc:def:crs:EPSG::27700", - TYPENAME => "Whole_Street", - VERSION => "1.1.0", - outputformat => "geojson", - BBOX => "$w,$s,$e,$n" - ); - - my $response = get($uri); - - my $j = JSON->new->utf8->allow_nonref; - try { - $j = $j->decode($response); - } catch { - # There was either no asset found, or an error with the WFS - # call - in either case let's just proceed without the USRN. - return ''; - }; - - # We have a list of features, and we want to find the one closest to the - # report location. - my $site_code = ''; - my $nearest; - - # There are only certain features we care about, the rest can be ignored. - my @valid_types = ( "2", "3A", "3B", "4A", "4B", "HE", "HWOA", "HWSA", "P" ); - my %valid_types = map { $_ => 1 } @valid_types; - - for my $feature ( @{ $j->{features} } ) { +sub lookup_site_code_config { { + buffer => 200, # metres + url => "https://tilma.mysociety.org/mapserver/bucks", + srsname => "urn:ogc:def:crs:EPSG::27700", + typename => "Whole_Street", + property => "site_code", + accept_feature => sub { + my $feature = shift; + + # There are only certain features we care about, the rest can be ignored. + my @valid_types = ( "2", "3A", "3B", "4A", "4B", "HE", "HWOA", "HWSA", "P" ); + my %valid_types = map { $_ => 1 } @valid_types; my $type = $feature->{properties}->{feature_ty}; - next unless $valid_types{$type}; - - # We shouldn't receive anything aside from these two geometry types, but belt and braces. - next unless $feature->{geometry}->{type} eq 'MultiLineString' || $feature->{geometry}->{type} eq 'LineString'; - my @coordinates = @{ $feature->{geometry}->{coordinates} }; - if ( $feature->{geometry}->{type} eq 'MultiLineString') { - # The coordinates are stored as a list of lists, so flatten 'em out - @coordinates = map { @{ $_ } } @coordinates; - } - - # If any of this feature's points are closer than those we've seen so - # far then use the site_code from this feature. - for my $coords ( @coordinates ) { - my ($fx, $fy) = @$coords; - my $distance = $self->_distance($x, $y, $fx, $fy); - if ( !defined $nearest || $distance < $nearest ) { - $site_code = $feature->{properties}->{site_code}; - $nearest = $distance; - } - } + return $valid_types{$type}; } +} } - return $site_code; -} - - -=head2 _distance - -Returns the cartesian distance between two coordinates. -This is not a general-purpose distance function, it's intended for use with -fairly nearby coordinates in EPSG:27700 where a spheroid doesn't need to be -taken into account. - -=cut -sub _distance { - my ($self, $ax, $ay, $bx, $by) = @_; - return sqrt( (($ax - $bx) ** 2) + (($ay - $by) ** 2) ); -} 1; diff --git a/perllib/FixMyStreet/Cobrand/UKCouncils.pm b/perllib/FixMyStreet/Cobrand/UKCouncils.pm index 25f809d8c..72f6ff89e 100644 --- a/perllib/FixMyStreet/Cobrand/UKCouncils.pm +++ b/perllib/FixMyStreet/Cobrand/UKCouncils.pm @@ -6,6 +6,10 @@ use warnings; use Carp; use URI::Escape; +use LWP::Simple; +use URI; +use Try::Tiny; +use JSON::MaybeXS; sub is_council { 1; @@ -222,4 +226,98 @@ sub prefill_report_fields_for_inspector { 1 } sub social_auth_disabled { 1 } +=head2 lookup_site_code + +Reports made via FMS.com or the app probably won't have a site code +value (required for Confirm integrations) because we don't display +the adopted highways layer on those frontends. +Instead we'll look up the closest asset from the WFS +service at the point we're sending the report over Open311. + +NB this requires the cobrand to implement `lookup_site_code_config` - +see Buckinghamshire or Lincolnshire for an example. + + +=cut + +sub lookup_site_code { + my $self = shift; + my $row = shift; + my $buffer = shift; + + my $cfg = $self->lookup_site_code_config; + + $buffer ||= $cfg->{buffer}; # metres + my ($x, $y) = $row->local_coords; + my ($w, $s, $e, $n) = ($x-$buffer, $y-$buffer, $x+$buffer, $y+$buffer); + + my $uri = URI->new($cfg->{url}); + $uri->query_form( + REQUEST => "GetFeature", + SERVICE => "WFS", + SRSNAME => $cfg->{srsname}, + TYPENAME => $cfg->{typename}, + VERSION => "1.1.0", + outputformat => "geojson", + BBOX => "$w,$s,$e,$n" + ); + + my $response = get($uri); + + my $j = JSON->new->utf8->allow_nonref; + try { + $j = $j->decode($response); + } catch { + # There was either no asset found, or an error with the WFS + # call - in either case let's just proceed without the USRN. + return ''; + }; + + # We have a list of features, and we want to find the one closest to the + # report location. + my $site_code = ''; + my $nearest; + + for my $feature ( @{ $j->{features} } ) { + next unless $cfg->{accept_feature}($feature); + + # We shouldn't receive anything aside from these two geometry types, but belt and braces. + next unless $feature->{geometry}->{type} eq 'MultiLineString' || $feature->{geometry}->{type} eq 'LineString'; + + my @coordinates = @{ $feature->{geometry}->{coordinates} }; + if ( $feature->{geometry}->{type} eq 'MultiLineString') { + # The coordinates are stored as a list of lists, so flatten 'em out + @coordinates = map { @{ $_ } } @coordinates; + } + + # If any of this feature's points are closer than those we've seen so + # far then use the site_code from this feature. + for my $coords ( @coordinates ) { + my ($fx, $fy) = @$coords; + my $distance = $self->_distance($x, $y, $fx, $fy); + if ( !defined $nearest || $distance < $nearest ) { + $site_code = $feature->{properties}->{$cfg->{property}}; + $nearest = $distance; + } + } + } + + return $site_code; +} + + +=head2 _distance + +Returns the cartesian distance between two coordinates. +This is not a general-purpose distance function, it's intended for use with +fairly nearby coordinates in EPSG:27700 where a spheroid doesn't need to be +taken into account. + +=cut +sub _distance { + my ($self, $ax, $ay, $bx, $by) = @_; + return sqrt( (($ax - $bx) ** 2) + (($ay - $by) ** 2) ); +} + + 1; |