source: subversion/applications/utils/osm-extract/polygons/rel2poly.pl @ 29411

Last change on this file since 29411 was 26497, checked in by frederik, 8 years ago

new utilities: rel2poly.pl reads OSM relation and makes polygon file; poly2wkt.pl creates WKT string for use with spatial databases

File size: 4.0 KB
Line 
1#!/usr/bin/perl
2
3# script to convert an OSM file to a polygon file.
4#
5# usage:
6# perl rel2osm.pl < input.osm > output.poly
7#
8# difference between this program and osm2poly.pl:
9#
10# This program takes all ways found in the file, assembles them into rings, and
11# outputs ONE polygon for the ring with the most nodes. This means that it works
12# for files with one closed way as well as for files with a multipolygon or
13# boundary relation as obtained by an URL like
14# http://api.openstreetmap.org/api/0.6/relation/1234/full
15#
16# This program does not honour inner rings or multiple outer rings. This could
17# be improved if somebody were so inclined.
18#
19# On the other hand, osm2poly.pl requires closed ways only (no relation
20# processing) but can support multiple of them in one file.
21#
22# written by Frederik Ramm <frederik@remote.org>, public domain.
23
24use strict;
25use warnings;
26
27my $poly_id;
28my $poly_file;
29my $polybuf;
30my $outbuf;
31my $nodes;
32my $id=0;
33my $ways;
34my $wayid;
35my $currentway;
36my $waycount;
37my $nodecount;
38
39while(<>) 
40{
41    if (/^\s*<node.*\sid=["']([0-9-]+)['"].*lat=["']([0-9.eE-]+)["'] lon=["']([0-9.eE-]+)["']/)
42    {
43        $nodes->{$1}=[$2,$3];
44        $nodecount++;
45    }
46    elsif (/^\s*<way.*\sid=["']([0-9-]+)['"]/)
47    {
48        $wayid=$1;
49        $waycount++;
50    }
51    elsif (/^\s*<nd ref=['"]([0-9-]+)["']/)
52    {
53        my $id=$1;
54        die("dangling reference to node $id") unless defined($nodes->{$id});
55        push(@$currentway, $id);
56    }
57    elsif (/^\s*<\/way/) 
58    {
59        $ways->{$wayid} = $currentway;
60        undef $currentway;
61    }
62}
63
64my $rings;
65my $currentring = [];
66my $firstnode;
67my $lastnode;
68my $closed = 0;
69my $unclosed = 0;
70
71die ("no ways found in file") unless(scalar keys %$ways);
72
73while(scalar keys %$ways)
74{
75    my $nochange = 1;
76    foreach my $wid (keys %$ways)
77    {
78        if (!scalar(@$currentring))
79        {
80            add_way_to_ring($currentring, $wid, 0, 0);
81            delete $ways->{$wid};
82            $nochange = 0;
83            last;
84        }
85        $firstnode = $currentring->[0];
86        $lastnode = $currentring->[scalar(@$currentring)-1];
87        my $wayfirst = $ways->{$wid}->[0];
88        my $waylast = $ways->{$wid}->[scalar(@{$ways->{$wid}})-1];
89        if ($wayfirst == $firstnode)
90        {
91            shift @$currentring;
92            add_way_to_ring($currentring, $wid, 1, 1);
93            delete $ways->{$wid};
94            $nochange = 0;
95            last;
96        } 
97        elsif ($wayfirst == $lastnode)
98        {
99            pop @$currentring;
100            add_way_to_ring($currentring, $wid, 0, 0);
101            delete $ways->{$wid};
102            $nochange = 0;
103            last;
104        }
105        elsif ($waylast == $firstnode)
106        {
107            shift @$currentring;
108            add_way_to_ring($currentring, $wid, 1, 0);
109            delete $ways->{$wid};
110            $nochange = 0;
111            last;
112        } 
113        elsif ($waylast == $lastnode)
114        {
115            pop @$currentring;
116            add_way_to_ring($currentring, $wid, 0, 1);
117            delete $ways->{$wid};
118            $nochange = 0;
119            last;
120        }
121    }
122    $firstnode = $currentring->[0];
123    $lastnode = $currentring->[scalar(@$currentring)-1];
124    if ($nochange)
125    {
126        $currentring = [];
127        $unclosed++;
128        next;
129    }
130    if ($firstnode == $lastnode)
131    {
132        push(@$rings, $currentring);
133        $closed++;
134        $currentring = [];
135    }
136}
137
138die ("no closed rings in file") unless $closed;
139
140printf(STDERR "processed %d nodes, %d ways, dropped %d unclosed rings, chose biggest of %d closed rings\n",
141   $nodecount, $waycount, $unclosed, $closed);
142
143foreach my $ring(sort { scalar(@$b) <=> scalar(@$a) } @$rings)
144{
145    print "polygon\n1\n";
146    foreach my $id(@$ring)
147    {
148        printf("   %E   %E\n", $nodes->{$id}->[1], $nodes->{$id}->[0]);
149    }
150    printf("END\nEND\n");
151    last;
152}
153
154sub add_way_to_ring
155{
156    my ($ring, $wayid, $front, $rev) = @_;
157    my @nodes = @{$ways->{$wayid}};
158    @nodes = reverse @nodes if ($rev);
159    if ($front) { unshift(@$ring, @nodes) } else { push(@$ring, @nodes) };
160}
161
Note: See TracBrowser for help on using the repository browser.