source: subversion/applications/utils/gary68/mwMap.pm @ 26272

Last change on this file since 26272 was 26272, checked in by gary68, 8 years ago

new mapweaver version 0.12

File size: 26.9 KB
Line 
1#
2# PERL mapweaver module by gary68
3#
4#
5#
6#
7# Copyright (C) 2011, Gerhard Schwanz
8#
9# 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
10# Free Software Foundation; either version 3 of the License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License along with this program; if not, see <http://www.gnu.org/licenses/>
16#
17
18
19package mwMap ; 
20
21use strict ;
22use warnings ;
23
24use mwConfig ;
25# use mwMisc ;
26# use mwFile ;
27# use mwLabel ;
28
29use OSM::osm ;
30
31use Geo::Proj4 ;
32
33
34my $areaNum = 0 ;
35my %areaDef = () ;
36
37use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
38
39require Exporter ;
40
41@ISA = qw ( Exporter AutoLoader ) ;
42
43@EXPORT = qw (  initGraph
44                        drawCircle
45                        drawSquare
46                        drawTriangle
47                        drawDiamond
48                        drawRect
49                        drawText
50                        writeMap
51                        drawWay
52                        drawArea
53                        fitsPaper
54                        getScale
55                        createPath
56                        pathText
57                        placeIcon
58                        convert
59                        gridSquare
60                        getDimensions
61                        initOneways
62                        addOnewayArrows
63                        addAreaIcon
64                        createShield
65                        getMaxShieldSize
66                        getShieldSizes
67                        getShieldId
68                        addToLayer
69                 ) ;
70
71
72my @belowWays = ("background", "base", "area", "multi") ;
73
74my @aboveWays = ( "wayLabels", "shields", "routes", "routeStops", "nodes", "icons", "text", "additional") ;
75
76my @elements = ("scale", "ruler", "legend", "header", "footer", "rectangles", "title") ;
77
78my %svgLayer = () ;
79my %wayLayer = () ;
80
81my $shieldPathId = 0 ;
82my %createdShields = () ;
83my %shieldXSize = () ;
84my %shieldYSize = () ;
85
86my $proj ;
87
88my ($bottom, $left, $right, $top) ;
89my ($sizeX, $sizeY) ;
90my ($projLeft, $projBottom, $projRight, $projTop) ;
91my ($projSizeX, $projSizeY) ;
92
93sub initGraph {
94
95        # function initializes the picture and projection
96
97        my ($x, $l, $b, $r, $t) = @_ ; 
98
99        # my $l0 = int($l) - 1 ;
100        my $l0 = int(($r+$l) / 2 ) ;
101
102        $proj = Geo::Proj4->new(
103                proj => cv('projection'), 
104                ellps => cv('ellipsoid'), 
105                lon_0 => $l0 
106                ) or die "parameter error: ".Geo::Proj4->error. "\n"; 
107
108
109        ($projLeft, $projBottom) = $proj->forward($b, $l) ; # lat/lon!!!
110        ($projRight, $projTop) = $proj->forward($t, $r) ; # lat/lon!!!
111
112        $projSizeX = $projRight - $projLeft ;
113        $projSizeY = $projTop - $projBottom ;
114
115        my $factor = $projSizeY / $projSizeX ;
116
117        $sizeX = int ($x) ;
118        $sizeY = int ($x * $factor) ;
119
120        mwLabel::initQuadTrees ($sizeX, $sizeY) ;
121
122        $top = $t ;
123        $left = $l ;
124        $right = $r ;
125        $bottom = $b ;
126
127        if ( cv('ruler') ne "0" ) {
128                drawRuler() ;
129        }
130
131        if ( cv('scale') ne "0" ) {
132                drawScale() ;
133        }
134
135        if ( cv('grid') != 0) {
136                drawGrid() ;
137        }
138        if ( cv('coords') eq "1") {
139                drawCoords() ;
140        }
141        if ( length cv('foot') > 0 ) {
142                drawFoot() ;
143        }
144        if ( length cv('head') > 0 ) {
145                drawHead() ;
146        }
147
148}
149
150sub addToLayer {
151        my ($layer, $text) = @_ ;
152
153        if ( $layer =~ /^[\d\-\.]+$/) {
154                push @{$wayLayer{$layer}}, $text ;
155                # print "adding NUMERIC: $text\n" ;
156        }
157        else {
158                push @{$svgLayer{$layer}}, $text ;
159                # print "adding TEXTUAL: $text\n" ;
160        }
161}
162
163sub drawWay {
164
165        # accepts list of nodes (plus convert=1)  or list of x,y,x,y (convert=0) and draws way/polygon to layerNr if defined or to layerName
166
167        my ($nodesRef, $convert, $svgString, $layerName, $layerNumber) = @_ ;
168        my @points = () ;
169
170        # convert? and expand.
171        if ($convert) {
172                my ($lonRef, $latRef, $tagRef) = mwFile::getNodePointers() ;
173                foreach my $node (@$nodesRef) {
174                        my ($x, $y) = convert ( $$lonRef{$node}, $$latRef{$node}) ;
175                        push @points, $x, $y ;
176                }
177        }
178        else {
179                @points = @$nodesRef ;
180        }
181
182        my $refp = simplifyPoints (\@points) ;
183        @points = @$refp ;
184
185
186        my $svg = "<polyline points=\"" ;
187        for (my$i=0; $i<scalar(@points)-1; $i+=2) {
188                $svg = $svg . $points[$i] . "," . $points[$i+1] . " " ;
189        }
190
191        $svg = $svg . "\" $svgString />" ;
192
193        if (defined $layerNumber) {
194                push @{ $wayLayer{ $layerNumber } }, $svg ;
195        }
196        else {
197                push @{ $svgLayer { $layerName } }, $svg ;
198        }
199}
200
201
202
203sub drawText {
204
205        my ($x, $y, $convert, $text, $svgString, $layerName) = @_ ;
206
207        if ($convert) {
208                ($x, $y) = convert ($x, $y) ;
209        }
210
211        my $svg = "<text x=\"$x\" y=\"$y\" $svgString>" . $text . "</text>" ;
212
213        push @{ $svgLayer { $layerName } }, $svg ;
214
215}
216
217
218
219
220sub drawCircle {
221
222        # draws circle element to svgLayer given; if convertCoords then lon / lat is converted to x / y
223        # circleradius either in pixel or in meters (convert=1)
224
225        my ($x, $y, $convertCoords, $radius, $convertRadius, $format, $layerName) = @_ ;
226
227        if ($convertCoords) {
228                ($x, $y) = convert ($x, $y) ;
229        }
230        if ($convertRadius) {
231                $radius = $radius / (1000 * distance ($left, $bottom, $right, $bottom) ) * $sizeX ;
232        }
233        my $svg = "<circle cx=\"$x\" cy=\"$y\" r=\"$radius\" " ;
234        $svg .= $format . " />" ;
235
236        push @{ $svgLayer { $layerName } }, $svg ;
237}
238
239sub drawSquare {
240
241        # draws square element to svgLayer given; if convertCoords then lon / lat is converted to x / y
242        # square size either in pixel or in meters (convert=1)
243
244        my ($x, $y, $convertCoords, $size, $convertSize, $format, $layerName) = @_ ;
245
246        if ($convertCoords) {
247                ($x, $y) = convert ($x, $y) ;
248        }
249        if ($convertSize) {
250                $size = $size / (1000 * distance ($left, $bottom, $right, $bottom) ) * $sizeX ;
251        }
252
253        my $x1 = $x - $size ;
254        my $y1 = $y - $size ;
255        my $dSize = 2 * $size ;
256
257        my $svg = "<rect x=\"$x1\" y=\"$y1\" width=\"$dSize\" height=\"$dSize\" " ;
258        $svg .= $format . " />" ;
259
260        push @{ $svgLayer { $layerName } }, $svg ;
261}
262
263sub drawTriangle {
264
265        # draws triangle element to svgLayer given; if convertCoords then lon / lat is converted to x / y
266        # square size either in pixel or in meters (convert=1)
267
268        my ($x, $y, $convertCoords, $size, $convertSize, $format, $layerName) = @_ ;
269
270        if ($convertCoords) {
271                ($x, $y) = convert ($x, $y) ;
272        }
273        if ($convertSize) {
274                $size = $size / (1000 * distance ($left, $bottom, $right, $bottom) ) * $sizeX ;
275        }
276
277        my $h = int ( sqrt ($size * $size / 2) ) ;
278
279        my $x1 = $x ;
280        my $y1 = $y - $size ;
281        my $x2 = $x - $h ;
282        my $y2 = $y + $h ;
283        my $x3 = $x + $h ;
284        my $y3 = $y + $h ;
285
286        my $svg = "<polyline points=\"$x1,$y1 $x2,$y2 $x3,$y3 $x1,$y1\" " ;
287        $svg .= $format . " />" ;
288
289        push @{ $svgLayer { $layerName } }, $svg ;
290}
291
292sub drawDiamond {
293
294        # draws diamond element to svgLayer given; if convertCoords then lon / lat is converted to x / y
295        # square size either in pixel or in meters (convert=1)
296
297        my ($x, $y, $convertCoords, $size, $convertSize, $format, $layerName) = @_ ;
298
299        if ($convertCoords) {
300                ($x, $y) = convert ($x, $y) ;
301        }
302        if ($convertSize) {
303                $size = $size / (1000 * distance ($left, $bottom, $right, $bottom) ) * $sizeX ;
304        }
305
306        my $x1 = $x - $size ; # left
307        my $y1 = $y ;
308        my $x2 = $x ; # top
309        my $y2 = $y - $size ;
310        my $x3 = $x + $size ; #right
311        my $y3 = $y ;
312        my $x4 = $x ; # bottom
313        my $y4 = $y + $size ;
314
315        my $svg = "<polyline points=\"$x1,$y1 $x2,$y2 $x3,$y3 $x4,$y4 $x1,$y1\" " ;
316        $svg .= $format . " />" ;
317
318        push @{ $svgLayer { $layerName } }, $svg ;
319}
320
321sub drawRect {
322
323        # draws square element to svgLayer given; if convertCoords then lon / lat is converted to x / y
324        # square size either in pixel or in meters (convert=1)
325
326        my ($x1, $y1, $x2, $y2, $convertCoords, $format, $layerName) = @_ ;
327
328        if ($convertCoords) {
329                ($x1, $y1) = convert ($x1, $y1) ;
330                ($x2, $y2) = convert ($x2, $y2) ;
331        }
332
333        my $sizeX = $x2 - $x1 ;
334        my $sizeY = $y2 - $y1 ;
335
336        my $svg = "<rect x=\"$x1\" y=\"$y1\" width=\"$sizeX\" height=\"$sizeY\" " ;
337        $svg .= $format . " />" ;
338
339        push @{ $svgLayer { $layerName } }, $svg ;
340}
341
342
343sub createPath {
344#
345# creates path element for later use with textPath
346#
347        my ($pathName, $refp, $layer) = @_ ;
348
349        my $refp2 = simplifyPoints ($refp) ;
350        my @points = @$refp2 ;
351
352        my $svg = "<path id=\"" . $pathName . "\" d=\"M " ;
353        my $i ;
354        my $first = 1 ;
355        for ($i=0; $i<scalar(@points); $i+=2) {
356                if ($first) {
357                        $svg = $svg . $points[$i] . "," . $points[$i+1] . " " ;
358                        $first = 0 ;
359                }
360                else {
361                        $svg = $svg . "L " . $points[$i] . "," . $points[$i+1] . " " ;
362                }
363        }
364        $svg = $svg . "\" />\n" ;
365
366        push @{ $svgLayer{ $layer } }, $svg ;
367}
368
369
370sub pathText {
371#
372# draws text to path element; alignment: start, middle, end
373#
374        my ($svgText, $text, $pathName, $tSpan, $alignment, $offset, $layer) = @_ ;
375
376        my $svg = "<text $svgText >\n" ;
377        $svg = $svg . "<textPath xlink:href=\"#" . $pathName . "\" text-anchor=\"" . $alignment . "\" startOffset=\"" . $offset . "%\" >\n" ;
378        $svg = $svg . "<tspan dy=\"" . $tSpan . "\" >" . $text . " </tspan>\n" ;
379        $svg = $svg . "</textPath>\n</text>\n" ;
380
381        push @{ $svgLayer{ $layer } }, $svg ;
382}
383
384
385sub placeIcon {
386#
387# create SVG text for icons
388#
389        my ($x, $y, $icon, $sizeX, $sizeY, $layer) = @_ ;
390        my ($out) = "<image x=\"" . $x . "\"" ;
391        $out .= " y=\"" . $y . "\"" ;
392        if ($sizeX > 0) { $out .= " width=\"" . $sizeX . "\"" ; }
393        if ($sizeY > 0) { $out .= " height=\"" . $sizeY . "\"" ; }
394        $out .= " xlink:href=\"" . $icon . "\" />" ;
395
396        push @{ $svgLayer{ $layer } }, $out ;
397}
398
399
400sub drawArea {
401#
402# draws mp in svg ARRAY of ARRAY of nodes/coordinates
403#
404        my ($svgText, $icon, $ref, $convert, $layer) = @_ ;
405        my @ways = @$ref ;
406        my $i ;
407        my $svg ;
408
409        if ($convert) {
410                my ($lonRef, $latRef, $tagRef) = mwFile::getNodePointers () ;
411                foreach my $aRef (@ways) {
412                        my @way = @$aRef ;
413                        my @newCoords = () ;
414                        foreach my $n (@way) {
415                                my ($x, $y) = convert ($$lonRef{$n}, $$latRef{$n}) ;
416                                push @newCoords, $x, $y ;
417                        }
418                        @$aRef = @newCoords ;
419                }
420        }
421
422        if (defined $areaDef{$icon}) {
423                $svg = "<path $svgText fill-rule=\"evenodd\" style=\"fill:url(" . $areaDef{$icon} . ")\" d=\"" ;
424        }
425        else {
426                $svg = "<path $svgText fill-rule=\"evenodd\" d=\"" ;
427        }
428       
429        foreach my $way (@ways) {
430                my @actual = @$way ;
431                for ($i=0; $i<scalar(@actual); $i+=2) {
432                        if ($i == 0) { $svg .= " M " ; } else { $svg .= " L " ; }
433                        $svg = $svg . $actual[$i] . " " . $actual[$i+1] ;
434                }
435                $svg .= " z" ;
436        }
437
438        $svg = $svg . "\" />" ;
439
440        push @{ $svgLayer{ $layer } }, $svg ;
441}
442
443
444
445# ---------------------------------------------------------------------
446
447sub writeMap {
448
449        my $fileName = cv ('out')  ;
450
451        open (my $file, ">", $fileName) || die "can't open svg output file $fileName\n";
452
453        print $file "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>\n" ;
454        print $file "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\" >\n" ;
455
456        my $w = $sizeX / 300 * 2.54 ; # cm
457        my $h = $sizeY / 300 * 2.54 ;
458
459        my ($svg) = "<svg version=\"1.1\" baseProfile=\"full\" xmlns=\"http://www.w3.org/2000/svg\" " ;
460        $svg .= "xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:ev=\"http://www.w3.org/2001/xml-events\" " ;
461        $svg .= "width=\"$w" . "cm\" height=\"$h" . "cm\" viewBox=\"0 0 $sizeX $sizeY\">\n" ;
462        print $file $svg ;
463
464        # definitions
465        if ( defined @{$svgLayer{'definitions'}} ) {
466                print $file "<defs>\n" ;
467                foreach ( @{$svgLayer{'definitions'}} ) { print $file $_, "\n" ; }
468                print $file "</defs>\n" ;
469        }
470
471        # below ways
472        foreach my $layer (@belowWays) {
473                if ( defined @{$svgLayer{$layer}} ) {
474                        print $file "<g id=\"$layer\">\n" ;
475                        foreach ( @{$svgLayer{$layer}} ) { print $file $_, "\n" ; }
476                        print $file "</g>\n" ;
477                }
478        }
479
480        # ways
481        foreach my $layer (sort {$a <=> $b} keys %wayLayer) {
482                if ( defined @{$wayLayer{$layer}} ) {
483                        print $file "<g id=\"way$layer\">\n" ;
484                        foreach ( @{$wayLayer{$layer}} ) { print $file $_, "\n" ; }
485                        print $file "</g>\n" ;
486                }
487        }
488
489
490        # above of ways
491        foreach my $layer (@aboveWays) {
492                if ( defined @{$svgLayer{$layer}} ) {
493                        print $file "<g id=\"$layer\">\n" ;
494                        foreach ( @{$svgLayer{$layer}} ) { print $file $_, "\n" ; }
495                        print $file "</g>\n" ;
496                }
497        }
498
499
500        # TODO use groups
501
502        foreach my $layer (@elements) {
503                if (defined @{$svgLayer{$layer}}) {
504                        print $file "<g id=\"$layer\">\n" ;
505                        foreach ( @{$svgLayer{$layer}} ) { print $file $_, "\n" ; }
506                        print $file "</g>\n" ;
507                }
508        }
509
510
511        print $file "</svg>\n" ;
512
513        close ($file) ;
514
515        if (cv('pdf') eq "1") {
516                my ($pdfName) = $fileName ;
517                $pdfName =~ s/\.svg/\.pdf/ ;
518                print "creating pdf file $pdfName ...\n" ;
519                `inkscape -A $pdfName $fileName` ;
520        }
521
522        if (cv('png') eq "1") {
523                my ($pngName) = $fileName ;
524                $pngName =~ s/\.svg/\.png/ ;
525                print "creating png file $pngName ...\n" ;
526                `inkscape --export-dpi=300 -e $pngName $fileName` ;
527        }
528
529
530
531}
532
533# -----------------------------------------------------------------------------------
534
535sub drawGrid {
536#
537# draw grid on top of map. receives number of parts in x/lon direction
538#
539
540        my $number = cv ('grid') ;
541        my $color = cv ('gridcolor') ;
542
543        my $part = $sizeX / $number ;
544        my $numY = $sizeY / $part ;
545
546        my $svgStringLine="stroke=\"$color\" stroke-width=\"5\" stroke-dasharray=\"30,30\"" ;
547
548        my $svgStringText="font-family=\"sans-serif\" font-size=\"60\" fill=\"$color\"" ;
549
550        # vertical lines
551        for (my $i = 1; $i <= $number; $i++) {
552                my @coords = ($i*$part, 0, $i*$part, $sizeY) ;
553                drawWay (\@coords, 0, $svgStringLine, "additional", undef) ;
554                drawText ( ($i-1)*$part+$part/2, 160, 0, chr($i+64), $svgStringText, "additional") ;
555
556        }
557
558        # hor. lines
559        for (my $i = 1; $i <= $numY; $i++) {
560                my @coords = (0, $i*$part, $sizeX, $i*$part) ;
561                drawWay (\@coords, 0, $svgStringLine, "additional", undef) ;
562                drawText ( 20, ($i-1)*$part+$part/2, 0, $i, $svgStringText, "additional") ;
563
564        }
565}
566
567sub drawCoords {
568#
569# draws coordinates grid on map
570#
571        my $exp = cv('coordsexp') ; 
572        my $color = cv ('coordscolor');
573        my $step = 10 ** $exp ;
574
575        # vert. lines
576        my $start = int ($left / $step) + 1 ;
577        my $actual = $start * $step ;
578
579        my $svgStringLine="stroke=\"$color\" stroke-width=\"3\"" ;
580        my $svgStringText="font-family=\"sans-serif\" font-size=\"30\" fill=\"$color\"" ;
581
582        while ($actual < $right) {
583                my ($x1, $y1) = convert ($actual, 0) ;
584
585                drawText ( $x1+10, $sizeY-50, 0, $actual, $svgStringText, "additional") ;
586
587                my @coords = ($x1, 0, $x1, $sizeY) ;
588                drawWay (\@coords, 0, $svgStringLine, "additional", undef) ;
589
590                $actual += $step ;
591        }
592
593        # hor lines
594        $start = int ($bottom / $step) + 1 ;
595        $actual = $start * $step ;
596        while ($actual < $top) {
597                # print "actualY: $actual\n" ;
598                my ($x1, $y1) = convert (0, $actual) ;
599
600                drawText ( $sizeX-180, $y1+30, 0, $actual, $svgStringText, "additional") ;
601
602                my @coords = (0, $y1, $sizeX, $y1) ;
603                drawWay (\@coords, 0, $svgStringLine, "additional", undef) ;
604
605                $actual += $step ;
606        }
607}
608
609
610
611
612# -----------------------------------------------------------------------------------
613
614sub convert {
615
616        # converts real world coordinates to system graph pixel coordinates
617
618        my ($x, $y) = @_ ;
619
620        my ($x1, $y1) = $proj->forward($y, $x) ; # lat/lon!!!
621
622        my $x2 = int ( ($x1 - $projLeft) / ($projRight - $projLeft) * $sizeX ) ;
623        my $y2 = $sizeY - int ( ($y1 - $projBottom) / ($projTop - $projBottom) * $sizeY ) ;
624
625        return ($x2, $y2) ;
626}
627
628sub simplifyPoints {
629        my $ref = shift ;
630        my @points = @$ref ;
631        my @newPoints ;
632        my $maxIndex = $#points ;
633
634        if (scalar @points > 4) {
635                # push first
636                push @newPoints, $points[0], $points[1] ;
637
638                # push other
639                for (my $i=2; $i <= $maxIndex; $i+=2) {
640                        # $simplifyTotal++ ;
641                        if ( ($points[$i]==$points[$i-2]) and ($points[$i+1]==$points[$i-1]) ) {
642                                # same
643                                # $simplified++ ;
644                        }
645                        else {
646                                push @newPoints, $points[$i], $points[$i+1] ;
647                        }
648                }
649                return (\@newPoints) ;
650        }
651        else {
652                return ($ref) ;
653        }
654
655}
656
657sub drawRuler {
658#
659# draws ruler
660#
661        my $col = cv('rulercolor') ;   
662
663        my $B ; my $B2 ;
664        my $L ; my $Lpix ;
665        my $x ;
666        my $text ;
667
668        my $lineThickness = 8 ; # at 300dpi
669        my $textSize = 40 ; # at 300 dpi
670        my $textDist = 60 ; # at 300 dpi
671        my $lineLen = 40 ; # at 300 dpi
672
673        my $xOffset = 2 * $lineThickness ;
674        my $yOffset = 2 * $lineThickness ;
675               
676        $B = $right - $left ;                           # in degrees
677        $B2 = $B * cos ($top/360*3.14*2) * 111.1 ;      # in km
678        $text = "50m" ; $x = 0.05 ;                     # default length ruler
679
680        if ($B2 > 0.5) {$text = "100 m" ; $x = 0.1 ; }  # enlarge ruler
681        if ($B2 > 1) {$text = "500 m" ; $x = 0.5 ; }    # enlarge ruler
682        if ($B2 > 5) {$text = "1 km" ; $x = 1 ; }
683        if ($B2 > 10) {$text = "5 km" ; $x = 5 ; }
684        if ($B2 > 50) {$text = "10 km" ; $x = 10 ; }
685        $L = $x / (cos ($top/360*3.14*2) * 111.1 ) ;    # length ruler in km
686        $Lpix = $L / $B * $sizeX ;                      # length ruler in pixels
687
688        my $rSizeX = int ($Lpix + 2 * $xOffset) ;
689        my $rSizeY = int ($lineLen + $textSize + 3 * $yOffset) ;
690        addToLayer ("definitions", "<g id=\"rulerdef\" width=\"$rSizeX\" height=\"$rSizeY\" >") ;
691
692        if ( cv('rulerbackground') ne "none" ) {
693                my $color = cv ('rulerbackground') ;
694                my $svgString = "fill=\"$color\"" ;
695                drawRect (0, 0, $rSizeX, $rSizeY, 0, $svgString, "definitions") ;
696        }
697
698        my $svgString = "stroke=\"$col\" stroke-width=\"$lineThickness\" stroke-linecap=\"round\" " ;
699
700        my @coords = ($xOffset, $yOffset, $xOffset+$Lpix, $yOffset) ;
701        drawWay (\@coords, 0, $svgString, "definitions", undef) ;
702
703        @coords = ($xOffset, $yOffset, $xOffset, $yOffset+$lineLen) ;
704        drawWay (\@coords, 0, $svgString, "definitions", undef) ;
705
706        @coords = ($xOffset+$Lpix, $yOffset, $xOffset+$Lpix, $yOffset+$lineLen) ;
707        drawWay (\@coords, 0, $svgString, "definitions", undef) ;
708
709        @coords = ($xOffset+$Lpix/2, $yOffset, $xOffset+$Lpix/2, $yOffset+$lineLen/2) ;
710        drawWay (\@coords, 0, $svgString, "definitions", undef) ;
711
712        $svgString = "fill=\"$col\" stroke=\"$col\" font-size=\"45\" " ;
713        my $scale= getScale() ;
714        $text .= "(1:$scale)" ;
715        drawText ($xOffset, $yOffset+$textDist+30, 0, $text, $svgString, "definitions") ;
716
717        addToLayer ("definitions", "</g>") ;
718
719        my $posX = 40 ; my $posY = 40 ;
720
721        if ( cv('ruler') eq "2") {
722                $posX = $sizeX - 40 - $rSizeX ;
723                $posY = 40 ;
724        }
725
726        if ( cv('ruler') eq "3") {
727                $posX = 40 ;
728                $posY = $sizeY - 40 - $rSizeY ;
729        }
730
731        if ( cv('ruler') eq "4") {
732                $posX = $sizeX - 40 - $rSizeX ;
733                $posY = $sizeY - 40 - $rSizeY ;
734        }
735
736        addToLayer ("ruler", "<use x=\"$posX\" y=\"$posY\" xlink:href=\"#rulerdef\" />") ;
737}
738
739sub drawScale {
740#
741# draws scale value
742#
743        my $col = cv('scalecolor') ;   
744
745        my $xOffset = 20 ;
746        my $yOffset = 20 ;
747        my $fontSize = 70 ;             
748        my $borderDist = 60 ;
749
750        my $rSizeX = int (350 + 2 * $xOffset) ;
751        my $rSizeY = int ($fontSize + 2 * $yOffset) ;
752        addToLayer ("definitions", "<g id=\"scaledef\" width=\"$rSizeX\" height=\"$rSizeY\" >") ;
753
754        if ( cv('scalebackground') ne "none" ) {
755                my $color = cv ('scalebackground') ;
756                my $svgString = "fill=\"$color\"" ;
757                drawRect (0, 0, $rSizeX, $rSizeY, 0, $svgString, "definitions") ;
758        }
759
760        my $scale= getScale() ;
761        my $svgString = "fill=\"$col\" stroke=\"$col\" font-size=\"$fontSize\" " ;
762        drawText ($xOffset, $fontSize + $yOffset, 0, "1:$scale", $svgString, "definitions") ;
763
764        addToLayer ("definitions", "</g>") ;
765
766        my $posX = $borderDist ; my $posY = $borderDist ;
767
768        if ( cv('scale') eq "2") {
769                $posX = $sizeX - $borderDist - $rSizeX ;
770                $posY = $borderDist ;
771        }
772
773        if ( cv('scale') eq "3") {
774                $posX = $borderDist ;
775                $posY = $sizeY - $borderDist - $rSizeY ;
776        }
777
778        if ( cv('scale') eq "4") {
779                $posX = $sizeX - $borderDist - $rSizeX ;
780                $posY = $sizeY - $borderDist - $rSizeY ;
781        }
782
783        addToLayer ("scale", "<use x=\"$posX\" y=\"$posY\" xlink:href=\"#scaledef\" />") ;
784}
785
786sub drawFoot {
787#
788# draws footer
789#
790        my $col = cv('footcolor') ;     
791        my $text = cv('foot') ; 
792        my $len = length $text ;
793
794        my $xOffset = 20 ;
795        my $yOffset = 20 ;
796        my $fontSize = cv('footsize') ;         
797        my $borderDistX = 60 ;
798        my $borderDistY = $fontSize + 50 ;
799
800        my $rSizeX = int ($len*cv('ppc')/10*$fontSize + 2 * $xOffset) ;
801        my $rSizeY = int ($fontSize + 2 * $yOffset) ;
802        addToLayer ("definitions", "<g id=\"footdef\" width=\"$rSizeX\" height=\"$rSizeY\" >") ;
803
804        if ( cv('footbackground') ne "none" ) {
805                my $color = cv ('footbackground') ;
806                my $svgString = "fill=\"$color\"" ;
807                drawRect (0, 0, $rSizeX, $rSizeY, 0, $svgString, "definitions") ;
808        }
809
810        my $svgString = "fill=\"$col\" stroke=\"$col\" font-size=\"$fontSize\" " ;
811        drawText ($xOffset, $fontSize + $yOffset, 0, $text, $svgString, "definitions") ;
812
813        addToLayer ("definitions", "</g>") ;
814
815        my $posX = $borderDistX ; my $posY = $sizeY - $borderDistY ;
816
817        addToLayer ("footer", "<use x=\"$posX\" y=\"$posY\" xlink:href=\"#footdef\" />") ;
818}
819
820sub drawHead {
821#
822# draws header
823#
824        my $col = cv('headcolor') ;     
825        my $text = cv('head') ; 
826        my $len = length $text ;
827
828        my $xOffset = 20 ;
829        my $yOffset = 20 ;
830        my $fontSize = cv('headsize') ;         
831        my $borderDistX = 60 ;
832        my $borderDistY = 60 ;
833
834        my $rSizeX = int ($len*cv('ppc')/10*$fontSize + 2 * $xOffset) ;
835        my $rSizeY = int ($fontSize + 2 * $yOffset) ;
836        addToLayer ("definitions", "<g id=\"headdef\" width=\"$rSizeX\" height=\"$rSizeY\" >") ;
837
838        if ( cv('headbackground') ne "none" ) {
839                my $color = cv ('headbackground') ;
840                my $svgString = "fill=\"$color\"" ;
841                drawRect (0, 0, $rSizeX, $rSizeY, 0, $svgString, "definitions") ;
842        }
843
844        my $svgString = "fill=\"$col\" stroke=\"$col\" font-size=\"$fontSize\" " ;
845        drawText ($xOffset, $fontSize + $yOffset, 0, $text, $svgString, "definitions") ;
846
847        addToLayer ("definitions", "</g>") ;
848
849        my $posX = $borderDistX ; my $posY = $borderDistY ;
850
851        addToLayer ("header", "<use x=\"$posX\" y=\"$posY\" xlink:href=\"#headdef\" />") ;
852}
853
854
855sub fitsPaper {
856#
857# calculates on what paper size the map will fit. sizes are taken from global variables
858#
859
860        my $width = $sizeX / 300 * 2.54 ;
861        my $height = $sizeY / 300 * 2.54 ;
862        my $paper = "" ;
863
864        my @sizes = () ;
865        push @sizes, ["4A0", 168.2, 237.8] ;
866        push @sizes, ["2A0", 118.9, 168.2] ;
867        push @sizes, ["A0", 84.1, 118.9] ;
868        push @sizes, ["A1", 59.4, 84.1] ;
869        push @sizes, ["A2", 42, 59.4] ;
870        push @sizes, ["A3", 29.7, 42] ;
871        push @sizes, ["A4", 21, 29.7] ;
872        push @sizes, ["A5", 14.8, 21] ;
873        push @sizes, ["A6", 10.5, 14.8] ;
874        push @sizes, ["A7", 7.4, 10.5] ;
875        push @sizes, ["none", 0, 0] ;
876
877        foreach my $size (@sizes) {
878                if ( ( ($width<=$size->[1]) and ($height<=$size->[2]) ) or ( ($width<=$size->[2]) and ($height<=$size->[1]) ) ) {
879                        $paper = $size->[0] ;
880                }
881        }
882
883        return ($paper, $width, $height) ;
884}
885
886sub getScale {
887#
888# calcs scale of map
889#
890        my ($dpi) = 300 ;
891
892        my $dist = distance ($left, $bottom, $right, $bottom) ;
893        my $inches = $sizeX / $dpi ;
894        my $cm = $inches * 2.54 ;
895        my $scale = int ( $dist / ($cm/100/1000)  ) ;
896        $scale = int ($scale / 100) * 100 ;
897
898        return ($scale) ;
899}
900
901sub gridSquare {
902#
903# returns grid square of given coordinates for directories
904#
905        my ($lon, $lat) = @_ ;
906
907        my $parts = cv('grid') ;
908
909        my ($x, $y) = convert ($lon, $lat) ;
910        my $xi = int ($x / ($sizeX / $parts)) + 1 ;
911        my $yi = int ($y / ($sizeX / $parts)) + 1 ;
912        if ( ($x >= 0) and ($x <= $sizeX) and ($y >= 0) and ($y <= $sizeY) ) {
913                return (chr($xi+64) . $yi) ;
914        }
915        else {
916                return undef ;
917        }
918}
919
920
921sub getDimensions {
922        return ($sizeX, $sizeY) ;
923}
924
925# ----------------------------------------------------------------------
926
927sub initOneways {
928#
929# write marker defs to svg
930#
931        my $color = cv('onewaycolor') ;
932        my $markerSize = cv('onewaysize') ;
933
934        my @svgOutputDef = () ;
935        push @svgOutputDef, "<marker id=\"Arrow1\"" ;
936        push @svgOutputDef, "viewBox=\"0 0 10 10\" refX=\"5\" refY=\"5\"" ;
937        push @svgOutputDef, "markerUnits=\"strokeWidth\"" ;
938        push @svgOutputDef, "markerWidth=\"" . $markerSize . "\" markerHeight=\"" . $markerSize . "\"" ;
939        push @svgOutputDef, "orient=\"auto\">" ;
940        push @svgOutputDef, "<path d=\"M 0 4 L 6 4 L 6 2 L 10 5 L 6 8 L 6 6 L 0 6 Z\" fill=\"" . $color .  "\" />" ;
941        push @svgOutputDef, "</marker>" ;
942
943        foreach my $line (@svgOutputDef) {
944                addToLayer ("definitions", $line) ;
945        }
946}
947
948sub addOnewayArrows {
949#
950# adds oneway arrows to new pathes
951#
952        my ($wayNodesRef, $direction, $thickness, $layer) = @_ ;
953        my @wayNodes = @$wayNodesRef ;
954        my $minDist = cv('onewaysize') * 1.5 ;
955        my ($lonRef, $latRef) = mwFile::getNodePointers() ;
956
957        if ($direction == -1) { @wayNodes = reverse @wayNodes ; }
958
959        # create new pathes with new nodes
960        for (my $i=0; $i<scalar(@wayNodes)-1;$i++) {
961                my ($x1, $y1) = convert ($$lonRef{$wayNodes[$i]}, $$latRef{$wayNodes[$i]}) ;
962                my ($x2, $y2) = convert ($$lonRef{$wayNodes[$i+1]}, $$latRef{$wayNodes[$i+1]}) ;
963                my $xn = ($x2+$x1) / 2 ;
964                my $yn = ($y2+$y1) / 2 ;
965                if (sqrt (($x2-$x1)**2+($y2-$y1)**2) > $minDist) {
966                        # create path
967                        # use path
968                        my $svg = "<path d=\"M $x1 $y1 L $xn $yn L $x2 $y2\" fill=\"none\" marker-mid=\"url(#Arrow1)\" />" ;
969                       
970                        addToLayer ($layer+$thickness/100, $svg) ;
971                }
972        }
973}
974
975# ----------------------------------------------------------------------------
976
977sub addAreaIcon {
978#
979# initial collection of area icons
980#
981        my $fileNameOriginal = shift ;
982        # print "AREA: $fileNameOriginal\n" ;
983        my $result = open (my $file, "<", $fileNameOriginal) ;
984        close ($file) ;
985        if ($result) {
986                my ($x, $y) ;
987                if (grep /.svg/, $fileNameOriginal) {
988                        ($x, $y) = mwMisc::sizeSVG ($fileNameOriginal) ;
989                        if ( ($x == 0) or ($y == 0) ) { 
990                                $x = 32 ; $y = 32 ; 
991                                print "WARNING: size of file $fileNameOriginal could not be determined. Set to 32px x 32px\n" ;
992                        } 
993                }
994
995                if (grep /.png/, $fileNameOriginal) {
996                        ($x, $y) = mwMisc::sizePNG ($fileNameOriginal) ;
997                }
998
999                if (!defined $areaDef{$fileNameOriginal}) {
1000
1001                        my $x1 = $x ; # scale area icons
1002                        my $y1 = $y ;
1003                        my $fx = $x1 / $x ;
1004                        my $fy = $y1 / $y ;
1005                       
1006                        # add defs to svg output
1007                        my $defName = "A" . $areaNum ;
1008                        # print "INFO area icon $fileNameOriginal, $defName, $x, $y --- $x1, $y1 --- $fx, $fy --- processed.\n" ;
1009                        $areaNum++ ;
1010
1011                        my $svgElement = "<pattern id=\"" . $defName . "\" width=\"" . $x . "\" height=\"" . $y . "\" " ;
1012                        $svgElement .= "patternTransform=\"translate(0,0) scale(" . $fx . "," . $fy . ")\" \n" ;
1013                        $svgElement .= "patternUnits=\"userSpaceOnUse\">\n" ;
1014                        $svgElement .= "  <image xlink:href=\"" . $fileNameOriginal . "\"/>\n" ;
1015                        $svgElement .= "</pattern>\n" ;
1016
1017                        addToLayer ("definitions", $svgElement) ;
1018
1019                        $defName = "#" . $defName ;
1020                        $areaDef{$fileNameOriginal} = $defName ;
1021                }
1022        }
1023        else {
1024                print "WARNING: area icon $fileNameOriginal not found!\n" ;
1025        }
1026}
1027
1028# ----------------------------------------------------------------------------
1029
1030sub createShield {
1031        my ($name, $targetSize) = @_ ;
1032        my @a = split /:/, $name ;
1033        my $shieldFileName = $a[1] ;
1034        my $shieldText = $a[2] ;
1035
1036        if (! defined $createdShields{$name}) {
1037                open (my $file, "<", $shieldFileName) or die ("ERROR: shield definition $shieldFileName not found.\n") ;
1038                my @defText = <$file> ;
1039                close ($file) ;
1040
1041                # get size
1042                # calc scaling
1043                my $sizeX = 0 ;
1044                my $sizeY = 0 ;
1045                foreach my $line (@defText) {
1046                        if (grep /<svg/, $line) {
1047                                ($sizeY) = ( $line =~ /height=\"(\d+)px\"/ ) ;
1048                                ($sizeX) = ( $line =~ /width=\"(\d+)px\"/ ) ;
1049                                if ( (!defined $sizeX) or (!defined $sizeY) ) {
1050                                        die "ERROR: size of shield in $shieldFileName could not be determined.\n" ;
1051                                }
1052                        }
1053                }
1054                if ( ($sizeX == 0) or ($sizeY == 0) ) {
1055                        die "ERROR: initial size of shield $shieldFileName could not be determined.\n" ;
1056                }
1057
1058                my $scaleFactor = $targetSize / $sizeY ;
1059
1060                $shieldXSize{ $name } = int ($sizeX * $scaleFactor) ;
1061                $shieldYSize{ $name } = int ($sizeY * $scaleFactor) ;
1062
1063                $shieldPathId++ ;
1064                my $shieldPathName = "ShieldPath" . $shieldPathId ;
1065                my $shieldGroupName = "ShieldGroup" . $shieldPathId ;
1066
1067                foreach my $line (@defText) {
1068                        $line =~ s/REPLACEID/$shieldGroupName/ ;
1069                        $line =~ s/REPLACESCALE/$scaleFactor/g ;
1070                        $line =~ s/REPLACEPATH/$shieldPathName/ ;
1071                        $line =~ s/REPLACELABEL/$shieldText/ ;
1072                }
1073
1074                foreach my $line (@defText) {
1075                        addToLayer ("definitions", $line) ;
1076                }
1077
1078                $createdShields{$name} = $shieldGroupName ;
1079        }
1080}
1081
1082sub getMaxShieldSize {
1083        my $name = shift ;
1084        my $max = $shieldXSize{$name} ;
1085        if ( $shieldYSize{$name} > $max) { $max = $shieldYSize{$name} ; }
1086        return $max ;
1087}
1088
1089sub getShieldSizes {
1090        my $name = shift ;
1091        my $x = $shieldXSize{$name} ;
1092        my $y = $shieldYSize{$name} ;
1093        return $x, $y ;
1094}
1095
1096sub getShieldId {
1097        my $name = shift ;
1098        return $createdShields{$name} ;
1099}
1100
11011 ;
1102
1103
Note: See TracBrowser for help on using the repository browser.