source: subversion/applications/utils/osm-extract/polygons/polyconvert.pl @ 26629

Last change on this file since 26629 was 26629, checked in by zverik, 8 years ago

polyconvert.pl

File size: 7.1 KB
Line 
1#!/usr/bin/perl
2
3# This converts *.poly into *.osm or *.gpx or *.wkt and back.
4# Can work as a CGI script, format=osm/gpx/wkt (default osm), source: content or file
5# Replaces (and is based on) poly2osm.pl, poly2wkt.pl, poly2bb.pl, gpx2poly.pl, osm2poly.pl
6#
7# written by Ilya Zverev <zverik@textual.ru>, public domain.
8
9use strict;
10use CGI;
11
12my $iscgi = defined($ENV{'REQUEST_METHOD'});
13my $cgi = CGI->new if $iscgi;
14
15my $to = $iscgi ? $cgi->param('format') || 'osm' : 'osm';
16
17my $contents;
18my $tmpseparator = $/;
19undef $/;
20if( $iscgi ) {
21        my $handle  = $cgi->upload('file');
22        $contents = defined($handle) ? <$handle> : $cgi->param('content');
23} else {
24        $contents = <>;
25}
26$/ = $tmpseparator;
27error("Empty input file") if $contents =~ /^\s*$/;
28$contents =~ s/\r//g;
29
30my $result;
31my $ext;
32if( $contents =~ /END\s+END\s*$/ ) {
33        # poly
34        if( $to eq 'osm' ) { $result = poly2osm($contents); $ext = 'osm'; }
35        elsif( $to eq 'gpx' || $to eq 'ol' ) { $result = poly2gpx($contents); $ext = 'gpx'; }
36        elsif( $to eq 'wkt' ) { $result = poly2wkt($contents); $ext = 'wkt'; }
37        else { error("Unknown format $to"); }
38}
39elsif( $contents =~ /^MULTIPOLYGON/ ) {
40        $result = wkt2poly($contents);
41        $ext = 'poly';
42}
43elsif( $contents =~ /\<gpx.+\<trkpt/s ) {
44        $result = gpx2poly($contents);
45        $ext = 'poly';
46}
47elsif( $contents =~ /\<osm.+\<node/s ) {
48        $result = osm2poly($contents);
49        $ext = 'poly';
50}
51else { error("Unknown format of input file"); }
52
53if( $to eq 'ol' ) {
54        error("Source file must be poly or gpx") if $result !~ /\<gpx/ && $contents !~ /\<gpx/;
55        $result = openlayers($result =~ /\<gpx/ ? $result : $contents);
56        print "Content-type: text/html\n\n" if $iscgi;
57} else {
58        print "Content-Disposition: attachment; filename=result.$ext\n\n" if $iscgi;
59}
60print $result;
61
62sub error {
63        my($error) = @_;
64        die($error) if !$iscgi;
65        print "Content-type: text/html\n\nError: <b>$error</b><br>Sorry.";
66        exit;
67}
68
69# Worker subs. Input: the whole file as string. Returns resulting file as string.
70
71sub poly2gpx {
72        my @contents = split /^/, $_[0];
73        my $pos = 0;
74        # first line
75        # (employ workaround for polygon files without initial text line)
76        my $poly_file = $contents[$pos++]; chomp($poly_file);
77        my $workaround = 0;
78        if ($poly_file =~ /^\d+$/)
79        {
80                $workaround=$poly_file;
81                $poly_file="none";
82        }
83
84        my $tracks;
85
86        while(1)
87        {
88                my $poly_id = $workaround || $contents[$pos++];
89                chomp($poly_id);
90                last if ($poly_id =~ /^END/); # end of file
91               
92                $tracks .= "<trk>\n<name>$poly_file $poly_id</name>\n<trkseg>\n";       
93
94                while(my $line = $contents[$pos++])
95                {
96                        last if ($line =~ /^END/); # end of poly
97                        my ($dummy, $x, $y) = split(/\s+/, $line);
98                        $tracks .= sprintf("  <trkpt lat=\"%f\" lon=\"%f\" />\n  </trkpt>\n", $y, $x);
99                }
100                $tracks .= "</trkseg>\n</trk>\n";       
101                $workaround=0;
102        }
103
104        return "<?xml version='1.0' encoding='UTF-8'?>\n<gpx version=\"1.1\" creator=\"polyconvert.pl\" xmlns=\"http://www.topografix.com/GPX/1/1\" ".
105    "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd\">\n".
106        "$tracks</gpx>";
107}
108
109sub poly2wkt {
110        my @contents = split /^/, $_[0];
111        my $pos = 0;
112        # first line
113        # (employ workaround for polygon files without initial text line)
114        my $poly_file = $contents[$pos++]; chomp($poly_file);
115        my $workaround = 0;
116        if ($poly_file =~ /^\d+$/)
117        {
118                $workaround=$poly_file;
119                $poly_file="none";
120        }
121
122        my $polygons;
123
124        while(1)
125        {
126                my $poly_id = $workaround || $contents[$pos++];
127                chomp($poly_id);
128                last if ($poly_id =~ /^END/); # end of file
129                my $coords;
130
131                while(my $line = $contents[$pos++])
132                {
133                        last if ($line =~ /^END/); # end of poly
134                        my ($dummy, $x, $y) = split(/\s+/, $line);
135                        push(@$coords, sprintf("%f %f", $x, $y));
136                }
137                push(@$polygons, "((".join(",", @$coords)."))");
138                $workaround=0;
139        }
140
141        return "MULTIPOLYGON(".join(",",@$polygons).")\n";
142}
143
144sub poly2osm {
145        my @contents = split /^/, $_[0];
146        my $pos = 0;
147        my %nodehash;
148
149        # first line
150        # (employ workaround for polygon files without initial text line)
151        my $poly_file = $contents[$pos++]; chomp($poly_file);
152        my $workaround = 0;
153        if ($poly_file =~ /^\d+$/)
154        {
155                $workaround=$poly_file;
156                $poly_file="none";
157        }
158
159        my $nodecnt = -1;
160        my $waycnt = -1;
161
162        my $nodes;
163        my $ways;
164        my $note = "    <tag k='note' v='created by poly2osm.pl from a polygon file. not for uploading!' />\n";
165        my $line;
166
167        while(1) {
168                my $poly_id;
169                if ($workaround==0) {
170                   $poly_id=$contents[$pos++];
171                } else {
172                   $poly_id=$workaround;
173                }
174                chomp($poly_id);
175                my $startnode = $nodecnt;
176                last if ($poly_id =~ /^END/); # end of file
177
178                $ways .= sprintf("  <way id='%d'>\n    <tag k='polygon_id' v='%d' />\n    <tag k='polygon_file' v='%s' />\n",
179                        $waycnt--, $poly_id, $poly_file);
180                $ways .= $note;
181
182                while($line = $contents[$pos++])
183                {
184                        last if ($line =~ /^END/); # end of poly
185                        my ($dummy, $x, $y) = split(/\s+/, $line);
186                        my $existingnode = $nodehash{"$x|$y"};
187                        if (defined($existingnode))
188                        {
189                                $ways .= sprintf("    <nd ref='%d' />\n", $existingnode);
190                        }
191                        else
192                        {
193                                $nodehash{"$x|$y"} = $nodecnt;
194                                $ways .= sprintf("    <nd ref='%d' />\n", $nodecnt);
195                                $nodes .= sprintf("  <node id='%d' lat='%f' lon='%f' />\n", $nodecnt--, $y, $x);
196                        }
197                }
198                $ways .= "  </way>\n";
199                undef $workaround;
200        };
201        return "<osm generator='osm2poly.pl' version='0.5'>\n$nodes$ways</osm>\n";
202}
203
204sub gpx2poly {
205        my @contents = split /^/, $_[0];
206        my $pos = 0;
207        my $poly_id = -1;
208        my $poly_file;
209        my $polybuf;
210        my $outbuf;
211        my $id=0;
212
213        while($pos <= $#contents) 
214        {
215                $_ = $contents[$pos++];
216                if (/^\s*<trkpt.*\slon=["']([0-9.eE-]+)["'] lat=["']([0-9.eE-]+)["']/)
217                {
218                        $polybuf .= sprintf "\t%f\t%f\n", $1,$2;
219                } 
220                elsif (/^\s*<trk>/) 
221                {
222                        $polybuf = "";
223                        $poly_id++;
224                }
225                elsif (/^\s*<\/trk>/) 
226                {
227                        $outbuf .= "$poly_id\n$polybuf"."END\n";
228                }
229        }
230
231        $poly_file = "polygon" unless defined($poly_file);
232        return "$poly_file\n$outbuf"."END\n";
233}
234
235sub wkt2poly {
236        error("wkt2poly not implemented yet");
237}
238
239sub osm2poly {
240        my @contents = split /^/, $_[0];
241        my $pos = 0;
242        my $poly_id;
243        my $poly_file;
244        my $polybuf;
245        my $outbuf;
246        my $nodes;
247        my $id=0;
248
249        while($pos <= $#contents) 
250        {
251                $_ = $contents[$pos++];
252                if (/^\s*<node.*\sid=["']([0-9-]+)['"].*lat=["']([0-9.eE-]+)["'] lon=["']([0-9.eE-]+)["']/)
253                {
254                        $nodes->{$1}=[$2,$3];
255                }
256                elsif (/^\s*<way /)
257                {
258                        undef $poly_id;
259                        undef $poly_file;
260                        $polybuf = "";
261                }
262                elsif (defined($polybuf) && /k=["'](.*)["']\s*v=["'](.*?)["']/)
263                {
264                        if ($1 eq "polygon_file") 
265                        {
266                                $poly_file=$2;
267                        }
268                        elsif ($1 eq "polygon_id")
269                        {
270                                $poly_id=$2;
271                        }
272                        elsif ($1 ne "note")
273                        {
274                                error("cannot process tag '$1'");
275                        }
276                }
277                elsif (/^\s*<nd ref=['"]([0-9-]+)["']/)
278                {
279                        my $id=$1;
280                        error("dangling reference to node $id") unless defined($nodes->{$id});
281                        $polybuf .= sprintf("   %f   %f\n", $nodes->{$id}->[1], $nodes->{$id}->[0]);
282                }
283                elsif (/^\s*<\/way/) 
284                {
285                        if (!defined($polybuf))
286                        {
287                                error("incomplete way definition");
288                        }
289                        $poly_id = ++$id unless defined($poly_id);
290                        $outbuf .= "$poly_id\n$polybuf"."END\n";
291                        undef $polybuf;
292                }
293        }
294        $poly_file = "polygon" unless defined($poly_file);
295        return "$poly_file\n$outbuf"."END\n";
296}
297
298sub openlayers {
299        error("no OpenLayers output yet");
300}
Note: See TracBrowser for help on using the repository browser.