001 #!/usr/local/bin/perl -w 002 use strict; 003 use Geo::Parse::OSM; 004 use Graph::Directed; 005 use LWP::UserAgent; 006 007 my @bbox = qw( -122.4374 37.74754 008 -122.42096 37.75894 ); 009 my $url = "http://api.openstreetmap.org/" . 010 "api/0.6/map?bbox=" . join ',', @bbox; 011 012 my $mapfile = "map.osm.gz"; 013 014 my( $street_on, $street_cross1, 015 $street_cross2, $side ) = @ARGV; 016 die "usage: $0 street cross1 cross2 side" 017 if !defined $side; 018 019 my $ua = LWP::UserAgent->new(); 020 $ua->default_header("Accept-Encoding", 021 "gzip"); 022 if( ! -f $mapfile or -M $mapfile > 7 ) { 023 my $rsp = $ua->mirror( $url, $mapfile ); 024 $rsp->is_success or die $rsp->message(); 025 } 026 027 my $osm = Geo::Parse::OSM->new( $mapfile ); 028 029 my %on_nodes = (); 030 031 street_nodes( $osm, $street_on, sub { 032 $on_nodes{ $_[0] } = 1; 033 } ); 034 035 my $cross1_node = cross_find( $osm, 036 \%on_nodes, $street_cross1 ); 037 my $cross2_node = cross_find( $osm, 038 \%on_nodes, $street_cross2 ); 039 040 my( $nodes, $flip_order) = 041 find_path_on_way( $osm, $street_on, 042 $cross1_node, $cross2_node ); 043 044 $side = flipside( $side, $flip_order ); 045 046 my $parking = parking($osm, $nodes, $side); 047 048 print "Street Cleaning: ", 049 street_cleaning( $parking ), "\n"; 050 051 ########################################### 052 sub street_nodes { 053 ########################################### 054 my( $osm, $name, $cb ) = @_; 055 056 $osm->seek_to( 0 ); 057 $osm->parse( sub { 058 my($n) = @_; 059 if( exists $n->{tag}->{name} and 060 $n->{tag}->{name} eq $name ) { 061 for my $n ( @{ $n->{chain} } ) { 062 $cb->( $n ) or last; 063 } 064 } 065 }, only => "way"); 066 } 067 068 ########################################### 069 sub cross_find { 070 ########################################### 071 my($osm, $on_nodes, $cross_street) = @_; 072 073 my $found; 074 street_nodes( $osm, $cross_street, sub { 075 my($n) = @_; 076 if( exists $on_nodes->{ $n } ) { 077 $found = $n; 078 return 0; # stop iteration 079 } 080 return 1; # continue iteration 081 }); 082 083 return $found; 084 } 085 086 ########################################### 087 sub find_path_on_way { 088 ########################################### 089 my( $osm, $way_name, @nodes ) = @_; 090 091 my $g = Graph::Directed->new(); 092 093 $osm->seek_to(0); 094 $osm->parse(sub { 095 my($n) = @_; 096 if( exists $n->{tag}->{name} and 097 $n->{tag}->{name} eq $way_name ) { 098 $g->add_path( @{ $n->{chain} } ); 099 } 100 }, only => "way" ); 101 102 my $flip_order = 0; 103 104 my @path = $g->SP_Dijkstra( @nodes ); 105 106 if( !@path ) { 107 @nodes = reverse @nodes; 108 @path = $g->SP_Dijkstra( @nodes ); 109 $flip_order = 1; 110 } 111 112 return( \@path, $flip_order ); 113 } 114 115 ########################################### 116 sub parking { 117 ########################################### 118 my( $osm, $nodes, $side ) = @_; 119 120 my %to_match = map { $_ => 1 } @$nodes; 121 my %results = (); 122 123 $osm->seek_to( 0 ); 124 $osm->parse( sub { 125 my($w) = @_; 126 127 my @matches = 128 grep { exists $to_match{$_} } 129 @{ $w->{chain} }; 130 131 return if @matches < 2; 132 133 for my $tag ( keys %{ $w->{tag} } ) { 134 if( $tag =~ 135 /parking:condition:$side:.*/ ) { 136 $results{$tag} = $w->{tag}->{$tag}; 137 } 138 } 139 }, only => "way"); 140 141 return \%results; 142 } 143 144 ########################################### 145 sub street_cleaning { 146 ########################################### 147 my( $parking ) = @_; 148 149 for my $key ( keys %$parking ) { 150 if( $key =~ /(.*)\:reason/ ) { 151 if( $parking->{ $key } eq 152 "street_cleaning" ) { 153 return $parking->{ $1 . 154 ":time_interval" }; 155 } 156 } 157 } 158 159 return undef; 160 } 161 162 ########################################### 163 sub flipside { 164 ########################################### 165 my($side, $flip_order) = @_; 166 167 if( $flip_order ) { 168 if( $side eq "left" ) { 169 $side = "right"; 170 } else { 171 $side = "left"; 172 } 173 } 174 175 return $side; 176 }