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 }