source: subversion/applications/utils/filter/merge-ways/merge-ways.pl @ 17756

Last change on this file since 17756 was 14462, checked in by frederik, 11 years ago

new utility to merge adjoining ways into one, as a preprocessor for osmarender etc

File size: 3.6 KB
Line 
1#!/usr/bin/perl
2
3# A script that merges ways into one if they share certain characterstics.
4#     
5# Reads an OSM file on stdin, writes the merged file on stdout.
6#
7# May break referential integrity by dropping ways that are referenced by a relation!
8#
9# Writtern by Frederik Ramm <frederik@remote.org>, public domain.
10# -----------------------------------------------------------------------------
11
12# this is basically the configuration function: it controls which ways may be merged:
13
14sub tags_compatible 
15{
16    my ($a, $b) = @_;
17
18    return
19        $a->{highway} eq $b->{highway} &&
20        $a->{railway} eq $b->{railway} &&
21        $a->{waterway} eq $b->{waterway} &&
22        $a->{name} eq $b->{name};
23}
24
25# -----------------------------------------------------------------------------
26# no user serviceable parts below.
27#
28use strict;
29
30my $copy = 1;
31my $w = {};
32my $ways_beginning_at;
33
34while(<>)
35{
36    if (/^\s*<(node|way|relation) (.*)/)
37    {
38        if ($1 eq "way") 
39        {
40            $copy = 0;
41        }
42        elsif ($1 eq "relation") 
43        {
44            print_ways();
45            $copy = 1;
46        }
47    }
48    if ($copy)
49    {
50        print;
51        next;
52    }
53    if (/way id=['"](\d+)['"]/)
54    {
55        $w = {};
56        $w->{attr} = $_;
57        $w->{id} = $1;
58    }
59    elsif (/<nd ref=['"](\d+)['"]/)
60    {
61        if (defined($w->{firstnode}))
62        {
63            $w->{lastnode} = $1;
64        }
65        else
66        {
67            $w->{firstnode} = $1;
68        }
69        $w->{nodexml} .= $_;
70    }
71    elsif (/<tag k=(['"])(.*)\1 v=\1(.*)\1/)
72    {
73        $w->{tag}->{$2} = $3;
74        $w->{tagxml} .= $_;
75    }
76    elsif (/<\/way>/)
77    {
78        push(@{$ways_beginning_at->{$w->{firstnode}}}, $w);
79    }
80}
81
82sub print_ways
83{
84    foreach my $startnode(keys(%$ways_beginning_at))
85    {
86        foreach my $way(@{$ways_beginning_at->{$startnode}})
87        {
88            next if ($way->{drop});
89            do
90            {
91                my $again = 0;
92                next if ($way->{firstnode} == $way->{lastnode});
93                foreach my $cont(@{$ways_beginning_at->{$way->{lastnode}}})
94                {
95                    next if ($cont->{drop});
96                    next if ($cont->{firstnode} == $cont->{lastnode});
97                    if (tags_compatible($way->{tag}, $cont->{tag}))
98                    {
99                        # merge
100                        $cont->{drop} = 1;
101                        $way->{lastnode} = $cont->{lastnode};
102                        $way->{nodexml} .= $cont->{nodexml}; # fixme this duplicates one node in between
103                        $again = 1;
104
105                        printf STDERR "merge: %d (%s) and %d (%s)\n", 
106                            $way->{id}, tostring($way->{tag}), $cont->{id}, tostring($cont->{tag});
107                        last;
108                    }
109                }
110                last unless $again;
111            } 
112        }
113    }
114
115    my $sorted_ways = [];
116    foreach my $startnode(keys(%$ways_beginning_at))
117    {
118        foreach my $way(@{$ways_beginning_at->{$startnode}})
119        {
120            push @$sorted_ways, $way;
121        }
122        delete $ways_beginning_at->{$startnode};
123    }
124    undef $ways_beginning_at;
125
126    foreach my $way (sort { $a->{id} <=> $b->{id} } @$sorted_ways)
127    {
128        next if ($way->{drop});
129        print $way->{attr};
130        print $way->{tagxml};
131        print $way->{nodexml};
132        print "</way>\n";
133    }
134}
135
136sub tostring
137{
138    my $a = shift;
139    my $tags = [];
140    foreach my $key(keys %$a) { push(@$tags, "$key=".$a->{$key}); }
141    return "no tags" unless scalar(@$tags);
142    return join(",", @$tags);
143}
144
Note: See TracBrowser for help on using the repository browser.