source: subversion/applications/utils/gary68/distancemap.pl @ 26507

Last change on this file since 26507 was 16545, checked in by gary68, 10 years ago

first alpha 1.0

  • Property svn:executable set to *
File size: 11.2 KB
Line 
1#
2#
3# Copyright (C) 2009, Gerhard Schwanz
4#
5# This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the
6# Free Software Foundation; either version 3 of the License, or (at your option) any later version.
7#
8# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
9# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
10#
11# You should have received a copy of the GNU General Public License along with this program; if not, see <http://www.gnu.org/licenses/>
12#
13
14use strict ;
15use warnings ;
16
17use OSM::osm 4.0 ;
18use OSM::osmgraph 2.0 ;
19
20my $programName = "distancemap.pl" ;
21my $usage = "distancemap.pl file.osm out.png size" ; # svg and other output names are automatic
22my $version = "1.0" ;
23
24#
25# ENTER INFORMATION IN THIS SECTION
26# ---------------------------------
27#
28
29# enter destination node id here
30my $root = 88453792 ;
31
32# add all allowed pathes here
33my %allowedPaths = () ;
34$allowedPaths{"highway:residential"} = 1 ;
35$allowedPaths{"highway:primary"} = 1 ;
36$allowedPaths{"highway:secondary"} = 1 ;
37$allowedPaths{"highway:tertiary"} = 1 ;
38$allowedPaths{"highway:service"} = 1 ;
39# etc...
40
41#
42#
43#
44
45my $infinity = "inf";
46my %dist ;
47my %edge ;
48my %prev ;
49my @s ;
50my %usedNodes ;
51my @unsolved ;
52my %wayCount = () ;
53
54my $labelMinLength = 0.1 ; # min length of street so that it will be labled / needs adjustment according to picture size
55
56my $wayId ;
57my $wayUser ;
58my @wayNodes ;
59my @wayTags ;
60my $nodeId ;
61my $nodeUser ;
62my $nodeLat ;
63my $nodeLon ;
64my @nodeTags ;
65my $aRef1 ;
66my $aRef2 ;
67
68my $osmName ; 
69my $pngName ;
70
71my %lon ; my %lat ;
72my %placeName ;
73
74my $size ;
75my $lonMin ; my $latMin ; my $lonMax ; my $latMax ;
76
77my $time0 ; my $time1 ;
78
79# get parameter
80
81$osmName = shift||'';
82if (!$osmName)
83{
84        die (print $usage, "\n");
85}
86
87$pngName = shift||'';
88if (!$pngName)
89{
90        die (print $usage, "\n");
91}
92
93$size = shift||'';
94if (!$size)
95{
96        $size = 4096 ; # default size
97}
98
99print "\n$programName $version for file $osmName\n" ;
100
101$time0 = time() ;
102
103# get all node locations and place information
104
105print "get node information...\n" ;
106openOsmFile ($osmName) ;
107
108($nodeId, $nodeLon, $nodeLat, $nodeUser, $aRef1) = getNode () ;
109if ($nodeId != -1) {
110        @nodeTags = @$aRef1 ;
111}
112
113while ($nodeId != -1) {
114
115        $lon{$nodeId} = $nodeLon ;     
116        $lat{$nodeId} = $nodeLat ;     
117
118        my $place = 0 ; my $name = 0 ; my $tag ; my $nameStr ;
119        foreach $tag (@nodeTags) {
120                my $tmp = $tag ;
121                if ((grep /name:/ , $tag) and ( ($tmp =~ s/://g ) == 1 ) and 
122                        ( ! (grep /place_name:/ , $tag)) ) { 
123                        $nameStr = $tag ; $nameStr =~ s/name:// ;
124                        $name = 1 ; 
125                }
126                if (grep /place:/, $tag)  { $place = 1 ; }
127        }
128        if (($place) and ($name)) {
129                $placeName{$nodeId} = $nameStr ;
130                #print $nodeId, " ", $nameStr, "\n" ;
131        }
132
133        ($nodeId, $nodeLon, $nodeLat, $nodeUser, $aRef1) = getNode () ;
134        if ($nodeId != -1) {
135                @nodeTags = @$aRef1 ;
136        }
137}
138
139# calc area of pic
140
141$lonMin = 999 ; $lonMax = -999 ; $latMin = 999 ; $latMax = -999 ;
142my $key ;
143foreach $key (keys %lon) {
144        if ($lon{$key} > $lonMax) { $lonMax = $lon{$key} ; }
145        if ($lon{$key} < $lonMin) { $lonMin = $lon{$key} ; }
146        if ($lat{$key} > $latMax) { $latMax = $lat{$key} ; }
147        if ($lat{$key} < $latMin) { $latMin = $lat{$key} ; }
148}
149
150initGraph ($size, $lonMin, $latMin, $lonMax, $latMax) ;
151
152enableSVG () ;
153
154# draw areas first
155
156print "draw areas and init dijkstra data...\n" ;
157
158($wayId, $wayUser, $aRef1, $aRef2) = getWay () ;
159if ($wayId != -1) {
160        @wayNodes = @$aRef1 ;
161        @wayTags = @$aRef2 ;
162}
163while ($wayId != -1) {
164        my $highway = "none" ;
165        foreach $key (@wayTags) {
166                if ($key eq "waterway:riverbank") {
167                        drawArea ("lightblue", nodes2Coordinates(@wayNodes)) ;
168                }
169                if ($key eq "natural:water") {
170                        drawArea ("lightblue", nodes2Coordinates(@wayNodes)) ;
171                }
172                if ( ($key eq "landuse:forest") or ($key eq "natural:wood") ) {
173                        drawArea ("lightbrown", nodes2Coordinates(@wayNodes)) ;
174                }
175                if ( ($key eq "landuse:farm") or ($key eq "landuse:village_green") ) {
176                        drawArea ("lightgreen", nodes2Coordinates(@wayNodes)) ;
177                }
178                if ($key eq "landuse:residential") {
179                        drawArea ("lightgray", nodes2Coordinates(@wayNodes)) ;
180                }
181                if (grep /^highway:/, $key) { $highway = $key ; }
182        }       
183
184        # init dijkstra data
185        if ( (defined ($allowedPaths{$highway})) and (scalar (@wayNodes) > 1 ) ) {
186                # set distances
187                my $i ;
188                for ($i=0; $i<$#wayNodes; $i++) {
189                        my $dist = distance ($lon{$wayNodes[$i]}, $lat{$wayNodes[$i]}, $lon{$wayNodes[$i+1]}, $lat{$wayNodes[$i+1]}) ;
190                        $edge{$wayNodes[$i]}{$wayNodes[$i+1]} = $dist ;
191                        $edge{$wayNodes[$i+1]}{$wayNodes[$i]} = $dist ;
192                }
193
194                # incr waycount per node (count > 0 --> crossing)
195                foreach my $node (@wayNodes) {
196                        if (defined ($wayCount{$node})) {
197                                $wayCount{$node} ++ ;
198                        }
199                        else {
200                                $wayCount{$node} = 1 ;
201                        }
202                        $usedNodes{$node} = 1 ;
203                }
204       
205        }       
206
207        ($wayId, $wayUser, $aRef1, $aRef2) = getWay () ;
208        if ($wayId != -1) {
209                @wayNodes = @$aRef1 ;
210                @wayTags = @$aRef2 ;
211        }
212}
213
214closeOsmFile () ;
215
216# DIJKSTRA
217print "dijkstra running...\n" ;
218
219# init unsolved nodes array
220foreach my $node (keys %usedNodes) { push @unsolved, $node ; }
221
222# alg
223# all dist = infinity
224foreach my $n (keys %usedNodes) { 
225        $dist{$n} = $infinity ; 
226        $prev{$n}=$n ; 
227}
228
229$dist{$root} = 0;
230
231# loop while we have unsolved nodes
232while (@unsolved) {
233        my ($n, $n2) ;
234        @unsolved = sort byDistance @unsolved;
235        push @s, $n = shift @unsolved;
236        foreach $n2 (keys %{$edge{$n}}) {
237                if (($dist{$n2} eq $infinity) ||
238                        ($dist{$n2} > ($dist{$n} + $edge{$n}{$n2}) )) {
239                        $dist{$n2} = $dist{$n} + $edge{$n}{$n2} ;
240                        $prev{$n2} = $n;
241                }
242        }
243}
244
245
246
247
248# draw ways
249
250print "draw ways...\n" ;
251
252openOsmFile ($osmName) ;
253skipNodes () ;
254
255($wayId, $wayUser, $aRef1, $aRef2) = getWay () ;
256if ($wayId != -1) {
257        @wayNodes = @$aRef1 ;
258        @wayTags = @$aRef2 ;
259}
260while ($wayId != -1) {
261        my $name = "" ; my $ref = "" ;
262        my $length = 0 ;
263        foreach $key (@wayTags) {
264                if (grep /^name:/, $key) { $name = $key ; $name =~ s/name:// ; }
265                if (grep /^ref:/, $key) { $ref = $key ; $ref =~ s/ref:// ; }
266        }
267
268        if (scalar @wayNodes > 1) {
269
270
271                my $i ;
272                for ($i = 0; $i<$#wayNodes; $i++) {
273                        $length += distance ($lon{$wayNodes[$i]}, $lat{$wayNodes[$i]}, $lon{$wayNodes[$i+1]}, $lat{$wayNodes[$i+1]}) ;
274                }
275
276
277                foreach $key (@wayTags) {
278                        if ($key eq "highway:residential") {
279                                drawWay ("gray", 1, nodes2Coordinates(@wayNodes)) ;
280                                if ( ($name ne "") and ($length > $labelMinLength) ) { labelWay ("black", 0, "", $name, -2, nodes2Coordinates(@wayNodes)) ; }
281                        }
282                        if ( ($key eq "highway:service") or ($key eq "highway:unclassified") ) {
283                                drawWay ("gray", 1, nodes2Coordinates(@wayNodes)) ;
284                        }
285                        if ( ($key eq "waterway:river") or ($key eq "waterway:stream") ) {
286                                drawWay ("lightblue", 1, nodes2Coordinates(@wayNodes)) ;
287                        }
288                        if ($key eq "highway:motorway") {
289                                drawWay ("blue", 3, nodes2Coordinates(@wayNodes)) ;
290                                if ( ($ref ne "") and ($length > $labelMinLength) ) { labelWay ("blue", 4, "", $ref, -8, nodes2Coordinates(@wayNodes)) ; }
291                        }
292                        if ($key eq "highway:motorway_link") {
293                                drawWay ("blue", 2, nodes2Coordinates(@wayNodes)) ;
294                        }
295                        if ($key eq "highway:trunk") {
296                                drawWay ("blue", 3, nodes2Coordinates(@wayNodes)) ;
297                                if ( ($ref ne "") and ($length > $labelMinLength) ) { labelWay ("blue", 4, "", $ref, -8, nodes2Coordinates(@wayNodes)) ; }
298                        }
299                        if ($key eq "highway:trunk_link") {
300                                drawWay ("blue", 2, nodes2Coordinates(@wayNodes)) ;
301                        }
302                        if ( ($key eq "highway:primary") or ($key eq "highway:primary_link") ) {
303                                drawWay ("red", 2, nodes2Coordinates(@wayNodes)) ;
304                        }
305                        if ( ($key eq "highway:primary") ) {
306                                if ( ($ref ne "") and ($length > $labelMinLength) ) { labelWay ("red", 2, "", $ref, -3, nodes2Coordinates(@wayNodes)) ;  }
307                        }
308                        if ($key eq "highway:secondary") {
309                                drawWay ("red", 2, nodes2Coordinates(@wayNodes)) ;
310                                if ( ($ref ne "") and ($length > $labelMinLength) ) { labelWay ("red", 2, "", $ref, -3, nodes2Coordinates(@wayNodes)) ;  }
311                        }
312                        if ($key eq "highway:tertiary") {
313                                drawWay ("gray", 2, nodes2Coordinates(@wayNodes)) ;
314                                if ( ($ref ne "") and ($length > $labelMinLength) ) { labelWay ("gray", 2, "", $ref, -3, nodes2Coordinates(@wayNodes)) ; }
315                        }
316        #               if ($key eq "highway:track") {
317        #                       drawWay ("lightgray", 1, nodes2Coordinates(@wayNodes)) ;
318        #               }
319                }
320        }       
321       
322        ($wayId, $wayUser, $aRef1, $aRef2) = getWay () ;
323        if ($wayId != -1) {
324                @wayNodes = @$aRef1 ;
325                @wayTags = @$aRef2 ;
326        }
327}
328
329closeOsmFile () ;
330
331# draw place names
332
333print "draw places and distances...\n" ;
334
335foreach $key (keys %placeName) {
336        # drawNodeDot ($lon{$key}, $lat{$key}, "black", 4) ;
337        drawTextPos ($lon{$key}, $lat{$key}, 0, 0, $placeName{$key}, "black", 2) ;
338}
339
340# draw node dist information
341foreach my $node (keys %wayCount) {
342        if ( ($wayCount{$node} > 1) and ($dist{$node} > 0) ) {
343                my $d = int ($dist{$node} * 1000) / 1000 ;
344                drawTextPos ($lon{$node}, $lat{$node}, 0, 0, $d, "blue", 1) ;
345        }
346}
347
348# draw other information
349
350print "draw other information...\n" ;
351
352drawTextPos ($lon{$root}, $lat{$root}, 0, 0, "DEST", "red", 4) ;
353
354drawLegend (2, "Farm", "lightgreen", "Forest", "lightbrown", "Residential", "lightgray", "Water", "lightblue", "Primary", "red", "Motorway", "blue", "Legend", "black") ;
355drawRuler ("darkgray") ;
356drawHead ("gary68's distancemap", "black", 2) ;
357drawFoot ("data by www.openstreetmap.org", "gray", 2) ;
358
359
360writeGraph ($pngName) ;
361
362my $svgName = $pngName ; $svgName =~ s/.png/.svg/ ;
363writeSVG ($svgName) ;
364
365# write gpx file and osm snippet
366my $gpxName = $pngName ; $gpxName =~ s/.png/.gpx/ ;
367my $gpxFile ;
368open ($gpxFile, ">", $gpxName) or die ("can't open gpx output file") ;
369printGPXHeader ($gpxFile) ;
370foreach my $node (keys %wayCount) {
371        if ($wayCount{$node} > 1) {
372                printGPXWaypoint ($gpxFile, $lon{$node}, $lat{$node}, $dist{$node}) 
373        }
374}
375printGPXFoot ($gpxFile) ;
376close ($gpxFile) ;
377
378my $osm2Name = $pngName ; $osm2Name =~ s/.png/.osm/ ;
379my $osm2File ;
380open ($osm2File, ">", $osm2Name) or die ("can't open osm output file") ;
381foreach my $node (keys %wayCount) {
382        if ($wayCount{$node} > 1) {
383                my $id = 1000000000 + $node ;
384                print $osm2File "  <node id=\"", $id, "\" timestamp=\"2009-07-14T00:00:00+00:00\" user=\"distancemap\"" ;
385                print $osm2File " lat=\"", $lat{$node}, "\"" ;
386                print $osm2File " lon=\"", $lon{$node}, "\">\n" ;
387                print $osm2File "    <tag k=\"type\" v=\"distance\"/>\n" ;
388                print $osm2File "    <tag k=\"distance\" v=\"", $dist{$node}, "\"/>\n" ;
389                print $osm2File "  </node>\n" ;
390        }
391}
392close ($osm2File) ;
393
394
395$time1 = time() ;
396print "\n$programName finished after ", stringTimeSpent ($time1-$time0), "\n\n" ;
397
398
399sub nodes2Coordinates {
400#
401# transform list of nodeIds to list of lons/lats
402#
403        my @nodes = @_ ;
404        my $i ;
405        my @result = () ;
406
407        #print "in @nodes\n" ;
408
409        for ($i=0; $i<=$#nodes; $i++) {
410                push @result, $lon{$nodes[$i]} ;
411                push @result, $lat{$nodes[$i]} ;
412        }
413        return @result ;
414}
415
416
417
418sub byDistance {
419   $dist{$a} eq $infinity ? +1 :
420   $dist{$b} eq $infinity ? -1 :
421       $dist{$a} <=> $dist{$b};
422}
Note: See TracBrowser for help on using the repository browser.