source: subversion/applications/utils/osm-extract/osm-subset.pl @ 6294

Last change on this file since 6294 was 5531, checked in by joerg, 12 years ago

.../*.pl: remove @INC lines to reduce modules taken from svn instead of installed system

  • Property svn:executable set to *
File size: 10.2 KB
Line 
1#!/usr/bin/perl
2# Licence GPL
3
4BEGIN {
5    my $dir = $0;
6    $dir =~s,[^/]+/[^/]+$,,;
7    unshift(@INC,"$dir/perl_lib");
8    unshift(@INC,"../perl_lib");
9}
10
11
12use strict;
13use warnings;
14
15use XML::Parser;
16use Getopt::Long;
17use IO::File;
18use Pod::Usage;
19use Data::Dumper;
20use Carp;
21
22use Geo::Filter::Area;
23use Geo::OSM::Planet;
24use Utils::Debug;
25use Utils::File;
26use Utils::Math;
27
28sub parse_planet($$$); # {}
29
30our $man=0;
31our $help=0;
32my $areas_todo;
33my $do_list_areas=0;
34my $do_update_only=0;
35
36my $use_max_mem=0;
37
38Getopt::Long::Configure('no_ignore_case');
39GetOptions ( 
40             'debug+'              => \$DEBUG,     
41             'd+'                  => \$DEBUG,     
42             'verbose+'            => \$VERBOSE,
43             'MAN'                 => \$man, 
44             'man'                 => \$man, 
45             'h|help|x'            => \$help, 
46
47             'no-mirror'           => \$Utils::LWP::Utils::NO_MIRROR,
48             'proxy=s'             => \$Utils::LWP::Utils::PROXY,
49
50             'area=s'              => \$areas_todo,
51             'list-areas'          => \$do_list_areas,
52             )
53    or pod2usage(1);
54
55pod2usage(1) if $help;
56pod2usage(-verbose=>2) if $man;
57
58
59# TODO:
60# if the input filename is not planet*osm* we have to change the output filename too.
61my $Filename = shift();
62unless ( $Filename && -s $Filename ) {
63    $Filename = mirror_planet();
64};
65if ( ! -s $Filename ) {
66    die "Cannot read $Filename\n";
67}
68
69pod2usage(1) unless $Filename;
70
71our $READ_FH=undef;
72our $WRITE_FH=undef;
73
74$areas_todo ||= 'europe';
75$areas_todo=lc($areas_todo);
76if ( $do_list_areas ) {
77    print Geo::Filter::Area->list_areas()."\n";
78    exit;
79}
80
81print STDERR "Using OSM-subset: $Filename\n" if $VERBOSE || $DEBUG;
82
83
84our (%MainAttr,$Type,%Tags, @WaySegments);
85# Stats
86# Stored data
87our @NODES;
88our @SEGMENTS;
89
90our %Stats;
91our $AREA_FILTER;
92our $PARSING_START_TIME=0;
93our $PARSING_DISPLAY_TIME=0;
94
95our $vsz0 = mem_usage('vsz');
96
97for my $area_name ( split(",",$areas_todo) ) {
98    # -----------------------------------------------------------------------------
99    # Temporary data
100
101    (%MainAttr,%Tags)=((),());
102    $Type='';
103    @WaySegments = ();
104    (%Stats)=('elem'=>0,'node'=>0,'segment'=>0,'way'=>0);
105    # Currently active Area Filter
106    $PARSING_START_TIME=0;
107
108    #----------------------------------------------
109    # Processing stage
110    #----------------------------------------------
111
112    my $file_out = $Filename;
113    $file_out =~ s/\.osm(\.gz|\.bz2)?$/-$area_name.osm/;
114    parse_planet($Filename,$file_out,$area_name);
115
116    printf STDERR "$area_name Done\n";
117}
118exit;
119
120#----------------------------------------------
121# Parsing planet.osm File
122#----------------------------------------------
123sub parse_planet($$$){
124    my $Filename_in = shift;
125    my $Filename_out = shift;
126    my $area_name = shift;
127
128    print STDERR "Reading and Parsing XML from $Filename for $area_name\n" if $DEBUG;
129
130    $AREA_FILTER = Geo::Filter::Area->new( area => $area_name );
131
132    $PARSING_START_TIME=time();
133    $READ_FH = data_open($Filename_in);
134    $WRITE_FH = IO::File->new(">$Filename_out");
135    $WRITE_FH->binmode(':utf8');
136    print $WRITE_FH '<?xml version="1.0" encoding="UTF-8"?>'."\n";
137    print $WRITE_FH '<osm version="0.3" generator="OpenStreetMap planet.rb">'."\n";
138
139    if ( $VERBOSE || $DEBUG )  {
140        print STDERR "\n";
141        print STDERR "osm-subset.pl: Parsing $Filename_in for area ".$AREA_FILTER->name()."\n";
142    }
143    my $P = new XML::Parser( Handlers => {
144        Start => \&DoStart, 
145        End => \&DoEnd, 
146        Char => \&DoChar});
147    eval {
148        $P->parse($READ_FH);
149        $READ_FH->close();
150        print $WRITE_FH '</osm>'."\n";
151        $WRITE_FH->close();
152    };
153    if ( $VERBOSE || $DEBUG )  {
154        print STDERR "\n";
155    }
156
157    if ($@) {
158        print STDERR "WARNING: Could not parse osm data $Filename_in\n";
159        print STDERR "ERROR: $@\n";
160        return;
161    }
162    if (not $P) {
163        print STDERR "WARNING: Could not parse osm data $Filename_in\n";
164        return;
165    }
166    $Stats{"time parsing"} = time()-$PARSING_START_TIME;
167    printf("osm-subset.pl: Parsing Osm-Data in %.0f sec\n",time()-$PARSING_START_TIME )
168        if $DEBUG || $VERBOSE;
169
170}
171
172sub display_status($){
173    my $mode = shift;
174    return unless $VERBOSE || $DEBUG ;
175    return unless time()-$PARSING_DISPLAY_TIME >2;
176
177    $PARSING_DISPLAY_TIME= time();
178    print STDERR "\r";
179    #print STDERR "$mode(".$AREA_FILTER->name()."): ";
180
181    print STDERR time_estimate($PARSING_START_TIME,
182                               $Stats{"elem read"},estimated_max_count("elem"));
183
184    my $pos = $READ_FH->tell();
185    printf STDERR " pos:%.2fGB ",$pos/1024/1024/1024;
186    for my $k ( sort keys %Stats ) {
187        next if $k =~ m/( read)$/;
188        next if $k =~ m/(tag|mem)$/;
189        next if $k =~ m/named/ && $VERBOSE <=1;
190        next if $k !~ m/elem/ && $VERBOSE <=2;
191        print STDERR "$k:".$Stats{$k};
192        my $estim=estimated_max_count($k);
193        if ( defined($Stats{"$k read"}) ) {
194            printf STDERR "=%.0f%%",(100*$Stats{"$k read"}/$estim) 
195                if $estim;
196        }
197        print STDERR "($estim) ";
198    }
199
200    my $vsz = mem_usage('vsz');
201
202    if ( ! $use_max_mem and (mem_info("MemFree")<10) ){
203        die "\nToo much memory ($vsz MB) used; MemFree: ".mem_info("MemFree")."MB\n";
204    }
205    if ( $use_max_mem >0 and ( $vsz > $use_max_mem ) ) {
206        die "\nToo much memory($vsz MB) used; max allowed: $use_max_mem MB ".mem_info()."\n";
207    }
208   
209    print STDERR mem_usage();
210    print STDERR "\r";
211   
212    #print STDERR "\n";
213    #store_mem_arrays();
214
215}
216
217
218# Function is called whenever an XML tag is started
219#----------------------------------------------
220sub DoStart()
221{
222    my ($Expat, $Name, %Attr) = @_;
223   
224    if($Name eq "node"){
225        undef %Tags;
226        %MainAttr = %Attr;
227        $Type = "n";
228    }
229    if($Name eq "segment"){
230        undef %Tags;
231        %MainAttr = %Attr;
232        $Type = "s";
233    }
234    if($Name eq "way"){
235        undef %Tags;
236        undef @WaySegments;
237        %MainAttr = %Attr;
238        $Type = "w";
239    }
240    if($Name eq "tag"){
241        # TODO: protect against id,from,to,lat,long,etc. being used as tags
242        $Tags{$Attr{"k"}} = $Attr{"v"};
243        $Stats{"tag"}++;
244    }
245    if($Name eq "seg"){
246        my $id = $Attr{"id"};
247        if ( $SEGMENTS[$id] ) {
248            push(@WaySegments, $id);
249        }
250    }
251    $Stats{"elem"}++;
252}
253
254# ------------------------------------------------------------------
255sub tags2osm($){
256    my $tags = shift;
257   
258    my $erg = "";
259    for my $k ( keys %{$tags} ) {
260        my $v = $tags->{$k};
261        if ( ! defined $v ) {
262            warn "incomplete Object: ".Dumper(\$tags);
263        }
264        #next unless defined $v;
265
266        # character escaping as per http://www.w3.org/TR/REC-xml/
267        $v =~ s/&/&amp;/g;
268        $v =~ s/\'/&apos;/g;
269        $v =~ s/</&lt;/g;
270        $v =~ s/>/&gt;/g;
271        $v =~ s/\"/&quot;/g;
272
273        $erg .= "    <tag k=\"$k\" v=\"$v\" />\n";
274    }
275    return $erg;
276}
277
278# Function is called whenever an XML tag is ended
279#----------------------------------------------
280sub DoEnd(){
281    my ($Expat, $Element) = @_;
282    my $id = $MainAttr{"id"};
283    $Stats{"elem read"}++;
284    display_status("Read: ");
285
286    if($Element eq "node"){
287        $Stats{"node read"}++;
288        if ( $AREA_FILTER->inside(\%MainAttr) ) {
289            $NODES[$id]=1;
290
291            print $WRITE_FH "  <node id=\"$id\"";
292            print $WRITE_FH " lat=\"$MainAttr{lat}\"";
293            print $WRITE_FH " lon=\"$MainAttr{lon}\"";
294            print $WRITE_FH " timestamp=\"".$MainAttr{timestamp}."\"" 
295                if defined $MainAttr{timestamp};
296            if ( keys %Tags ){
297                print $WRITE_FH ">\n";
298                print $WRITE_FH tags2osm(\%Tags);
299                print $WRITE_FH "  </node>\n";
300            } else {
301                print $WRITE_FH "/>\n";
302            }
303            $Stats{"node"}++;
304        }
305    }
306
307    if($Element eq "segment"){
308        print STDERR "\n" unless $Stats{"segment read"}++ && $VERBOSE;
309        my $from = $MainAttr{"from"};
310        my $to   = $MainAttr{"to"};
311        if ( $NODES[$from] and $NODES[$to] ) {
312            print $WRITE_FH "  <segment id=\"$id\"";
313            print $WRITE_FH " from=\"$MainAttr{from}\"";
314            print $WRITE_FH " to=\"$MainAttr{to}\" ";
315            print $WRITE_FH " timestamp=\"".$MainAttr{timestamp}."\"" 
316                if defined $MainAttr{timestamp};
317            if ( keys %Tags ){
318                print $WRITE_FH ">\n";
319                print $WRITE_FH tags2osm(\%Tags);
320                print $WRITE_FH "  </segment>\n";
321            } else {
322                print $WRITE_FH "/>\n";
323            }
324            $Stats{"segment"}++;
325            $SEGMENTS[$id]=1;
326        }
327    }
328
329    if($Element eq "way"){
330        print STDERR "\n" unless $Stats{"way read"}++ && $VERBOSE;
331        if ( @WaySegments ) {
332        print $WRITE_FH "  <way id=\'$id\'";
333        print $WRITE_FH " timestamp=\'".$MainAttr{timestamp}."\'" 
334            if defined $MainAttr{timestamp};
335        print $WRITE_FH ">";
336        print $WRITE_FH tags2osm(\%Tags);
337        for my $seg_id ( @WaySegments) {
338            next unless $seg_id;
339            print $WRITE_FH "    <seg id=\'$seg_id\'/>\n";
340        }
341        print $WRITE_FH "  </way>\n";
342        $Stats{"way"}++;
343        }
344    }
345
346}
347
348# Function is called whenever text is encountered in the XML file
349#----------------------------------------------
350sub DoChar(){
351    my ($Expat, $String) = @_;
352}
353
354##################################################################
355# Usage/manual
356
357__END__
358
359=head1 NAME
360
361B<osm-subset.pl.pl> Version 0.02
362
363=head1 DESCRIPTION
364
365B<osm-subset.pl.pl> is a program to extract an area from an osm File
366
367=head1 SYNOPSIS
368
369B<Common usages:>
370
371osm-subset.pl.pl [-d] [-v] [-h] [--no-mirror] [--proxy=<proxy:port>] [--list-areas] <planet_filename.osm>
372
373=head1 OPTIONS
374
375=over 2
376
377=item B<--man> Complete documentation
378
379Complete documentation
380
381=item B<--proxy=<proxy:port>>
382
383Use proxy Server to get the newest planet.osm File
384
385=item B<--no-mirror>
386
387do not try to get the newest planet.osm first
388
389=item B<--debug> B<-d>
390
391write out some debug info too
392
393=item B<--verbose> B<-v>
394
395write out more info while processing
396
397=item B<--area=germany> Area Filter
398
399Select Area for processing
400
401=item B<--list-areas>
402
403print all areas possible
404
405=item B<planet_filename.osm>
406
407the file to read from
408
409=back
410
411=head1 COPYRIGHT
412
413Copyright 2006, Jörg Ostertag
414
415This program is free software; you can redistribute it and/or
416modify it under the terms of the GNU General Public License
417as published by the Free Software Foundation; either version 2
418of the License, or (at your option) any later version.
419
420This program is distributed in the hope that it will be useful,
421but WITHOUT ANY WARRANTY; without even the implied warranty of
422MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
423GNU General Public License for more details.
424
425You should have received a copy of the GNU General Public License
426along with this program; if not, write to the Free Software
427Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
428
429=head1 AUTHOR
430
431Jörg Ostertag (planet-count-for-openstreetmap@ostertag.name)
432
433=head1 SEE ALSO
434
435http://www.openstreetmap.org/
436
437=cut
Note: See TracBrowser for help on using the repository browser.