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

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

mapweaver: small svg bux fixed

File size: 29.3 KB
RevLine 
[26136]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 ;
[26271]25# use mwMisc ;
[26136]26# use mwFile ;
[26159]27# use mwLabel ;
[26136]28
29use OSM::osm ;
30
31use Geo::Proj4 ;
32
33
[26271]34my $areaNum = 0 ;
35my %areaDef = () ;
36
[26136]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
[26259]49                        drawText
[26136]50                        writeMap
51                        drawWay
[26164]52                        drawArea
[26136]53                        fitsPaper
54                        getScale
55                        createPath
56                        pathText
57                        placeIcon
[26159]58                        convert
[26191]59                        gridSquare
[26199]60                        getDimensions
[26201]61                        initOneways
62                        addOnewayArrows
[26271]63                        addAreaIcon
[26272]64                        createShield
65                        getMaxShieldSize
66                        getShieldSizes
67                        getShieldId
68                        addToLayer
[26412]69                        createLegendFile
[26136]70                 ) ;
71
72
73my @belowWays = ("background", "base", "area", "multi") ;
74
[26427]75my @aboveWays = ( "arealabels", "wayLabels", "shields", "routes", "routeStops", "nodes", "icons", "text", "additional") ;
[26136]76
[26445]77my @elements = ("scale", "ruler", "legend", "wns", "header", "footer", "rectangles", "title") ;
[26136]78
79my %svgLayer = () ;
80my %wayLayer = () ;
81
[26272]82my $shieldPathId = 0 ;
83my %createdShields = () ;
84my %shieldXSize = () ;
85my %shieldYSize = () ;
86
[26136]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
[26159]121        mwLabel::initQuadTrees ($sizeX, $sizeY) ;
[26136]122
123        $top = $t ;
124        $left = $l ;
125        $right = $r ;
126        $bottom = $b ;
127
[26356]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
[26136]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        }
[26191]154
[26136]155}
156
157sub addToLayer {
158        my ($layer, $text) = @_ ;
[26201]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        }
[26136]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#
[26159]354        my ($pathName, $refp, $layer) = @_ ;
[26136]355
[26159]356        my $refp2 = simplifyPoints ($refp) ;
357        my @points = @$refp2 ;
[26136]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#
[26191]381        my ($svgText, $text, $pathName, $tSpan, $alignment, $offset, $layer) = @_ ;
[26136]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
[26164]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 ;
[26356]414        my $svg = "" ;
[26431]415        my @newArray = () ;
[26136]416
[26431]417        # TODO loop converts original data !!!
418
[26164]419        if ($convert) {
420                my ($lonRef, $latRef, $tagRef) = mwFile::getNodePointers () ;
421                foreach my $aRef (@ways) {
422                        my @way = @$aRef ;
423                        my @newCoords = () ;
424                        foreach my $n (@way) {
425                                my ($x, $y) = convert ($$lonRef{$n}, $$latRef{$n}) ;
426                                push @newCoords, $x, $y ;
427                        }
[26431]428                        push @newArray , [@newCoords] ;
[26164]429                }
[26431]430                @ways = @newArray ;
[26164]431        }
[26136]432
[26164]433        if (defined $areaDef{$icon}) {
434                $svg = "<path $svgText fill-rule=\"evenodd\" style=\"fill:url(" . $areaDef{$icon} . ")\" d=\"" ;
435        }
436        else {
437                $svg = "<path $svgText fill-rule=\"evenodd\" d=\"" ;
438        }
439       
440        foreach my $way (@ways) {
441                my @actual = @$way ;
442                for ($i=0; $i<scalar(@actual); $i+=2) {
443                        if ($i == 0) { $svg .= " M " ; } else { $svg .= " L " ; }
444                        $svg = $svg . $actual[$i] . " " . $actual[$i+1] ;
445                }
446                $svg .= " z" ;
447        }
448
449        $svg = $svg . "\" />" ;
450
451        push @{ $svgLayer{ $layer } }, $svg ;
452}
453
454
455
[26136]456# ---------------------------------------------------------------------
457
458sub writeMap {
459
460        my $fileName = cv ('out')  ;
461
462        open (my $file, ">", $fileName) || die "can't open svg output file $fileName\n";
463
464        print $file "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>\n" ;
465        print $file "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\" >\n" ;
466
467        my $w = $sizeX / 300 * 2.54 ; # cm
468        my $h = $sizeY / 300 * 2.54 ;
469
470        my ($svg) = "<svg version=\"1.1\" baseProfile=\"full\" xmlns=\"http://www.w3.org/2000/svg\" " ;
471        $svg .= "xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:ev=\"http://www.w3.org/2001/xml-events\" " ;
472        $svg .= "width=\"$w" . "cm\" height=\"$h" . "cm\" viewBox=\"0 0 $sizeX $sizeY\">\n" ;
473        print $file $svg ;
474
475        # definitions
476        if ( defined @{$svgLayer{'definitions'}} ) {
477                print $file "<defs>\n" ;
478                foreach ( @{$svgLayer{'definitions'}} ) { print $file $_, "\n" ; }
479                print $file "</defs>\n" ;
480        }
481
482        # below ways
483        foreach my $layer (@belowWays) {
484                if ( defined @{$svgLayer{$layer}} ) {
485                        print $file "<g id=\"$layer\">\n" ;
486                        foreach ( @{$svgLayer{$layer}} ) { print $file $_, "\n" ; }
487                        print $file "</g>\n" ;
488                }
489        }
490
491        # ways
492        foreach my $layer (sort {$a <=> $b} keys %wayLayer) {
493                if ( defined @{$wayLayer{$layer}} ) {
494                        print $file "<g id=\"way$layer\">\n" ;
495                        foreach ( @{$wayLayer{$layer}} ) { print $file $_, "\n" ; }
496                        print $file "</g>\n" ;
497                }
498        }
499
500
501        # above of ways
502        foreach my $layer (@aboveWays) {
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        foreach my $layer (@elements) {
512                if (defined @{$svgLayer{$layer}}) {
513                        print $file "<g id=\"$layer\">\n" ;
514                        foreach ( @{$svgLayer{$layer}} ) { print $file $_, "\n" ; }
515                        print $file "</g>\n" ;
516                }
517        }
518
519
520        print $file "</svg>\n" ;
521
522        close ($file) ;
523
524        if (cv('pdf') eq "1") {
525                my ($pdfName) = $fileName ;
526                $pdfName =~ s/\.svg/\.pdf/ ;
527                print "creating pdf file $pdfName ...\n" ;
528                `inkscape -A $pdfName $fileName` ;
529        }
530
531        if (cv('png') eq "1") {
532                my ($pngName) = $fileName ;
533                $pngName =~ s/\.svg/\.png/ ;
[26356]534                my $dpi = cv('pngdpi') ;
535                print "creating png file $pngName ($dpi dpi)...\n" ;
536                `inkscape --export-dpi=$dpi -e $pngName $fileName` ;
[26136]537        }
538
539
540
541}
542
543# -----------------------------------------------------------------------------------
544
545sub drawGrid {
546#
547# draw grid on top of map. receives number of parts in x/lon direction
548#
549
550        my $number = cv ('grid') ;
551        my $color = cv ('gridcolor') ;
552
553        my $part = $sizeX / $number ;
554        my $numY = $sizeY / $part ;
555
556        my $svgStringLine="stroke=\"$color\" stroke-width=\"5\" stroke-dasharray=\"30,30\"" ;
557
[26507]558        my $svgStringText = mwMisc::createTextSVG ( cv('elementFontFamily'), cv('elementFont'), undef, undef, 60, $color, undef, undef) ;
[26136]559
560        # vertical lines
561        for (my $i = 1; $i <= $number; $i++) {
562                my @coords = ($i*$part, 0, $i*$part, $sizeY) ;
563                drawWay (\@coords, 0, $svgStringLine, "additional", undef) ;
564                drawText ( ($i-1)*$part+$part/2, 160, 0, chr($i+64), $svgStringText, "additional") ;
565
566        }
567
568        # hor. lines
569        for (my $i = 1; $i <= $numY; $i++) {
570                my @coords = (0, $i*$part, $sizeX, $i*$part) ;
571                drawWay (\@coords, 0, $svgStringLine, "additional", undef) ;
572                drawText ( 20, ($i-1)*$part+$part/2, 0, $i, $svgStringText, "additional") ;
573
574        }
575}
576
577sub drawCoords {
578#
579# draws coordinates grid on map
580#
581        my $exp = cv('coordsexp') ; 
582        my $color = cv ('coordscolor');
583        my $step = 10 ** $exp ;
584
585        # vert. lines
586        my $start = int ($left / $step) + 1 ;
587        my $actual = $start * $step ;
588
589        my $svgStringLine="stroke=\"$color\" stroke-width=\"3\"" ;
[26507]590        my $svgStringText = mwMisc::createTextSVG ( cv('elementFontFamily'), cv('elementFont'), undef, undef, 30, $color, undef, undef) ;
[26136]591
592        while ($actual < $right) {
593                my ($x1, $y1) = convert ($actual, 0) ;
594
595                drawText ( $x1+10, $sizeY-50, 0, $actual, $svgStringText, "additional") ;
596
597                my @coords = ($x1, 0, $x1, $sizeY) ;
598                drawWay (\@coords, 0, $svgStringLine, "additional", undef) ;
599
600                $actual += $step ;
601        }
602
603        # hor lines
604        $start = int ($bottom / $step) + 1 ;
605        $actual = $start * $step ;
606        while ($actual < $top) {
607                # print "actualY: $actual\n" ;
608                my ($x1, $y1) = convert (0, $actual) ;
609
610                drawText ( $sizeX-180, $y1+30, 0, $actual, $svgStringText, "additional") ;
611
612                my @coords = (0, $y1, $sizeX, $y1) ;
613                drawWay (\@coords, 0, $svgStringLine, "additional", undef) ;
614
615                $actual += $step ;
616        }
617}
618
619
620
621
622# -----------------------------------------------------------------------------------
623
624sub convert {
625
626        # converts real world coordinates to system graph pixel coordinates
627
628        my ($x, $y) = @_ ;
629
630        my ($x1, $y1) = $proj->forward($y, $x) ; # lat/lon!!!
631
632        my $x2 = int ( ($x1 - $projLeft) / ($projRight - $projLeft) * $sizeX ) ;
633        my $y2 = $sizeY - int ( ($y1 - $projBottom) / ($projTop - $projBottom) * $sizeY ) ;
634
635        return ($x2, $y2) ;
636}
637
638sub simplifyPoints {
639        my $ref = shift ;
640        my @points = @$ref ;
641        my @newPoints ;
642        my $maxIndex = $#points ;
643
644        if (scalar @points > 4) {
645                # push first
646                push @newPoints, $points[0], $points[1] ;
647
648                # push other
649                for (my $i=2; $i <= $maxIndex; $i+=2) {
650                        # $simplifyTotal++ ;
651                        if ( ($points[$i]==$points[$i-2]) and ($points[$i+1]==$points[$i-1]) ) {
652                                # same
653                                # $simplified++ ;
654                        }
655                        else {
656                                push @newPoints, $points[$i], $points[$i+1] ;
657                        }
658                }
659                return (\@newPoints) ;
660        }
661        else {
662                return ($ref) ;
663        }
664
665}
666
667sub drawRuler {
668#
669# draws ruler
670#
671        my $col = cv('rulercolor') ;   
672
673        my $B ; my $B2 ;
674        my $L ; my $Lpix ;
675        my $x ;
676        my $text ;
677
678        my $lineThickness = 8 ; # at 300dpi
679        my $textSize = 40 ; # at 300 dpi
680        my $textDist = 60 ; # at 300 dpi
681        my $lineLen = 40 ; # at 300 dpi
682
683        my $xOffset = 2 * $lineThickness ;
684        my $yOffset = 2 * $lineThickness ;
685               
686        $B = $right - $left ;                           # in degrees
687        $B2 = $B * cos ($top/360*3.14*2) * 111.1 ;      # in km
688        $text = "50m" ; $x = 0.05 ;                     # default length ruler
689
690        if ($B2 > 0.5) {$text = "100 m" ; $x = 0.1 ; }  # enlarge ruler
691        if ($B2 > 1) {$text = "500 m" ; $x = 0.5 ; }    # enlarge ruler
692        if ($B2 > 5) {$text = "1 km" ; $x = 1 ; }
693        if ($B2 > 10) {$text = "5 km" ; $x = 5 ; }
694        if ($B2 > 50) {$text = "10 km" ; $x = 10 ; }
695        $L = $x / (cos ($top/360*3.14*2) * 111.1 ) ;    # length ruler in km
696        $Lpix = $L / $B * $sizeX ;                      # length ruler in pixels
697
698        my $rSizeX = int ($Lpix + 2 * $xOffset) ;
699        my $rSizeY = int ($lineLen + $textSize + 3 * $yOffset) ;
700        addToLayer ("definitions", "<g id=\"rulerdef\" width=\"$rSizeX\" height=\"$rSizeY\" >") ;
701
702        if ( cv('rulerbackground') ne "none" ) {
703                my $color = cv ('rulerbackground') ;
704                my $svgString = "fill=\"$color\"" ;
705                drawRect (0, 0, $rSizeX, $rSizeY, 0, $svgString, "definitions") ;
706        }
707
708        my $svgString = "stroke=\"$col\" stroke-width=\"$lineThickness\" stroke-linecap=\"round\" " ;
709
710        my @coords = ($xOffset, $yOffset, $xOffset+$Lpix, $yOffset) ;
711        drawWay (\@coords, 0, $svgString, "definitions", undef) ;
712
713        @coords = ($xOffset, $yOffset, $xOffset, $yOffset+$lineLen) ;
714        drawWay (\@coords, 0, $svgString, "definitions", undef) ;
715
716        @coords = ($xOffset+$Lpix, $yOffset, $xOffset+$Lpix, $yOffset+$lineLen) ;
717        drawWay (\@coords, 0, $svgString, "definitions", undef) ;
718
719        @coords = ($xOffset+$Lpix/2, $yOffset, $xOffset+$Lpix/2, $yOffset+$lineLen/2) ;
720        drawWay (\@coords, 0, $svgString, "definitions", undef) ;
721
[26462]722
[26136]723        my $scale= getScale() ;
724        $text .= "(1:$scale)" ;
[26462]725
726
[26507]727        $svgString = mwMisc::createTextSVG ( cv('elementFontFamily'), cv('elementFont'), undef, undef, 45, $col, undef, undef) ;
[26136]728        drawText ($xOffset, $yOffset+$textDist+30, 0, $text, $svgString, "definitions") ;
729
730        addToLayer ("definitions", "</g>") ;
731
732        my $posX = 40 ; my $posY = 40 ;
733
734        if ( cv('ruler') eq "2") {
735                $posX = $sizeX - 40 - $rSizeX ;
736                $posY = 40 ;
737        }
738
739        if ( cv('ruler') eq "3") {
740                $posX = 40 ;
741                $posY = $sizeY - 40 - $rSizeY ;
742        }
743
744        if ( cv('ruler') eq "4") {
745                $posX = $sizeX - 40 - $rSizeX ;
746                $posY = $sizeY - 40 - $rSizeY ;
747        }
748
749        addToLayer ("ruler", "<use x=\"$posX\" y=\"$posY\" xlink:href=\"#rulerdef\" />") ;
750}
751
752sub drawScale {
753#
754# draws scale value
755#
756        my $col = cv('scalecolor') ;   
757
758        my $xOffset = 20 ;
759        my $yOffset = 20 ;
760        my $fontSize = 70 ;             
761        my $borderDist = 60 ;
762
763        my $rSizeX = int (350 + 2 * $xOffset) ;
764        my $rSizeY = int ($fontSize + 2 * $yOffset) ;
765        addToLayer ("definitions", "<g id=\"scaledef\" width=\"$rSizeX\" height=\"$rSizeY\" >") ;
766
767        if ( cv('scalebackground') ne "none" ) {
768                my $color = cv ('scalebackground') ;
769                my $svgString = "fill=\"$color\"" ;
770                drawRect (0, 0, $rSizeX, $rSizeY, 0, $svgString, "definitions") ;
771        }
772
773        my $scale= getScale() ;
[26462]774
[26507]775        my $svgString = mwMisc::createTextSVG ( cv('elementFontFamily'), cv('elementFont'), undef, undef, $fontSize, $col, undef, undef) ;
[26136]776        drawText ($xOffset, $fontSize + $yOffset, 0, "1:$scale", $svgString, "definitions") ;
777
778        addToLayer ("definitions", "</g>") ;
779
780        my $posX = $borderDist ; my $posY = $borderDist ;
781
782        if ( cv('scale') eq "2") {
783                $posX = $sizeX - $borderDist - $rSizeX ;
784                $posY = $borderDist ;
785        }
786
787        if ( cv('scale') eq "3") {
788                $posX = $borderDist ;
789                $posY = $sizeY - $borderDist - $rSizeY ;
790        }
791
792        if ( cv('scale') eq "4") {
793                $posX = $sizeX - $borderDist - $rSizeX ;
794                $posY = $sizeY - $borderDist - $rSizeY ;
795        }
796
797        addToLayer ("scale", "<use x=\"$posX\" y=\"$posY\" xlink:href=\"#scaledef\" />") ;
798}
799
800sub drawFoot {
801#
802# draws footer
803#
804        my $col = cv('footcolor') ;     
805        my $text = cv('foot') ; 
806        my $len = length $text ;
807
808        my $xOffset = 20 ;
809        my $yOffset = 20 ;
810        my $fontSize = cv('footsize') ;         
811        my $borderDistX = 60 ;
812        my $borderDistY = $fontSize + 50 ;
813
814        my $rSizeX = int ($len*cv('ppc')/10*$fontSize + 2 * $xOffset) ;
815        my $rSizeY = int ($fontSize + 2 * $yOffset) ;
816        addToLayer ("definitions", "<g id=\"footdef\" width=\"$rSizeX\" height=\"$rSizeY\" >") ;
817
818        if ( cv('footbackground') ne "none" ) {
819                my $color = cv ('footbackground') ;
820                my $svgString = "fill=\"$color\"" ;
821                drawRect (0, 0, $rSizeX, $rSizeY, 0, $svgString, "definitions") ;
822        }
823
[26507]824        my $svgString = mwMisc::createTextSVG ( cv('elementFontFamily'), cv('elementFont'), undef, undef, $fontSize, $col, undef, undef) ;
[26136]825        drawText ($xOffset, $fontSize + $yOffset, 0, $text, $svgString, "definitions") ;
826
827        addToLayer ("definitions", "</g>") ;
828
829        my $posX = $borderDistX ; my $posY = $sizeY - $borderDistY ;
830
831        addToLayer ("footer", "<use x=\"$posX\" y=\"$posY\" xlink:href=\"#footdef\" />") ;
832}
833
834sub drawHead {
835#
836# draws header
837#
838        my $col = cv('headcolor') ;     
839        my $text = cv('head') ; 
840        my $len = length $text ;
841
842        my $xOffset = 20 ;
843        my $yOffset = 20 ;
844        my $fontSize = cv('headsize') ;         
845        my $borderDistX = 60 ;
846        my $borderDistY = 60 ;
847
848        my $rSizeX = int ($len*cv('ppc')/10*$fontSize + 2 * $xOffset) ;
849        my $rSizeY = int ($fontSize + 2 * $yOffset) ;
850        addToLayer ("definitions", "<g id=\"headdef\" width=\"$rSizeX\" height=\"$rSizeY\" >") ;
851
852        if ( cv('headbackground') ne "none" ) {
853                my $color = cv ('headbackground') ;
854                my $svgString = "fill=\"$color\"" ;
855                drawRect (0, 0, $rSizeX, $rSizeY, 0, $svgString, "definitions") ;
856        }
857
[26507]858        my $svgString = mwMisc::createTextSVG ( cv('elementFontFamily'), cv('elementFont'), undef, undef, $fontSize, $col, undef, undef) ;
[26136]859        drawText ($xOffset, $fontSize + $yOffset, 0, $text, $svgString, "definitions") ;
860
861        addToLayer ("definitions", "</g>") ;
862
863        my $posX = $borderDistX ; my $posY = $borderDistY ;
864
865        addToLayer ("header", "<use x=\"$posX\" y=\"$posY\" xlink:href=\"#headdef\" />") ;
866}
867
868
869sub fitsPaper {
870#
871# calculates on what paper size the map will fit. sizes are taken from global variables
872#
873
874        my $width = $sizeX / 300 * 2.54 ;
875        my $height = $sizeY / 300 * 2.54 ;
876        my $paper = "" ;
877
878        my @sizes = () ;
879        push @sizes, ["4A0", 168.2, 237.8] ;
880        push @sizes, ["2A0", 118.9, 168.2] ;
881        push @sizes, ["A0", 84.1, 118.9] ;
882        push @sizes, ["A1", 59.4, 84.1] ;
883        push @sizes, ["A2", 42, 59.4] ;
884        push @sizes, ["A3", 29.7, 42] ;
885        push @sizes, ["A4", 21, 29.7] ;
886        push @sizes, ["A5", 14.8, 21] ;
887        push @sizes, ["A6", 10.5, 14.8] ;
888        push @sizes, ["A7", 7.4, 10.5] ;
889        push @sizes, ["none", 0, 0] ;
890
891        foreach my $size (@sizes) {
892                if ( ( ($width<=$size->[1]) and ($height<=$size->[2]) ) or ( ($width<=$size->[2]) and ($height<=$size->[1]) ) ) {
893                        $paper = $size->[0] ;
894                }
895        }
896
897        return ($paper, $width, $height) ;
898}
899
900sub getScale {
901#
902# calcs scale of map
903#
904        my ($dpi) = 300 ;
905
906        my $dist = distance ($left, $bottom, $right, $bottom) ;
907        my $inches = $sizeX / $dpi ;
908        my $cm = $inches * 2.54 ;
909        my $scale = int ( $dist / ($cm/100/1000)  ) ;
910        $scale = int ($scale / 100) * 100 ;
911
912        return ($scale) ;
913}
914
[26191]915sub gridSquare {
916#
917# returns grid square of given coordinates for directories
918#
919        my ($lon, $lat) = @_ ;
[26136]920
[26191]921        my $parts = cv('grid') ;
922
923        my ($x, $y) = convert ($lon, $lat) ;
924        my $xi = int ($x / ($sizeX / $parts)) + 1 ;
925        my $yi = int ($y / ($sizeX / $parts)) + 1 ;
926        if ( ($x >= 0) and ($x <= $sizeX) and ($y >= 0) and ($y <= $sizeY) ) {
927                return (chr($xi+64) . $yi) ;
928        }
929        else {
930                return undef ;
931        }
932}
933
934
[26199]935sub getDimensions {
936        return ($sizeX, $sizeY) ;
937}
[26191]938
[26201]939# ----------------------------------------------------------------------
940
941sub initOneways {
942#
943# write marker defs to svg
944#
945        my $color = cv('onewaycolor') ;
946
947        my @svgOutputDef = () ;
[26500]948        for (my $markerSize = 5; $markerSize <= 40; $markerSize++) {
949                push @svgOutputDef, "<marker id=\"Arrow$markerSize\"" ;
950                push @svgOutputDef, "viewBox=\"0 0 10 10\" refX=\"5\" refY=\"5\"" ;
951                push @svgOutputDef, "markerUnits=\"strokeWidth\"" ;
952                push @svgOutputDef, "markerWidth=\"" . $markerSize . "\" markerHeight=\"" . $markerSize . "\"" ;
953                push @svgOutputDef, "orient=\"auto\">" ;
954                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 .  "\" />" ;
955                push @svgOutputDef, "</marker>" ;
956        }
[26201]957
[26500]958
[26201]959        foreach my $line (@svgOutputDef) {
960                addToLayer ("definitions", $line) ;
961        }
962}
963
964sub addOnewayArrows {
965#
966# adds oneway arrows to new pathes
967#
968        my ($wayNodesRef, $direction, $thickness, $layer) = @_ ;
969        my @wayNodes = @$wayNodesRef ;
970        my ($lonRef, $latRef) = mwFile::getNodePointers() ;
971
972        if ($direction == -1) { @wayNodes = reverse @wayNodes ; }
973
[26500]974        my $minDist = cv('onewaysize') * 1.5 ;
975        my $markerSize = cv('onewaySize') ;
976
977        if ( cv('onewayAutoSize') != 0 ) {
978                $markerSize = int ( $thickness / 100 * cv('onewayAutoSize') ) ;
979                if ( $markerSize < 5 ) { $markerSize = 5 ; }
980                if ( $markerSize > 40 ) { $markerSize = 40 ; }
981                $minDist = $markerSize * 1.5 ;
982        }
983
[26201]984        # create new pathes with new nodes
[26500]985        for (my $i = 0; $i < scalar( @wayNodes ) - 1; $i++ ) {
[26201]986                my ($x1, $y1) = convert ($$lonRef{$wayNodes[$i]}, $$latRef{$wayNodes[$i]}) ;
987                my ($x2, $y2) = convert ($$lonRef{$wayNodes[$i+1]}, $$latRef{$wayNodes[$i+1]}) ;
988                my $xn = ($x2+$x1) / 2 ;
989                my $yn = ($y2+$y1) / 2 ;
990                if (sqrt (($x2-$x1)**2+($y2-$y1)**2) > $minDist) {
991                        # create path
992                        # use path
[26500]993                        my $svg = "<path d=\"M $x1 $y1 L $xn $yn L $x2 $y2\" fill=\"none\" marker-mid=\"url(#Arrow$markerSize)\" />" ;
[26201]994                       
995                        addToLayer ($layer+$thickness/100, $svg) ;
996                }
997        }
998}
999
[26271]1000# ----------------------------------------------------------------------------
[26201]1001
[26271]1002sub addAreaIcon {
1003#
1004# initial collection of area icons
1005#
1006        my $fileNameOriginal = shift ;
1007        # print "AREA: $fileNameOriginal\n" ;
1008        my $result = open (my $file, "<", $fileNameOriginal) ;
1009        close ($file) ;
1010        if ($result) {
1011                my ($x, $y) ;
1012                if (grep /.svg/, $fileNameOriginal) {
1013                        ($x, $y) = mwMisc::sizeSVG ($fileNameOriginal) ;
1014                        if ( ($x == 0) or ($y == 0) ) { 
1015                                $x = 32 ; $y = 32 ; 
1016                                print "WARNING: size of file $fileNameOriginal could not be determined. Set to 32px x 32px\n" ;
1017                        } 
1018                }
1019
1020                if (grep /.png/, $fileNameOriginal) {
1021                        ($x, $y) = mwMisc::sizePNG ($fileNameOriginal) ;
1022                }
1023
1024                if (!defined $areaDef{$fileNameOriginal}) {
1025
1026                        my $x1 = $x ; # scale area icons
1027                        my $y1 = $y ;
1028                        my $fx = $x1 / $x ;
1029                        my $fy = $y1 / $y ;
1030                       
1031                        # add defs to svg output
1032                        my $defName = "A" . $areaNum ;
1033                        # print "INFO area icon $fileNameOriginal, $defName, $x, $y --- $x1, $y1 --- $fx, $fy --- processed.\n" ;
1034                        $areaNum++ ;
1035
1036                        my $svgElement = "<pattern id=\"" . $defName . "\" width=\"" . $x . "\" height=\"" . $y . "\" " ;
1037                        $svgElement .= "patternTransform=\"translate(0,0) scale(" . $fx . "," . $fy . ")\" \n" ;
1038                        $svgElement .= "patternUnits=\"userSpaceOnUse\">\n" ;
1039                        $svgElement .= "  <image xlink:href=\"" . $fileNameOriginal . "\"/>\n" ;
1040                        $svgElement .= "</pattern>\n" ;
1041
1042                        addToLayer ("definitions", $svgElement) ;
1043
1044                        $defName = "#" . $defName ;
1045                        $areaDef{$fileNameOriginal} = $defName ;
1046                }
1047        }
1048        else {
1049                print "WARNING: area icon $fileNameOriginal not found!\n" ;
1050        }
1051}
1052
[26272]1053# ----------------------------------------------------------------------------
[26271]1054
[26272]1055sub createShield {
1056        my ($name, $targetSize) = @_ ;
1057        my @a = split /:/, $name ;
1058        my $shieldFileName = $a[1] ;
1059        my $shieldText = $a[2] ;
[26271]1060
[26272]1061        if (! defined $createdShields{$name}) {
1062                open (my $file, "<", $shieldFileName) or die ("ERROR: shield definition $shieldFileName not found.\n") ;
1063                my @defText = <$file> ;
1064                close ($file) ;
1065
1066                # get size
1067                # calc scaling
1068                my $sizeX = 0 ;
1069                my $sizeY = 0 ;
1070                foreach my $line (@defText) {
1071                        if (grep /<svg/, $line) {
1072                                ($sizeY) = ( $line =~ /height=\"(\d+)px\"/ ) ;
1073                                ($sizeX) = ( $line =~ /width=\"(\d+)px\"/ ) ;
1074                                if ( (!defined $sizeX) or (!defined $sizeY) ) {
1075                                        die "ERROR: size of shield in $shieldFileName could not be determined.\n" ;
1076                                }
1077                        }
1078                }
1079                if ( ($sizeX == 0) or ($sizeY == 0) ) {
1080                        die "ERROR: initial size of shield $shieldFileName could not be determined.\n" ;
1081                }
1082
1083                my $scaleFactor = $targetSize / $sizeY ;
1084
1085                $shieldXSize{ $name } = int ($sizeX * $scaleFactor) ;
1086                $shieldYSize{ $name } = int ($sizeY * $scaleFactor) ;
1087
1088                $shieldPathId++ ;
1089                my $shieldPathName = "ShieldPath" . $shieldPathId ;
1090                my $shieldGroupName = "ShieldGroup" . $shieldPathId ;
1091
1092                foreach my $line (@defText) {
1093                        $line =~ s/REPLACEID/$shieldGroupName/ ;
1094                        $line =~ s/REPLACESCALE/$scaleFactor/g ;
1095                        $line =~ s/REPLACEPATH/$shieldPathName/ ;
1096                        $line =~ s/REPLACELABEL/$shieldText/ ;
1097                }
1098
1099                foreach my $line (@defText) {
1100                        addToLayer ("definitions", $line) ;
1101                }
1102
1103                $createdShields{$name} = $shieldGroupName ;
1104        }
1105}
1106
1107sub getMaxShieldSize {
1108        my $name = shift ;
1109        my $max = $shieldXSize{$name} ;
1110        if ( $shieldYSize{$name} > $max) { $max = $shieldYSize{$name} ; }
1111        return $max ;
1112}
1113
1114sub getShieldSizes {
1115        my $name = shift ;
1116        my $x = $shieldXSize{$name} ;
1117        my $y = $shieldYSize{$name} ;
1118        return $x, $y ;
1119}
1120
1121sub getShieldId {
1122        my $name = shift ;
1123        return $createdShields{$name} ;
1124}
1125
[26412]1126# --------------------------------------------------------------------
1127
1128sub createLegendFile {
[26463]1129        my ($x, $y, $extension, $group) = @_ ;
[26412]1130
1131        my $svgName = cv('out') ;
[26463]1132        $svgName =~ s/\.svg/$extension\.svg/i ; 
[26412]1133        my $pngName = $svgName ;
1134        $pngName =~ s/\.svg/\.png/i ;
1135        my $pdfName = $svgName ;
1136        $pdfName =~ s/\.svg/\.pdf/i ;
1137
1138
1139        open (my $file, ">", $svgName) || die "can't open legend svg output file $svgName\n";
1140
1141        print $file "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>\n" ;
1142        print $file "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\" >\n" ;
1143
1144        my $w = $x / 300 * 2.54 ; # cm
1145        my $h = $y / 300 * 2.54 ;
1146
1147        my ($svg) = "<svg version=\"1.1\" baseProfile=\"full\" xmlns=\"http://www.w3.org/2000/svg\" " ;
1148        $svg .= "xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:ev=\"http://www.w3.org/2001/xml-events\" " ;
1149        $svg .= "width=\"$w" . "cm\" height=\"$h" . "cm\" viewBox=\"0 0 $x $y\">\n" ;
1150        print $file $svg ;
1151
1152        print $file "<defs>\n" ;
1153        foreach ( @{$svgLayer{'definitions'}} ) { print $file $_, "\n" ; }
1154        print $file "</defs>\n" ;
1155
[26463]1156        print $file "<use x=\"0\" y=\"0\" xlink:href=\"$group\" />\n" ;
[26412]1157        print $file "</svg>\n" ;
1158        close $file ;
1159
1160        if (cv('pdf') eq "1") {
1161                print "creating pdf file $pdfName ...\n" ;
1162                `inkscape -A $pdfName $svgName` ;
1163        }
1164
1165        if (cv('png') eq "1") {
1166                my $dpi = cv('pngdpi') ;
1167                print "creating png file $pngName ($dpi dpi)...\n" ;
1168                `inkscape --export-dpi=$dpi -e $pngName $svgName` ;
1169        }
1170}
1171
[26136]11721 ;
1173
1174
Note: See TracBrowser for help on using the repository browser.