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

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

new mapweaver version

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