source: subversion/applications/utils/gary68/OSM/mapgen.pm @ 19707

Last change on this file since 19707 was 19707, checked in by gary68, 10 years ago
  • Property svn:executable set to *
File size: 17.9 KB
Line 
1#
2# PERL mapgen module by gary68
3#
4# This module contains a lot of useful graphic functions for working with osm files and data. This enables you (in conjunction with osm.pm)
5# to easily draw custom maps.
6# Have a look at the last (commented) function below. It is useful for your main program!
7#
8#
9#
10#
11# Copyright (C) 2010, Gerhard Schwanz
12#
13# 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
14# Free Software Foundation; either version 3 of the License, or (at your option) any later version.
15#
16# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License along with this program; if not, see <http://www.gnu.org/licenses/>
20
21#
22# USAGE
23#
24#
25# drawArea ($color, @nodes) - real world
26# drawAreaPix ($color, @nodes) - pixels
27# drawHead ($text, $color, $size) / size (1..5)
28# drawFoot ($text, $color, $size) / size (1..5)
29# drawNodeDot ($lon, $lat, $color, $size) / size (1..5) - real world
30# drawNodeDotPix ($lon, $lat, $color, $size) / size (1..5) - pixels
31# drawNodeCircle ($lon, $lat, $color, $size) / size (1..5) - real world
32# drawNodeCirclePix ($lon, $lat, $color, $size) / size (1..5) - pixels
33# drawRuler ($color)
34# drawTextPix ($x, $y, $text, $color, $size) / size (1..5) top left = (0,0)
35# drawTextPos ($lon, $lat, $offX, $offY, $text, $color, $size) / size (1..5)
36# drawWay ($layer, d$color, $size, $dash, @nodes) / size = thickness / real world
37# drawWayBridge ($layer, d$color, $size, $dash, @nodes) / size = thickness / real world
38# drawWayPix ($color, $size, $dash, @nodes) / size = thickness / pixels
39# initGraph ($sizeX, $left, $bottom, $right, $top) / real world coordinates, sizeX in pixels, Y automatic
40# labelWay ($col, $size, $font, $text, $tSpan, @nodes) / size can be 0..5 (or bigger...) / $tSpan = offset to line/way
41# writeSVG ($fileName)
42#
43#
44# INTERNAL
45#
46# convert ($x, $y)                                              -> ($x1, $y1) pixels in graph
47#
48# INFO
49#
50# graph top left coordinates: (0,0)
51# font size (1..5). 1 = smallest, 5 = giant
52# size for lines = pixel width / thickness
53# pass color as string, i.e. "black". list see farther down.
54#
55#
56
57package OSM::mapgen ; 
58
59use strict ;
60use warnings ;
61
62use Math::Trig;
63use File::stat;
64use Time::localtime;
65use List::Util qw[min max] ;
66use Encode ;
67
68
69use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
70
71$VERSION = '0.04' ;
72
73require Exporter ;
74
75@ISA = qw ( Exporter AutoLoader ) ;
76
77@EXPORT = qw (  drawArea
78                        drawAreaPix
79                        drawCircleRadius
80                        drawCircleRadiusText
81                        drawHead
82                        drawFoot
83                        drawLegend
84                        drawNodeDot
85                        drawNodeDotPix
86                        drawNodeCircle
87                        drawNodeCirclePix
88                        drawRuler
89                        drawTextPix
90                        drawTextPix2
91                        drawTextPos
92                        drawWay
93                        drawWayBridge
94                        drawWayPix
95                        initGraph
96                        labelWay
97                        writeSVG ) ;
98
99#
100# constants
101#
102
103my %colorHash ;
104
105@{$colorHash{"black"}} = (0, 0, 0) ;
106@{$colorHash{"darkgray"}} = (79,79,79) ;
107@{$colorHash{"gray"}} = (145, 145, 145) ;
108@{$colorHash{"lightgray"}} = (207, 207, 207) ;
109@{$colorHash{"white"}} = (255, 255, 255) ;
110
111@{$colorHash{"red"}} = (255, 0, 0) ;
112@{$colorHash{"orange"}} = (255, 165, 0) ;
113@{$colorHash{"darkorange"}} = (255, 140, 0) ;
114@{$colorHash{"tomato"}} = (255, 140, 0) ;
115@{$colorHash{"yellow"}} = (255, 255, 0) ;
116
117@{$colorHash{"blue"}} = (0, 0, 255) ;
118@{$colorHash{"lightblue"}} = (135, 206, 235) ;
119@{$colorHash{"pink"}} = (255, 105, 180) ;
120@{$colorHash{"green"}} = (0, 255, 0) ;
121@{$colorHash{"darkgreen"}} = (105, 139, 105) ;
122@{$colorHash{"lightgreen"}} = (0, 255, 127) ;
123@{$colorHash{"brown"}} = (139, 69, 19) ;
124@{$colorHash{"lightbrown"}} = (244, 164, 96) ;
125
126my %dashStyle = () ;
127$dashStyle{1} = "15,5" ;
128$dashStyle{2} = "11,5" ;
129$dashStyle{3} = "7,5" ;
130$dashStyle{4} = "3,5" ;
131$dashStyle{10} = "2,2" ;
132$dashStyle{11} = "4,4" ;
133$dashStyle{12} = "6,6" ;
134$dashStyle{13} = "8,8" ;
135$dashStyle{14} = "10,10" ;
136$dashStyle{20} = "0,2,0,4" ;
137$dashStyle{21} = "0,4,0,8" ;
138$dashStyle{22} = "0,6,0,12" ;
139$dashStyle{23} = "0,8,0,16" ;
140
141my $lineCap = "round" ;
142my $lineJoin = "round" ;
143
144#
145# variables
146#
147my $image ;
148my %color ;
149
150my ($top, $bottom, $left, $right) ; # min and max real world coordinates
151my ($sizeX, $sizeY) ; # pic size in pixels
152
153my %svgOutputWaysNodes = () ;
154my @svgOutputAreas = () ;
155my @svgOutputText = () ;
156my @svgOutputPixel = () ;
157my @svgOutputDef = () ;
158my @svgOutputPathText = () ;
159my $pathNumber = 0 ;
160my $svgBaseFontSize = 10 ;
161
162
163sub initGraph {
164#
165# function initializes the picture, the colors and the background (white)
166#
167        my ($x, $l, $b, $r, $t) = @_ ; 
168       
169        $sizeX = $x ;
170        $sizeY = $x * ($t - $b) / ($r - $l) / cos ($t/360*3.14*2) ;
171        $top = $t ;
172        $left = $l ;
173        $right = $r ;
174        $bottom = $b ;
175}
176
177sub convert {
178#
179# converts real world coordinates to system graph pixel coordinates
180#
181        my ($x, $y) = @_ ;
182
183        my ($x1) = int( ($x - $left) / ($right - $left) * $sizeX ) ;
184        my ($y1) = $sizeY - int( ($y - $bottom) / ($top - $bottom) * $sizeY ) ;
185
186        return ($x1, $y1) ;
187}
188
189sub drawHead {
190#
191# draws text on top left corner of the picture
192#
193        my ($text, $col, $size) = @_ ;
194        push @svgOutputText, svgElementText (20, 20, $text, $size, $col, "") ;
195}
196
197sub drawFoot {
198#
199# draws text on bottom left corner of the picture, below legend
200#
201        my ($text, $col, $size) = @_ ;
202        push @svgOutputText, svgElementText (20, ($sizeY-20), $text, $size, $col, "") ;
203}
204
205
206sub drawTextPos {
207#
208# draws text at given real world coordinates. however an offset can be given for not to interfere with node dot i.e.
209#
210        my ($lon, $lat, $offX, $offY, $text, $col, $size) = @_ ;
211        my ($x1, $y1) = convert ($lon, $lat) ;
212        $x1 = $x1 + $offX ;
213        $y1 = $y1 - $offY ;
214        push @svgOutputText, svgElementText ($x1, $y1, $text, $size, $col, "") ;
215}
216
217
218sub drawTextPix {
219#
220# draws text at pixel position
221#
222        my ($x1, $y1, $text, $col, $size) = @_ ;
223
224        push @svgOutputPixel, svgElementText ($x1, $y1+9, $text, $size, $col, "") ;
225}
226
227sub drawNodeDot {
228#
229# draws node as a dot at given real world coordinates
230#
231        my ($lon, $lat, $col, $size) = @_ ;
232        my ($x1, $y1) = convert ($lon, $lat) ;
233        push @{$svgOutputWaysNodes{0}}, svgElementCircleFilled ($x1, $y1, $size, $col) ;
234}
235
236sub drawNodeDotPix {
237#
238# draws node as a dot at given pixels
239#
240        my ($x1, $y1, $col, $size) = @_ ;
241        push @svgOutputPixel, svgElementCircleFilled ($x1, $y1, $size, $col) ;
242}
243
244sub drawNodeCircle {
245#
246# draws node as a circle at given real world coordinates
247#
248        my ($lon, $lat, $col, $size) = @_ ;
249        my ($x1, $y1) = convert ($lon, $lat) ;
250        push @{$svgOutputWaysNodes{0}}, svgElementCircle ($x1, $y1, $size, 2, $col) ;
251}
252
253sub drawNodeCirclePix {
254#
255# draws node as a circle at given real world coordinates
256#
257        my ($x1, $y1, $col, $size) = @_ ;
258        push @{$svgOutputWaysNodes{0}}, svgElementCircle ($x1, $y1, $size, 2, $col) ;
259}
260
261sub drawCircleRadius {
262#
263# draws circle at real world coordinates with radius in meters
264#
265        my ($lon, $lat, $radius, $size, $col) = @_ ;
266        my $radX ; my $radY ;
267        my ($x1, $y1) = convert ($lon, $lat) ;
268
269        $radX = ($radius/1000) / (($right - $left) * 111.1) / cos ($top/360*3.14*2) * $sizeX ;
270        $radY = $radX ;
271        push @{$svgOutputWaysNodes{0}}, svgElementCircle ($x1, $y1, $radX, $size, $col) ;
272}
273
274sub drawCircleRadiusText {
275#
276# draws circle at real world coordinates with radius in meters
277#
278        my ($lon, $lat, $radius, $size, $col, $text) = @_ ;
279        my $radX ; my $radY ;
280        my ($x1, $y1) = convert ($lon, $lat) ;
281
282        $radX = ($radius/1000) / (($right - $left) * 111.1) / cos ($top/360*3.14*2) * $sizeX ;
283        $radY = $radX ;
284        if ($size > 4 ) { $size = 4 ; }
285        push @{$svgOutputWaysNodes{0}}, svgElementCircle ($x1, $y1, $radX, $size, $col) ;
286        push @svgOutputText, svgElementText ($x1, $y1+$radY+10, $text, $size, $col, "") ;
287}
288
289
290sub drawWay {
291#
292# draws way as a line at given real world coordinates. nodes have to be passed as array ($lon, $lat, $lon, $lat...)
293# $size = thickness
294#
295        my ($layer, $col, $size, $dash, @nodes) = @_ ;
296        my $i ;
297        my @points = () ;
298
299        for ($i=0; $i<$#nodes; $i+=2) {
300                my ($x, $y) = convert ($nodes[$i], $nodes[$i+1]) ;
301                push @points, $x ; push @points, $y ; 
302        }
303        push @{$svgOutputWaysNodes{$layer+$size/10}}, svgElementPolyline ($col, $size, $dash, @points) ;
304}
305sub drawWayBridge {
306#
307# draws way as a line at given real world coordinates. nodes have to be passed as array ($lon, $lat, $lon, $lat...)
308# $size = thickness
309#
310        my ($layer, $col, $size, $dash, @nodes) = @_ ;
311        my $i ;
312        my @points = () ;
313
314        for ($i=0; $i<$#nodes; $i+=2) {
315                my ($x, $y) = convert ($nodes[$i], $nodes[$i+1]) ;
316                push @points, $x ; push @points, $y ; 
317        }
318        push @{$svgOutputWaysNodes{$layer+$size/10}}, svgElementPolylineBridge ($col, $size, $dash, @points) ;
319}
320
321sub drawWayPix {
322#
323# draws way as a line at given pixels. nodes have to be passed as array ($x, $y, $x, $y...)
324# $size = thickness
325#
326        my ($col, $size, $dash, @nodes) = @_ ;
327        my $i ;
328        my @points = () ;
329
330        for ($i=0; $i<$#nodes; $i+=2) {
331                my ($x, $y) = ($nodes[$i], $nodes[$i+1]) ;
332                push @points, $x ; push @points, $y ; 
333        }
334        push @svgOutputPixel, svgElementPolyline ($col, $size, $dash, @points) ;
335}
336
337
338sub labelWay {
339#
340# labels a way
341#
342        my ($col, $size, $font, $text, $tSpan, @nodes) = @_ ;
343        my $i ;
344        my @points = () ;
345
346        #print "labelWay: $col, $size, $font, $text\n" ;
347
348        for ($i=0; $i<$#nodes; $i+=2) {
349                my ($x, $y) = convert ($nodes[$i], $nodes[$i+1]) ;
350                push @points, $x ; push @points, $y ; 
351        }
352        my $pathName = "Path" . $pathNumber ; $pathNumber++ ;
353        push @svgOutputDef, svgElementPath ($pathName, @points) ;
354        push @svgOutputPathText, svgElementPathText ($col, $size, $font, $text, $pathName, $tSpan) ;
355}
356
357
358sub drawArea {
359#
360# draws an area like waterway=riverbank or landuse=forest.
361# pass color as string and nodes as list (x1, y1, x2, y2...) - real world coordinates
362#
363        my ($col, @nodes) = @_ ;
364        my $i ;
365        my @points = () ;
366       
367        for ($i=0; $i<$#nodes; $i+=2) {
368                my ($x1, $y1) = convert ($nodes[$i], $nodes[$i+1]) ;
369                push @points, $x1 ; push @points, $y1 ; 
370        }
371        push @svgOutputAreas, svgElementPolygonFilled ($col, @points) ;
372}
373
374sub drawAreaPix {
375#
376# draws an area like waterway=riverbank or landuse=forest.
377# pass color as string and nodes as list (x1, y1, x2, y2...) - pixels
378#
379        my ($col, @nodes) = @_ ;
380        my $i ;
381        my @points = () ;
382        for ($i=0; $i<$#nodes; $i+=2) {
383                my ($x1, $y1) = ($nodes[$i], $nodes[$i+1]) ;
384                push @points, $x1 ; push @points, $y1 ; 
385        }
386        push @svgOutputPixel, svgElementPolygonFilled ($col, @points) ;
387}
388
389
390
391sub drawRuler {
392#
393# draws ruler in top right corner, size is automatic
394#
395        my $col = shift ;
396
397        my $B ;
398        my $B2 ;
399        my $L ;
400        my $Lpix ;
401        my $x ;
402        my $text ;
403        my $rx = $sizeX - 20 ;
404        my $ry = 20 ;
405       
406        $B = $right - $left ;                           # in degrees
407        $B2 = $B * cos ($top/360*3.14*2) * 111.1 ;      # in km
408        $text = "100m" ; $x = 0.1 ;                     # default length ruler
409        if ($B2 > 5) {$text = "500m" ; $x = 0.5 ; }     # enlarge ruler
410        if ($B2 > 10) {$text = "1km" ; $x = 1 ; }
411        if ($B2 > 50) {$text = "5km" ; $x = 5 ; }
412        if ($B2 > 100) {$text = "10km" ; $x = 10 ; }
413        $L = $x / (cos ($top/360*3.14*2) * 111.1 ) ;    # length ruler in km
414        $Lpix = $L / $B * $sizeX ;                      # length ruler in pixels
415
416        push @svgOutputText, svgElementLine ($rx-$Lpix,$ry,$rx,$ry, $col, 1) ;
417        push @svgOutputText, svgElementLine ($rx-$Lpix,$ry,$rx-$Lpix,$ry+10, $col, 1) ;
418        push @svgOutputText, svgElementLine ($rx,$ry,$rx,$ry+10, $col, 1) ;
419        push @svgOutputText, svgElementLine ($rx-$Lpix/2,$ry,$rx-$Lpix/2,$ry+5, $col, 1) ;
420        push @svgOutputText, svgElementText ($rx-$Lpix, $ry+15, $text, 2, $col, "") ;
421}
422
423
424
425
426#####
427# SVG
428#####
429
430
431sub writeSVG {
432#
433# writes svg elemets collected so far to file
434#
435        my ($fileName) = shift ;
436        my $file ;
437        open ($file, ">", $fileName) || die "can't open svg output file";
438        print $file "<?xml version=\"1.0\" encoding=\"iso-8859-1\" standalone=\"no\"?>\n" ;
439        print $file "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\" >\n" ;
440        print $file "<svg version=\"1.1\" baseProfile=\"full\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:ev=\"http://www.w3.org/2001/xml-events\" width=\"$sizeX\" height=\"$sizeY\" >\n" ;
441        print $file "<rect width=\"$sizeX\" height=\"$sizeY\" y=\"0\" x=\"0\" fill=\"#ffffff\" />\n" ;
442
443        print $file "<defs>\n" ;
444        foreach (@svgOutputDef) { print $file $_, "\n" ; }
445        print $file "</defs>\n" ;
446
447        print $file "<g id=\"Areas\">\n" ;
448        foreach (@svgOutputAreas) { print $file $_, "\n" ; }
449        print $file "</g>\n" ;
450
451        print $file "<g id=\"WaysAndNodes\">\n" ;
452
453        foreach my $layer (sort {$a <=> $b} (keys %svgOutputWaysNodes)) {
454                foreach (@{$svgOutputWaysNodes{$layer}}) { print $file $_, "\n" ; }
455        }
456        print $file "</g>\n" ;
457
458        print $file "<g id=\"Text\">\n" ;
459        foreach (@svgOutputText) { print $file $_, "\n" ; }
460        print $file "</g>\n" ;
461
462        print $file "<g id=\"Labels\">\n" ;
463        foreach (@svgOutputPathText) { print $file $_, "\n" ; }
464        print $file "</g>\n" ;
465
466        print $file "<g id=\"Pixels\">\n" ;
467        foreach (@svgOutputPixel) { print $file $_, "\n" ; }
468        print $file "</g>\n" ;
469
470        print $file "</svg>\n" ;
471        close ($file) ;
472}
473
474sub svgElementText {
475#
476# creates string with svg element incl utf-8 encoding
477# TODO support different fonts
478#
479        my ($x, $y, $text, $size, $col, $font) = @_ ; 
480        my $fontSize = 12 + ($size - 1) * 4 ;
481        my $svg = "<text x=\"" . $x . "\" y=\"" . $y . "\" font-size=\"" . $fontSize . "\" fill=\"#" . colorToHex(@{$colorHash{$col}}) . "\">" . encode("iso-8859-1", decode("utf8", $text)) . "</text>" ;
482        return $svg ;
483}
484
485sub svgElementCircleFilled {
486#
487# draws circle not filled
488#
489        my ($x, $y, $size, $col) = @_ ;
490        my $svg = "<circle cx=\"" . $x . "\" cy=\"" . $y . "\" r=\"" . $size . "\" fill=\"#" . colorToHex(@{$colorHash{$col}})  . "\" />" ;
491        return $svg ;
492}
493
494sub svgElementCircle {
495#
496# draws filled circle / dot
497#
498        my ($x, $y, $radius, $size, $col) = @_ ;
499        my $svg = "<circle cx=\"" . $x . "\" cy=\"" . $y . "\" r=\"" . $radius . "\" fill=\"none\" stroke=\"#" . colorToHex(@{$colorHash{$col}})  . "\" stroke-width=\"2\" />" ;
500        return $svg ;
501}
502
503sub svgElementLine {
504#
505# draws line between two points
506#
507        my ($x1, $y1, $x2, $y2, $col, $size) = @_ ;
508        my $svg = "<polyline points=\"" . $x1 . "," . $y1 . " " . $x2 . "," . $y2 . "\" stroke=\"#" . colorToHex(@{$colorHash{$col}}) . "\" stroke-width=\"" . $size . "\"/>" ;
509        return $svg ;
510}
511
512
513sub svgElementPolyline {
514#
515# draws way to svg
516#
517        my ($col, $size, $dash, @points) = @_ ;
518        my $svg = "<polyline points=\"" ;
519        my $i ;
520        for ($i=0; $i<scalar(@points)-1; $i+=2) {
521                $svg = $svg . $points[$i] . "," . $points[$i+1] . " " ;
522        }
523        if ($dash == 0) { 
524                $svg = $svg . "\" stroke=\"#" . colorToHex(@{$colorHash{$col}}) . "\" stroke-width=\"" . $size . "\" stroke-linecap=\"" . $lineCap . "\" stroke-linejoin=\"" . $lineJoin . "\" fill=\"none\" />" ;
525        }
526        else {
527                $svg = $svg . "\" stroke=\"#" . colorToHex(@{$colorHash{$col}}) . "\" stroke-width=\"" . $size . "\" stroke-linecap=\"" . $lineCap . "\" stroke-linejoin=\"" . $lineJoin . "\" stroke-dasharray=\"" . $dashStyle{$dash} . "\" fill=\"none\" />" ;
528        }
529        return $svg ;
530}
531
532sub svgElementPolylineBridge {
533#
534# draws way to svg
535#
536        my ($col, $size, $dash, @points) = @_ ;
537        my $svg = "<polyline points=\"" ;
538        my $i ;
539        for ($i=0; $i<scalar(@points)-1; $i+=2) {
540                $svg = $svg . $points[$i] . "," . $points[$i+1] . " " ;
541        }
542        if ($dash == 0) { 
543                $svg = $svg . "\" stroke=\"#" . colorToHex(@{$colorHash{$col}}) . "\" stroke-width=\"" . $size . "\" fill=\"none\" />" ;
544        }
545        else {
546                $svg = $svg . "\" stroke=\"#" . colorToHex(@{$colorHash{$col}}) . "\" stroke-width=\"" . $size . "\" stroke-dasharray=\"" . $dashStyle{$dash} . "\" fill=\"none\" />" ;
547        }
548        return $svg ;
549}
550
551sub svgElementPath {
552#
553# creates path element for later use with textPath
554#
555        my ($pathName, @points) = @_ ;
556        my $svg = "<path id=\"" . $pathName . "\" d=\"M " ;
557        my $i ;
558        my $first = 1 ;
559        for ($i=0; $i<scalar(@points); $i+=2) {
560                if ($first) {
561                        $svg = $svg . $points[$i] . "," . $points[$i+1] . " " ;
562                        $first = 0 ;
563                }
564                else {
565                        $svg = $svg . "L " . $points[$i] . "," . $points[$i+1] . " " ;
566                }
567        }
568        $svg = $svg . "\" />\n" ;
569}
570
571sub svgElementPathText {
572#
573# draws text to path element
574#
575        my ($col, $size, $font, $text, $pathName, $tSpan) = @_ ;
576        my $fontSize = 12 + ($size - 1) * 4 ;
577        my $svg = "<text font-family=\"" . $font . "\" " ;
578        $svg = $svg . "font-size=\"" . $fontSize . "\" " ;
579        $svg = $svg . "fill=\"#" . colorToHex(@{$colorHash{$col}}) . "\" >\n" ;
580        $svg = $svg . "<textPath xlink:href=\"#" . $pathName . "\" text-anchor=\"middle\" startOffset=\"50%\" >\n" ;
581        $svg = $svg . "<tspan dy=\"" . $tSpan . "\" >" . encode("iso-8859-1", decode("utf8", $text)) . " </tspan>\n" ;
582        $svg = $svg . "</textPath>\n</text>\n" ;
583        return $svg ;
584}
585
586sub svgElementPolygonFilled {
587#
588# draws areas in svg, filled with color
589#
590        my ($col, @points) = @_ ;
591        my $i ;
592        my $svg = "<polygon fill=\"#" . colorToHex(@{$colorHash{$col}}) . "\" points=\"" ;
593        for ($i=0; $i<scalar(@points); $i+=2) {
594                $svg = $svg . $points[$i] . "," . $points[$i+1] . " " ;
595        }
596        $svg = $svg . "\" />" ;
597        return $svg ;
598}
599
600sub colorToHex {
601#
602# converts array of integers (rgb) to hex string without hash # (internaly used)
603#
604        my @arr = @_ ;
605        my $string = "" ; 
606        $string = sprintf "%02x", $arr[0] ;
607        $string = $string . sprintf "%02x", $arr[1] ;
608        $string = $string . sprintf "%02x", $arr[2] ;
609        return $string ;
610}
611
6121 ;
613
614#
615# copy this useful function to your main program and uncomment, if needed
616#
617# sub nodes2Coordinates {
618#
619# transform list of nodeIds to list of lons/lats
620#
621#       my @nodes = @_ ;
622#       my $i ;
623#       my @result = () ;
624#
625#       #print "in @nodes\n" ;
626#
627#       for ($i=0; $i<=$#nodes; $i++) {
628#               push @result, $lon{$nodes[$i]} ;
629#               push @result, $lat{$nodes[$i]} ;
630#       }
631#       return @result ;
632#}
633
Note: See TracBrowser for help on using the repository browser.