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

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

new mapgen version

  • Property svn:executable set to *
File size: 22.2 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# center (lon, lat, lon, lat)
26# createLabel ($refTagArray, $styleLabelText)
27# drawArea ($color, @nodes) - real world
28# drawAreaPix ($color, @nodes) - pixels
29# drawGrid ($parts)
30# drawHead ($text, $color, $size) / size (1..5)
31# drawFoot ($text, $color, $size) / size (1..5)
32# drawNodeDot ($lon, $lat, $color, $size) / size (1..5) - real world
33# drawNodeDotPix ($lon, $lat, $color, $size) / size (1..5) - pixels
34# drawNodeCircle ($lon, $lat, $color, $size) / size (1..5) - real world
35# drawNodeCirclePix ($lon, $lat, $color, $size) / size (1..5) - pixels
36# drawRuler ($color)
37# drawTextPix ($x, $y, $text, $color, $size) / size (1..5) top left = (0,0)
38# drawTextPos ($lon, $lat, $offX, $offY, $text, $color, $size) / size (1..5)
39# drawWay ($layer, d$color, $size, $dash, @nodes) / size = thickness / real world
40# drawWayBridge ($layer, d$color, $size, $dash, @nodes) / size = thickness / real world
41# drawWayPix ($color, $size, $dash, @nodes) / size = thickness / pixels
42# gridSquare ($lon, $lat) / returns grid square for directory
43# initGraph ($sizeX, $left, $bottom, $right, $top) / real world coordinates, sizeX in pixels, Y automatic
44# labelWay ($col, $size, $font, $text, $tSpan, @nodes) / size can be 0..5 (or bigger...) / $tSpan = offset to line/way
45# printScale ($dpi, $color)
46# writeSVG ($fileName)
47#
48#
49# INTERNAL
50#
51# convert ($x, $y)                                              -> ($x1, $y1) pixels in graph
52#
53# INFO
54#
55# graph top left coordinates: (0,0)
56# size for lines = pixel width / thickness
57# pass color as string, i.e. "black". list see farther down.
58#
59#
60
61package OSM::mapgen ; 
62
63use strict ;
64use warnings ;
65
66use Math::Trig;
67use File::stat;
68use Time::localtime;
69use List::Util qw[min max] ;
70use Encode ;
71use OSM::osm ;
72
73use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
74
75$VERSION = '0.07' ;
76
77require Exporter ;
78
79@ISA = qw ( Exporter AutoLoader ) ;
80
81@EXPORT = qw (  center
82                        createLabel
83                        drawArea
84                        drawAreaPix
85                        drawCircleRadius
86                        drawCircleRadiusText
87                        drawHead
88                        drawFoot
89                        drawGrid
90                        drawLegend
91                        drawNodeDot
92                        drawNodeDotPix
93                        drawNodeCircle
94                        drawNodeCirclePix
95                        drawRuler
96                        drawTextPix
97                        drawTextPix2
98                        drawTextPos
99                        drawWay
100                        drawWayBridge
101                        drawWayPix
102                        gridSquare
103                        initGraph
104                        labelWay
105                        printScale
106                        writeSVG ) ;
107
108#
109# constants
110#
111
112my %colorHash ;
113
114@{$colorHash{"black"}} = (0, 0, 0) ;
115@{$colorHash{"darkgray"}} = (79,79,79) ;
116@{$colorHash{"gray"}} = (145, 145, 145) ;
117@{$colorHash{"lightgray"}} = (207, 207, 207) ;
118@{$colorHash{"white"}} = (255, 255, 255) ;
119
120@{$colorHash{"red"}} = (255, 0, 0) ;
121@{$colorHash{"orange"}} = (255, 165, 0) ;
122@{$colorHash{"darkorange"}} = (255, 140, 0) ;
123@{$colorHash{"tomato"}} = (255, 140, 0) ;
124@{$colorHash{"yellow"}} = (255, 255, 0) ;
125
126@{$colorHash{"blue"}} = (0, 0, 255) ;
127@{$colorHash{"lightblue"}} = (135, 206, 235) ;
128@{$colorHash{"pink"}} = (255, 105, 180) ;
129@{$colorHash{"green"}} = (0, 255, 0) ;
130@{$colorHash{"darkgreen"}} = (105, 139, 105) ;
131@{$colorHash{"lightgreen"}} = (0, 255, 127) ;
132@{$colorHash{"brown"}} = (139, 69, 19) ;
133@{$colorHash{"lightbrown"}} = (244, 164, 96) ;
134
135my %dashStyle = () ;
136$dashStyle{1} = "15,5" ;
137$dashStyle{2} = "11,5" ;
138$dashStyle{3} = "7,5" ;
139$dashStyle{4} = "3,5" ;
140$dashStyle{10} = "2,2" ;
141$dashStyle{11} = "4,4" ;
142$dashStyle{12} = "6,6" ;
143$dashStyle{13} = "8,8" ;
144$dashStyle{14} = "10,10" ;
145$dashStyle{20} = "0,2,0,4" ;
146$dashStyle{21} = "0,4,0,8" ;
147$dashStyle{22} = "0,6,0,12" ;
148$dashStyle{23} = "0,8,0,16" ;
149
150my $lineCap = "round" ;
151my $lineJoin = "round" ;
152
153#
154# variables
155#
156my $image ;
157my %color ;
158
159my ($top, $bottom, $left, $right) ; # min and max real world coordinates
160my ($sizeX, $sizeY) ; # pic size in pixels
161
162my %svgOutputWaysNodes = () ;
163my @svgOutputAreas = () ;
164my @svgOutputText = () ;
165my @svgOutputPixel = () ;
166my @svgOutputPixelGrid = () ;
167my @svgOutputDef = () ;
168my @svgOutputPathText = () ;
169my $pathNumber = 0 ;
170my $svgBaseFontSize = 10 ;
171
172my %clutter = () ;
173
174sub initGraph {
175#
176# function initializes the picture, the colors and the background (white)
177#
178        my ($x, $l, $b, $r, $t, $color) = @_ ; 
179       
180        $sizeX = $x ;
181        $sizeY = $x * ($t - $b) / ($r - $l) / cos ($t/360*3.14*2) ;
182        $top = $t ;
183        $left = $l ;
184        $right = $r ;
185        $bottom = $b ;
186
187        drawArea ($color, $l, $t, $r, $t, $r, $b, $l, $b, $l, $t) ;
188}
189
190sub convert {
191#
192# converts real world coordinates to system graph pixel coordinates
193#
194        my ($x, $y) = @_ ;
195
196        my ($x1) = int( ($x - $left) / ($right - $left) * $sizeX ) ;
197        my ($y1) = int ($sizeY - int( ($y - $bottom) / ($top - $bottom) * $sizeY ) ) ;
198
199        return ($x1, $y1) ;
200}
201
202sub gridSquare {
203        my ($lon, $lat, $parts) = @_ ;
204        my ($x, $y) = convert ($lon, $lat) ;
205        # my $partsY = $sizeY / ($sizeX / $parts) ;
206        my $xi = int ($x / ($sizeX / $parts)) + 1 ;
207        my $yi = int ($y / ($sizeX / $parts)) + 1 ;
208        return (chr($xi+64) . $yi) ;
209}
210
211sub drawHead {
212#
213# draws text on top left corner of the picture
214#
215        my ($text, $col, $size, $font) = @_ ;
216        push @svgOutputText, svgElementText (20, 20, $text, $size, $font, $col) ;
217}
218
219sub drawFoot {
220#
221# draws text on bottom left corner of the picture, below legend
222#
223        my ($text, $col, $size, $font) = @_ ;
224        push @svgOutputText, svgElementText (20, ($sizeY-20), $text, $size, $font, $col) ;
225}
226
227
228sub drawTextPos {
229#
230# draws text at given real world coordinates. however an offset can be given for not to interfere with node dot i.e.
231#
232        my ($lon, $lat, $offX, $offY, $text, $col, $size, $font, $declutter, $declutterMinX, $declutterMinY) = @_ ;
233        my ($x1, $y1) = convert ($lon, $lat) ;
234        $x1 = $x1 + $offX ;
235        $y1 = $y1 - $offY ;
236
237        my $cluttered = 0 ;
238        if ($declutter eq "1") {
239                foreach my $clutterX (keys %clutter) {
240                        foreach my $clutterY (keys %{$clutter{$clutterX}}) {
241                                my $distY = abs ($clutterY - $y1) ;
242                                if ($distY > $declutterMinY) {
243                                        # dist ok
244                                }
245                                else {
246                                        my $distX = abs ($clutterX - $x1) ;
247                                        if ($distX < $declutterMinX) { 
248                                                $cluttered = 1 ; 
249                                        }
250                                }
251                        }
252                }
253        }
254
255        if (!$cluttered) {
256                push @svgOutputText, svgElementText ($x1, $y1, $text, $size, $font, $col) ;
257                $clutter{$x1}{$y1} = $text ;
258        }
259        else {
260                print "WARNING: label \"$text\" omitted to prevent clutter!\n" ;
261        }
262}
263
264
265sub drawTextPix {
266#
267# draws text at pixel position
268#
269        my ($x1, $y1, $text, $col, $size, $font) = @_ ;
270
271        push @svgOutputPixel, svgElementText ($x1, $y1+9, $text, $size, $font, $col) ;
272}
273
274sub drawTextPixGrid {
275#
276# draws text at pixel position
277#
278        my ($x1, $y1, $text, $col, $size) = @_ ;
279
280        push @svgOutputPixelGrid, svgElementText ($x1, $y1+9, $text, $size, "sans-serif", $col) ;
281}
282
283sub drawNodeDot {
284#
285# draws node as a dot at given real world coordinates
286#
287        my ($lon, $lat, $col, $size) = @_ ;
288        my ($x1, $y1) = convert ($lon, $lat) ;
289        push @{$svgOutputWaysNodes{0}}, svgElementCircleFilled ($x1, $y1, $size, $col) ;
290}
291
292sub drawNodeDotPix {
293#
294# draws node as a dot at given pixels
295#
296        my ($x1, $y1, $col, $size) = @_ ;
297        push @svgOutputPixel, svgElementCircleFilled ($x1, $y1, $size, $col) ;
298}
299
300sub drawNodeCircle {
301#
302# draws node as a circle at given real world coordinates
303#
304        my ($lon, $lat, $col, $size) = @_ ;
305        my ($x1, $y1) = convert ($lon, $lat) ;
306        push @{$svgOutputWaysNodes{0}}, svgElementCircle ($x1, $y1, $size, 2, $col) ;
307}
308
309sub drawNodeCirclePix {
310#
311# draws node as a circle at given real world coordinates
312#
313        my ($x1, $y1, $col, $size) = @_ ;
314        push @{$svgOutputWaysNodes{0}}, svgElementCircle ($x1, $y1, $size, 2, $col) ;
315}
316
317sub drawCircleRadius {
318#
319# draws circle at real world coordinates with radius in meters
320#
321        my ($lon, $lat, $radius, $size, $col) = @_ ;
322        my $radX ; my $radY ;
323        my ($x1, $y1) = convert ($lon, $lat) ;
324
325        $radX = ($radius/1000) / (($right - $left) * 111.1) / cos ($top/360*3.14*2) * $sizeX ;
326        $radY = $radX ;
327        push @{$svgOutputWaysNodes{0}}, svgElementCircle ($x1, $y1, $radX, $size, $col) ;
328}
329
330sub drawCircleRadiusText {
331#
332# draws circle at real world coordinates with radius in meters
333#
334        my ($lon, $lat, $radius, $size, $font, $col, $text) = @_ ;
335        my $radX ; my $radY ;
336        my ($x1, $y1) = convert ($lon, $lat) ;
337
338        $radX = ($radius/1000) / (($right - $left) * 111.1) / cos ($top/360*3.14*2) * $sizeX ;
339        $radY = $radX ;
340        if ($size > 4 ) { $size = 4 ; }
341        push @{$svgOutputWaysNodes{0}}, svgElementCircle ($x1, $y1, $radX, $size, $col) ;
342        push @svgOutputText, svgElementText ($x1, $y1+$radY+10, $text, $size, $font, $col) ;
343}
344
345
346sub drawWay {
347#
348# draws way as a line at given real world coordinates. nodes have to be passed as array ($lon, $lat, $lon, $lat...)
349# $size = thickness
350#
351        my ($layer, $col, $size, $dash, @nodes) = @_ ;
352        my $i ;
353        my @points = () ;
354
355        for ($i=0; $i<$#nodes; $i+=2) {
356                my ($x, $y) = convert ($nodes[$i], $nodes[$i+1]) ;
357                push @points, $x ; push @points, $y ; 
358        }
359        push @{$svgOutputWaysNodes{$layer+$size/10}}, svgElementPolyline ($col, $size, $dash, @points) ;
360}
361sub drawWayBridge {
362#
363# draws way as a line at given real world coordinates. nodes have to be passed as array ($lon, $lat, $lon, $lat...)
364# $size = thickness
365#
366        my ($layer, $col, $size, $dash, @nodes) = @_ ;
367        my $i ;
368        my @points = () ;
369
370        for ($i=0; $i<$#nodes; $i+=2) {
371                my ($x, $y) = convert ($nodes[$i], $nodes[$i+1]) ;
372                push @points, $x ; push @points, $y ; 
373        }
374        push @{$svgOutputWaysNodes{$layer+$size/10}}, svgElementPolylineBridge ($col, $size, $dash, @points) ;
375}
376
377sub drawWayPix {
378#
379# draws way as a line at given pixels. nodes have to be passed as array ($x, $y, $x, $y...)
380# $size = thickness
381#
382        my ($col, $size, $dash, @nodes) = @_ ;
383        my $i ;
384        my @points = () ;
385
386        for ($i=0; $i<$#nodes; $i+=2) {
387                my ($x, $y) = ($nodes[$i], $nodes[$i+1]) ;
388                push @points, $x ; push @points, $y ; 
389        }
390        push @svgOutputPixel, svgElementPolyline ($col, $size, $dash, @points) ;
391}
392
393sub drawWayPixGrid {
394#
395# draws way as a line at given pixels. nodes have to be passed as array ($x, $y, $x, $y...)
396# $size = thickness
397#
398        my ($col, $size, $dash, @nodes) = @_ ;
399        my $i ;
400        my @points = () ;
401
402        for ($i=0; $i<$#nodes; $i+=2) {
403                my ($x, $y) = ($nodes[$i], $nodes[$i+1]) ;
404                push @points, $x ; push @points, $y ; 
405        }
406        push @svgOutputPixelGrid, svgElementPolyline ($col, $size, $dash, @points) ;
407}
408
409
410sub labelWay {
411#
412# labels a way
413#
414        my ($col, $size, $font, $text, $tSpan, @nodes) = @_ ;
415        my $i ;
416        my @points = () ;
417
418        #print "labelWay: $col, $size, $font, $text\n" ;
419
420        for ($i=0; $i<$#nodes; $i+=2) {
421                my ($x, $y) = convert ($nodes[$i], $nodes[$i+1]) ;
422                push @points, $x ; push @points, $y ; 
423        }
424        my $pathName = "Path" . $pathNumber ; $pathNumber++ ;
425        push @svgOutputDef, svgElementPath ($pathName, @points) ;
426        push @svgOutputPathText, svgElementPathText ($col, $size, $font, $text, $pathName, $tSpan) ;
427}
428
429
430sub drawArea {
431#
432# draws an area like waterway=riverbank or landuse=forest.
433# pass color as string and nodes as list (x1, y1, x2, y2...) - real world coordinates
434#
435        my ($col, @nodes) = @_ ;
436        my $i ;
437        my @points = () ;
438       
439        for ($i=0; $i<$#nodes; $i+=2) {
440                my ($x1, $y1) = convert ($nodes[$i], $nodes[$i+1]) ;
441                push @points, $x1 ; push @points, $y1 ; 
442        }
443        push @svgOutputAreas, svgElementPolygonFilled ($col, @points) ;
444}
445
446sub drawAreaPix {
447#
448# draws an area like waterway=riverbank or landuse=forest.
449# pass color as string and nodes as list (x1, y1, x2, y2...) - pixels
450#
451        my ($col, @nodes) = @_ ;
452        my $i ;
453        my @points = () ;
454        for ($i=0; $i<$#nodes; $i+=2) {
455                my ($x1, $y1) = ($nodes[$i], $nodes[$i+1]) ;
456                push @points, $x1 ; push @points, $y1 ; 
457        }
458        push @svgOutputPixel, svgElementPolygonFilled ($col, @points) ;
459}
460
461
462
463sub drawRuler {
464#
465# draws ruler in top right corner, size is automatic
466#
467        my $col = shift ;
468
469        my $B ;
470        my $B2 ;
471        my $L ;
472        my $Lpix ;
473        my $x ;
474        my $text ;
475        my $rx = $sizeX - 20 ;
476        my $ry = 20 ;
477       
478        $B = $right - $left ;                           # in degrees
479        $B2 = $B * cos ($top/360*3.14*2) * 111.1 ;      # in km
480        $text = "100m" ; $x = 0.1 ;                     # default length ruler
481        if ($B2 > 5) {$text = "500m" ; $x = 0.5 ; }     # enlarge ruler
482        if ($B2 > 10) {$text = "1km" ; $x = 1 ; }
483        if ($B2 > 50) {$text = "5km" ; $x = 5 ; }
484        if ($B2 > 100) {$text = "10km" ; $x = 10 ; }
485        $L = $x / (cos ($top/360*3.14*2) * 111.1 ) ;    # length ruler in km
486        $Lpix = $L / $B * $sizeX ;                      # length ruler in pixels
487
488        push @svgOutputText, svgElementLine ($rx-$Lpix,$ry,$rx,$ry, $col, 1) ;
489        push @svgOutputText, svgElementLine ($rx-$Lpix,$ry,$rx-$Lpix,$ry+10, $col, 1) ;
490        push @svgOutputText, svgElementLine ($rx,$ry,$rx,$ry+10, $col, 1) ;
491        push @svgOutputText, svgElementLine ($rx-$Lpix/2,$ry,$rx-$Lpix/2,$ry+5, $col, 1) ;
492        push @svgOutputText, svgElementText ($rx-$Lpix, $ry+15, $text, 10, "sans-serif", $col) ;
493}
494
495sub drawGrid {
496        my ($number, $color) = @_ ;
497        my $part = $sizeX / $number ;
498        my $numY = $sizeY / $part ;
499        # vertical lines
500        for (my $i = 1; $i <= $number; $i++) {
501                drawWayPixGrid ($color, 1, 1, $i*$part, 0, $i*$part, $sizeY) ;
502                drawTextPixGrid (($i-1)*$part+$part/2, 20, chr($i+64), $color, 20) ;
503        }
504        # hor. lines
505        for (my $i = 1; $i <= $numY; $i++) {
506                drawWayPixGrid ($color, 1, 1, 0, $i*$part, $sizeX, $i*$part) ;
507                drawTextPixGrid (20, ($i-1)*$part+$part/2, $i, $color, 20) ;
508        }
509}
510
511
512
513#####
514# SVG
515#####
516
517
518sub writeSVG {
519#
520# writes svg elemets collected so far to file
521#
522        my ($fileName) = shift ;
523        my $file ;
524        open ($file, ">", $fileName) || die "can't open svg output file";
525        print $file "<?xml version=\"1.0\" encoding=\"iso-8859-1\" standalone=\"no\"?>\n" ;
526        print $file "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\" >\n" ;
527        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" ;
528        print $file "<rect width=\"$sizeX\" height=\"$sizeY\" y=\"0\" x=\"0\" fill=\"#ffffff\" />\n" ;
529
530        print $file "<defs>\n" ;
531        foreach (@svgOutputDef) { print $file $_, "\n" ; }
532        print $file "</defs>\n" ;
533
534        print $file "<g id=\"Areas\">\n" ;
535        foreach (@svgOutputAreas) { print $file $_, "\n" ; }
536        print $file "</g>\n" ;
537
538        print $file "<g id=\"WaysAndNodes\">\n" ;
539
540        foreach my $layer (sort {$a <=> $b} (keys %svgOutputWaysNodes)) {
541                foreach (@{$svgOutputWaysNodes{$layer}}) { print $file $_, "\n" ; }
542        }
543        print $file "</g>\n" ;
544
545        print $file "<g id=\"Text\">\n" ;
546        foreach (@svgOutputText) { print $file $_, "\n" ; }
547        print $file "</g>\n" ;
548
549        print $file "<g id=\"Labels\">\n" ;
550        foreach (@svgOutputPathText) { print $file $_, "\n" ; }
551        print $file "</g>\n" ;
552
553        print $file "<g id=\"Grid\">\n" ;
554        foreach (@svgOutputPixelGrid) { print $file $_, "\n" ; }
555        print $file "</g>\n" ;
556
557        print $file "<g id=\"Pixels\">\n" ;
558        foreach (@svgOutputPixel) { print $file $_, "\n" ; }
559        print $file "</g>\n" ;
560
561        print $file "</svg>\n" ;
562        close ($file) ;
563}
564
565sub svgElementText {
566#
567# creates string with svg element incl utf-8 encoding
568#
569        my ($x, $y, $text, $size, $font, $col) = @_ ; 
570        my $svg = "<text x=\"" . $x . "\" y=\"" . $y . 
571                "\" font-size=\"" . $size . 
572                "\" font-family=\"" . $font . 
573                "\" fill=\"#" . colorToHex(@{$colorHash{$col}}) . 
574                "\">" . encode("iso-8859-1", decode("utf8", $text)) . "</text>" ;
575        return $svg ;
576}
577
578sub svgElementCircleFilled {
579#
580# draws circle not filled
581#
582        my ($x, $y, $size, $col) = @_ ;
583        my $svg = "<circle cx=\"" . $x . "\" cy=\"" . $y . "\" r=\"" . $size . "\" fill=\"#" . colorToHex(@{$colorHash{$col}})  . "\" />" ;
584        return $svg ;
585}
586
587sub svgElementCircle {
588#
589# draws filled circle / dot
590#
591        my ($x, $y, $radius, $size, $col) = @_ ;
592        my $svg = "<circle cx=\"" . $x . "\" cy=\"" . $y . "\" r=\"" . $radius . "\" fill=\"none\" stroke=\"#" . colorToHex(@{$colorHash{$col}})  . "\" stroke-width=\"2\" />" ;
593        return $svg ;
594}
595
596sub svgElementLine {
597#
598# draws line between two points
599#
600        my ($x1, $y1, $x2, $y2, $col, $size) = @_ ;
601        my $svg = "<polyline points=\"" . $x1 . "," . $y1 . " " . $x2 . "," . $y2 . "\" stroke=\"#" . colorToHex(@{$colorHash{$col}}) . "\" stroke-width=\"" . $size . "\"/>" ;
602        return $svg ;
603}
604
605
606sub svgElementPolyline {
607#
608# draws way to svg
609#
610        my ($col, $size, $dash, @points) = @_ ;
611        my $svg = "<polyline points=\"" ;
612        my $i ;
613        for ($i=0; $i<scalar(@points)-1; $i+=2) {
614                $svg = $svg . $points[$i] . "," . $points[$i+1] . " " ;
615        }
616        if ($dash == 0) { 
617                $svg = $svg . "\" stroke=\"#" . colorToHex(@{$colorHash{$col}}) . "\" stroke-width=\"" . $size . "\" stroke-linecap=\"" . $lineCap . "\" stroke-linejoin=\"" . $lineJoin . "\" fill=\"none\" />" ;
618        }
619        else {
620                $svg = $svg . "\" stroke=\"#" . colorToHex(@{$colorHash{$col}}) . "\" stroke-width=\"" . $size . "\" stroke-linecap=\"" . $lineCap . "\" stroke-linejoin=\"" . $lineJoin . "\" stroke-dasharray=\"" . $dashStyle{$dash} . "\" fill=\"none\" />" ;
621        }
622        return $svg ;
623}
624
625sub svgElementPolylineBridge {
626#
627# draws way to svg
628#
629        my ($col, $size, $dash, @points) = @_ ;
630        my $svg = "<polyline points=\"" ;
631        my $i ;
632        for ($i=0; $i<scalar(@points)-1; $i+=2) {
633                $svg = $svg . $points[$i] . "," . $points[$i+1] . " " ;
634        }
635        if ($dash == 0) { 
636                $svg = $svg . "\" stroke=\"#" . colorToHex(@{$colorHash{$col}}) . "\" stroke-width=\"" . $size . "\" fill=\"none\" />" ;
637        }
638        else {
639                $svg = $svg . "\" stroke=\"#" . colorToHex(@{$colorHash{$col}}) . "\" stroke-width=\"" . $size . "\" stroke-dasharray=\"" . $dashStyle{$dash} . "\" fill=\"none\" />" ;
640        }
641        return $svg ;
642}
643
644sub svgElementPath {
645#
646# creates path element for later use with textPath
647#
648        my ($pathName, @points) = @_ ;
649        my $svg = "<path id=\"" . $pathName . "\" d=\"M " ;
650        my $i ;
651        my $first = 1 ;
652        for ($i=0; $i<scalar(@points); $i+=2) {
653                if ($first) {
654                        $svg = $svg . $points[$i] . "," . $points[$i+1] . " " ;
655                        $first = 0 ;
656                }
657                else {
658                        $svg = $svg . "L " . $points[$i] . "," . $points[$i+1] . " " ;
659                }
660        }
661        $svg = $svg . "\" />\n" ;
662}
663
664sub svgElementPathText {
665#
666# draws text to path element
667#
668        my ($col, $size, $font, $text, $pathName, $tSpan) = @_ ;
669        my $svg = "<text font-family=\"" . $font . "\" " ;
670        $svg = $svg . "font-size=\"" . $size . "\" " ;
671        $svg = $svg . "fill=\"#" . colorToHex(@{$colorHash{$col}}) . "\" >\n" ;
672        $svg = $svg . "<textPath xlink:href=\"#" . $pathName . "\" text-anchor=\"middle\" startOffset=\"50%\" >\n" ;
673        $svg = $svg . "<tspan dy=\"" . $tSpan . "\" >" . encode("iso-8859-1", decode("utf8", $text)) . " </tspan>\n" ;
674        $svg = $svg . "</textPath>\n</text>\n" ;
675        return $svg ;
676}
677
678sub svgElementPolygonFilled {
679#
680# draws areas in svg, filled with color
681#
682        my ($col, @points) = @_ ;
683        my $i ;
684        my $svg = "<polygon fill-rule=\"evenodd\" fill=\"#" . colorToHex(@{$colorHash{$col}}) . "\" points=\"" ;
685        for ($i=0; $i<scalar(@points); $i+=2) {
686                $svg = $svg . $points[$i] . "," . $points[$i+1] . " " ;
687        }
688        $svg = $svg . "\" />" ;
689        return $svg ;
690}
691
692sub colorToHex {
693#
694# converts array of integers (rgb) to hex string without hash # (internaly used)
695#
696        my @arr = @_ ;
697        my $string = "" ; 
698        $string = sprintf "%02x", $arr[0] ;
699        $string = $string . sprintf "%02x", $arr[1] ;
700        $string = $string . sprintf "%02x", $arr[2] ;
701        return $string ;
702}
703
704sub createLabel {
705#
706# takes @tags and labelKey(s) from style file and creates labelTextTotal and array of labels for directory
707# takes more keys in string.
708# § all listed keys will be searched for and values be concatenated
709# # first of found keys will be used to select value
710# "name§ref" will return all values if given
711# "name#ref" will return name, if given. if no name is given, ref will be used. none given, no text
712#
713        my ($ref1, $styleLabelText) = @_ ;
714        my @tags = @$ref1 ;
715        my @keys ;
716        my @labels = () ;
717        my $labelTextTotal = "" ; 
718
719        if (grep /§/, $styleLabelText) { # AND
720                @keys = split ( /§/, $styleLabelText) ;
721                for (my $i=0; $i<=$#keys; $i++) {
722                        foreach my $tag (@tags) {
723                                if ($tag->[0] eq $keys[$i]) {
724                                        push @labels, $tag->[1] ;
725                                }
726                        }
727                }
728                $labelTextTotal = "" ;
729                foreach my $label (@labels) { $labelTextTotal .= $label . " " ; }
730        }
731        else { # PRIO
732                @keys = split ( /#/, $styleLabelText) ;
733                my $i = 0 ; my $found = 0 ;
734                while ( ($i<=$#keys) and ($found == 0) ) {
735                        foreach my $tag (@tags) {
736                                if ($tag->[0] eq $keys[$i]) {
737                                        push @labels, $tag->[1] ;
738                                        $labelTextTotal = $tag->[1] ;
739                                        $found = 1 ;
740                                }
741                        }
742                        $i++ ;
743                }               
744        }
745        return ( $labelTextTotal, \@labels) ;
746}
747
748sub center {
749        my @nodes = @_ ;
750        my $x = 0 ;
751        my $y = 0 ;
752        my $num = 0 ;
753
754        while (scalar @nodes > 0) { 
755                my $y1 = pop @nodes ;
756                my $x1 = pop @nodes ;
757                $x += $x1 ;
758                $y += $y1 ;
759                $num++ ;
760        }
761        $x = $x / $num ;
762        $y = $y / $num ;
763        return ($x, $y) ;
764}
765
766sub printScale {
767        my ($dpi, $color) = @_ ;
768
769        my $dist = distance ($left, $bottom, $right, $bottom) ;
770        # print "distance = $dist\n" ;
771        my $inches = $sizeX / $dpi ;
772        # print "inches = $inches\n" ;
773        my $cm = $inches * 2.54 ;
774        # print "cm = $cm\n" ;
775        my $scale = int ( $dist / ($cm/100/1000)  ) ;
776        $scale = int ($scale / 100) * 100 ;
777
778        my $text = "1 : $scale ($dpi dpi)" ;
779       
780        drawTextPix ($sizeX-200, 50, $text, $color, 14, "sans-serif") ;
781        # print "scale = $text\n\n" ;
782}
783
784
7851 ;
786
787#
788# copy this useful function to your main program and uncomment, if needed
789#
790# sub nodes2Coordinates {
791#
792# transform list of nodeIds to list of lons/lats
793#
794#       my @nodes = @_ ;
795#       my $i ;
796#       my @result = () ;
797#
798#       #print "in @nodes\n" ;
799#
800#       for ($i=0; $i<=$#nodes; $i++) {
801#               push @result, $lon{$nodes[$i]} ;
802#               push @result, $lat{$nodes[$i]} ;
803#       }
804#       return @result ;
805#}
806
Note: See TracBrowser for help on using the repository browser.