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

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

new mapweaver version; legend in separate file possible

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