source: subversion/applications/utils/conv05/04to05.pl @ 30494

Last change on this file since 30494 was 4835, checked in by gabriel, 12 years ago

conv05: 04to05.pl: Untested support for JOSM's action attribute.

  • Property svn:executable set to *
File size: 6.7 KB
Line 
1#!/usr/bin/env perl
2# Copyright (C) 2007  Gabriel Ebner
3#
4# Permission is hereby granted, free of charge, to any person
5# obtaining a copy of this software and associated documentation
6# files (the "Software"), to deal in the Software without
7# restriction, including without limitation the rights to use,
8# copy, modify, merge, publish, distribute, sublicense, and/or sell
9# copies of the Software, and to permit persons to whom the
10# Software is furnished to do so, subject to the following
11# conditions:
12#
13# The above copyright notice and this permission notice shall be
14# included in all copies or substantial portions of the Software.
15#
16# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23# OTHER DEALINGS IN THE SOFTWARE.
24
25use XML::Parser;
26use HTML::Entities;
27
28sub esc { HTML::Entities::encode_numeric( $_[0] || $_ ) }
29
30my $p = XML::Parser->new;
31
32my $new_rel_id = -1;
33my $new_way_id = -1;
34my ( %segs, %used_segs );
35our ( $id, $user, $timestamp, $action, %tags, $lat, $lon, $from, $to, @segs );
36
37sub obj_init($) {
38    my %attr = %{ $_[0] };
39    ( $id, $user, $timestamp, $visible, $action ) =
40      @attr{qw(id user timestamp visible action)};
41    $visible = 1 unless defined $visible;
42    $action ||= '';
43    %tags = @segs = ();
44}
45
46sub fmt_std_tags {
47    my %atts = (
48        id        => $id,
49        user      => $user,
50        visible   => $visible,
51        timestamp => $timestamp,
52        action    => $action || undef,
53    );
54    for ( keys %atts ) {
55        if ( defined $atts{$_} ) {
56            $atts{$_} = esc $atts{$_};
57        }
58        else {
59            delete $atts{$_};
60        }
61    }
62    join ' ', map qq($_="$atts{$_}"), keys %atts;
63}
64
65sub write_tags {
66    while ( my ( $k, $v ) = each %tags ) {
67        printf qq(    <tag k="%s" v="%s"/>\n), map esc, $k, $v;
68    }
69}
70
71$p->setHandlers(
72    Start => sub {
73        my ( $p, $name, %attr ) = @_;
74        if ( $name eq 'tag' ) {
75            $tags{ $attr{'k'} } = $attr{'v'};
76        }
77        elsif ( $name eq 'seg' ) {
78            push @segs, $attr{'id'};
79        }
80        elsif ( $name eq 'node' ) {
81            obj_init \%attr;
82            ( $lat, $lon ) = @attr{qw(lat lon)};
83        }
84        elsif ( $name eq 'segment' ) {
85            obj_init \%attr;
86            ( $from, $to ) = @attr{qw(from to)};
87        }
88        elsif ( $name eq 'way' ) {
89            obj_init \%attr;
90        }
91    },
92    End => sub {
93        my ( $p, $name ) = @_;
94        if ( $name eq 'node' ) {
95            printf qq(  <node %s lat="%s" lon="%s">\n), fmt_std_tags, map esc,
96              $lat, $lon;
97            write_tags;
98            printf qq(  </node>\n);
99        }
100        elsif ( $name eq 'segment' ) {
101            $segs{$id} =
102              [ $id, $user, $timestamp, $visible, $action, {%tags}, $from, $to ]
103              if $visible;
104        }
105        elsif ( $name eq 'way' ) {
106            $id = $new_way_id-- if $id < 0;
107            my @pairs = map {
108                $used_segs{$_} = 1;
109                if ( defined $segs{$_} ) {
110                    [ $segs{$_}->[6], $segs{$_}->[7] ];
111                }
112                else { () }
113            } @segs;
114            my @chunks;
115            while (@pairs) {
116                my @chunk = @{ shift @pairs };
117                while (1) {
118                    my $found = 0;
119                    my @new_pairs;
120                    for (@pairs) {
121                        if ( $_->[0] == $chunk[ @chunk - 1 ] ) {
122                            push @chunk, $_->[1];
123                            $found = 1;
124                        }
125                        elsif ( $_->[1] == $chunk[0] ) {
126                            unshift @chunk, $_->[0];
127                            $found = 1;
128                        }
129                        else {
130                            push @new_pairs, $_;
131                        }
132                    }
133                    @pairs = @new_pairs;
134                    last unless $found;
135                }
136                push @chunks, \@chunk;
137            }
138
139            my $new_action = '';
140            my @seg_actions = map $segs{$_}->[4], @segs;
141            $new_action = 'modify' if grep $_, @seg_actions;
142            $new_action = 'delete' if $action eq 'delete';
143            local $action = $new_action;
144
145            @chunks = $chunks[0] if @chunks and $action eq 'delete';
146
147            my $orig_id_used = 0;
148            my @ids;
149            for my $chunk (@chunks) {
150                my $way_id;
151                unless ($orig_id_used) {
152                    $way_id       = $id;
153                    $orig_id_used = 1;
154                }
155                else {
156                    $way_id = $new_way_id--;
157                }
158                push @ids, $way_id;
159                local $id = $way_id;
160                printf qq(  <way %s>\n), fmt_std_tags;
161                printf qq(    <nd ref="%s"/>\n), esc $_ for @$chunk;
162                write_tags;
163                printf qq(  </way>\n);
164            }
165
166            if ( @ids > 1 ) {
167                my $create_multipolygon =
168                  ( defined $tags{'natural'}
169                      and $tags{'natural'} ne 'coastline' )
170                  || ( defined $tags{'waterway'}
171                    and $tags{'waterway'} eq 'riverbank' )
172                  || grep( defined $tags{$_},
173                    qw(leisure landuse sport amenity tourism building) );
174                if ($create_multipolygon) {
175                    local $action = undef;
176                    local $id     = $new_rel_id--;
177                    printf qq(  <relation %s>\n), fmt_std_tags;
178                    printf qq(    <member type="way" ref="%s" role=""/>\n),
179                      esc $_
180                      for @ids;
181                    print qq(    <tag k="type" v="multipolygon"/>\n);
182                    print qq(  </relation>\n);
183                }
184            }
185        }
186    },
187);
188
189print qq(<?xml version="1.0"?>\n<osm version="0.5" generator="04to05.pl">\n);
190
191if (@ARGV) {
192    $p->parsefile($_) for @ARGV;
193}
194else {
195    $p->parse( \*STDIN );
196}
197
198for my $seg ( values %segs ) {
199    my $tags;
200    ( $id, $user, $timestamp, $visible, $action, $tags, $from, $to ) = @$seg;
201    %tags = %$tags;
202    next unless not $used_segs{$id} or grep( $_ ne 'created_by', keys %tags );
203    next if $action eq 'delete';
204
205    local $id = $new_way_id--;
206    printf qq(  <way %s>\n), fmt_std_tags;
207    printf qq(    <nd ref="%s"/>\n), esc $_ for ( $from, $to );
208    write_tags;
209    printf qq(  </way>\n);
210}
211
212print qq(</osm>\n);
Note: See TracBrowser for help on using the repository browser.