# # PERL mapweaver module by gary68 # # # # # Copyright (C) 2011, Gerhard Schwanz # # 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 # Free Software Foundation; either version 3 of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along with this program; if not, see # package mwMap ; use strict ; use warnings ; use mwConfig ; # use mwMisc ; # use mwFile ; # use mwLabel ; use OSM::osm ; use Geo::Proj4 ; my $areaNum = 0 ; my %areaDef = () ; use vars qw($VERSION @ISA @EXPORT @EXPORT_OK); require Exporter ; @ISA = qw ( Exporter AutoLoader ) ; @EXPORT = qw ( initGraph coordsOut drawCircle drawSquare drawTriangle drawDiamond drawRect drawText writeMap drawWay drawArea fitsPaper getScale createPath pathText placeIcon convert gridSquare getDimensions initOneways addOnewayArrows addAreaIcon createShield getMaxShieldSize getShieldSizes getShieldId addToLayer createLegendFile ) ; my @belowWays = ("background", "base", "area", "multi") ; my @aboveWays = ( "arealabels", "wayLabels", "routes", "routeStops", "shields", "nodes", "icons", "text", "additional", "occupied") ; my @elements = ("scale", "ruler", "legend", "wns", "header", "footer", "rectangles", "title", "gpx") ; my %svgLayer = () ; my %wayLayer = () ; my $shieldPathId = 0 ; my %createdShields = () ; my %shieldXSize = () ; my %shieldYSize = () ; my $proj ; my ($bottom, $left, $right, $top) ; my ($sizeX, $sizeY) ; my ($projLeft, $projBottom, $projRight, $projTop) ; my ($projSizeX, $projSizeY) ; sub initGraph { # function initializes the picture and projection my ($x, $l, $b, $r, $t) = @_ ; # my $l0 = int($l) - 1 ; my $l0 = int(($r+$l) / 2 ) ; $proj = Geo::Proj4->new( proj => cv('projection'), ellps => cv('ellipsoid'), lon_0 => $l0 ) or die "parameter error: ".Geo::Proj4->error. "\n"; ($projLeft, $projBottom) = $proj->forward($b, $l) ; # lat/lon!!! ($projRight, $projTop) = $proj->forward($t, $r) ; # lat/lon!!! $projSizeX = $projRight - $projLeft ; $projSizeY = $projTop - $projBottom ; my $factor = $projSizeY / $projSizeX ; $sizeX = int ($x) ; $sizeY = int ($x * $factor) ; $top = $t ; $left = $l ; $right = $r ; $bottom = $b ; if ( ( cv('bgcolor') ne "none" ) and ( cv('bgcolor') ne "" ) ) { my $col = cv('bgcolor') ; my $svgText = "fill=\"$col\" " ; drawRect (0, 0, $sizeX, $sizeY, 0, $svgText, "background") ; } if ( cv('ruler') ne "0" ) { drawRuler() ; } if ( cv('scale') ne "0" ) { drawScale() ; } if ( cv('grid') != 0) { drawGrid() ; } if ( cv('coords') eq "1") { drawCoords() ; } if ( length cv('foot') > 0 ) { drawFoot() ; } if ( length cv('head') > 0 ) { drawHead() ; } } sub addToLayer { my ($layer, $text) = @_ ; if ( $layer =~ /^[\d\-\.]+$/) { push @{$wayLayer{$layer}}, $text ; # print "adding NUMERIC: $text\n" ; } else { push @{$svgLayer{$layer}}, $text ; # print "adding TEXTUAL: $text\n" ; } } sub drawWay { # 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 my ($nodesRef, $convert, $svgString, $layerName, $layerNumber) = @_ ; my @points = () ; my $valid = 0 ; # convert? and expand. my ($lonRef, $latRef, $tagRef) = mwFile::getNodePointers() ; if ($convert) { foreach my $node (@$nodesRef) { my ($x, $y) = convert ( $$lonRef{$node}, $$latRef{$node}) ; push @points, $x, $y ; if (! coordsOut ($x, $y)) { $valid = 1 ; } } } else { @points = @$nodesRef ; foreach my $node (@$nodesRef) { my ($x, $y) = ( $$lonRef{$node}, $$latRef{$node}) ; if (! coordsOut ($x, $y)) { $valid = 1 ; } } } my $refp = simplifyPoints (\@points) ; @points = @$refp ; if ($valid) { my $svg = "" ; if (defined $layerNumber) { push @{ $wayLayer{ $layerNumber } }, $svg ; } else { push @{ $svgLayer { $layerName } }, $svg ; } } else { # if () { print "way not drawn, outside\n" ; } } } sub drawText { my ($x, $y, $convert, $text, $svgString, $layerName) = @_ ; if ($convert) { ($x, $y) = convert ($x, $y) ; } if ( ! coordsOut ($x, $y) ) { my $svg = "" . $text . "" ; push @{ $svgLayer { $layerName } }, $svg ; } } sub drawCircle { # draws circle element to svgLayer given; if convertCoords then lon / lat is converted to x / y # circleradius either in pixel or in meters (convert=1) my ($x, $y, $convertCoords, $radius, $convertRadius, $format, $layerName) = @_ ; if ($convertCoords) { ($x, $y) = convert ($x, $y) ; } if ($convertRadius) { $radius = $radius / (1000 * distance ($left, $bottom, $right, $bottom) ) * $sizeX ; } if ( ! coordsOut ($x, $y) ) { my $svg = "" ; push @{ $svgLayer { $layerName } }, $svg ; } } sub drawSquare { # draws square element to svgLayer given; if convertCoords then lon / lat is converted to x / y # square size either in pixel or in meters (convert=1) my ($x, $y, $convertCoords, $size, $convertSize, $format, $layerName) = @_ ; if ($convertCoords) { ($x, $y) = convert ($x, $y) ; } if ($convertSize) { $size = $size / (1000 * distance ($left, $bottom, $right, $bottom) ) * $sizeX ; } my $x1 = $x - $size ; my $y1 = $y - $size ; my $dSize = 2 * $size ; if ( ! coordsOut ($x, $y) ) { my $svg = "" ; push @{ $svgLayer { $layerName } }, $svg ; } } sub drawTriangle { # draws triangle element to svgLayer given; if convertCoords then lon / lat is converted to x / y # square size either in pixel or in meters (convert=1) my ($x, $y, $convertCoords, $size, $convertSize, $format, $layerName) = @_ ; if ($convertCoords) { ($x, $y) = convert ($x, $y) ; } if ($convertSize) { $size = $size / (1000 * distance ($left, $bottom, $right, $bottom) ) * $sizeX ; } my $h = int ( sqrt ($size * $size / 2) ) ; my $x1 = $x ; # my $y1 = $y - $size ; my $y1 = $y - $h ; my $x2 = $x - $h ; my $y2 = $y + $h ; my $x3 = $x + $h ; my $y3 = $y + $h ; if ( ! coordsOut ($x1, $y1, $x2, $y2, $x3, $y3) ) { my $svg = "" ; push @{ $svgLayer { $layerName } }, $svg ; } } sub drawDiamond { # draws diamond element to svgLayer given; if convertCoords then lon / lat is converted to x / y # square size either in pixel or in meters (convert=1) my ($x, $y, $convertCoords, $size, $convertSize, $format, $layerName) = @_ ; if ($convertCoords) { ($x, $y) = convert ($x, $y) ; } if ($convertSize) { $size = $size / (1000 * distance ($left, $bottom, $right, $bottom) ) * $sizeX ; } my $x1 = $x - $size ; # left my $y1 = $y ; my $x2 = $x ; # top my $y2 = $y - $size ; my $x3 = $x + $size ; #right my $y3 = $y ; my $x4 = $x ; # bottom my $y4 = $y + $size ; if ( ! coordsOut ($x1, $y1, $x2, $y2, $x3, $y3, $x4, $y4) ) { my $svg = "" ; push @{ $svgLayer { $layerName } }, $svg ; } } sub drawRect { # draws square element to svgLayer given; if convertCoords then lon / lat is converted to x / y # square size either in pixel or in meters (convert=1) my ($x1, $y1, $x2, $y2, $convertCoords, $format, $layerName) = @_ ; if ($convertCoords) { ($x1, $y1) = convert ($x1, $y1) ; ($x2, $y2) = convert ($x2, $y2) ; } my $sizeX = $x2 - $x1 ; my $sizeY = $y2 - $y1 ; if ( ! coordsOut ($x1, $y1, $x2, $y2) ) { my $svg = "" ; push @{ $svgLayer { $layerName } }, $svg ; } } sub createPath { # # creates path element for later use with textPath # my ($pathName, $refp, $layer) = @_ ; my $refp2 = simplifyPoints ($refp) ; my @points = @$refp2 ; my $svg = "\n" ; push @{ $svgLayer{ $layer } }, $svg ; } sub pathText { # # draws text to path element; alignment: start, middle, end # my ($svgText, $text, $pathName, $tSpan, $alignment, $offset, $layer) = @_ ; my $svg = "\n" ; $svg = $svg . "\n" ; $svg = $svg . "" . $text . " \n" ; $svg = $svg . "\n\n" ; push @{ $svgLayer{ $layer } }, $svg ; } sub placeIcon { # # create SVG text for icons # my ($x, $y, $icon, $sizeX, $sizeY, $layer) = @_ ; if ( ! coordsOut ($x, $y) ) { my ($out) = " 0) { $out .= " width=\"" . $sizeX . "\"" ; } if ($sizeY > 0) { $out .= " height=\"" . $sizeY . "\"" ; } $out .= " xlink:href=\"" . $icon . "\" />" ; push @{ $svgLayer{ $layer } }, $out ; } } sub drawArea { # # draws mp in svg ARRAY of ARRAY of nodes/coordinates # my ($svgText, $icon, $ref, $convert, $layer) = @_ ; my @ways = @$ref ; my $i ; my $svg = "" ; my $valid = 1 ; my @newArray = () ; # TODO loop converts original data !!! if ($convert) { my ($lonRef, $latRef, $tagRef) = mwFile::getNodePointers () ; foreach my $aRef (@ways) { my @way = @$aRef ; my @newCoords = () ; foreach my $n (@way) { my ($x, $y) = convert ($$lonRef{$n}, $$latRef{$n}) ; push @newCoords, $x, $y ; if (coordsOut ($x, $y)) { $valid = 0 ; } } push @newArray , [@newCoords] ; } @ways = @newArray ; } if (defined $areaDef{$icon}) { $svg = "" ; if ($valid) { push @{ $svgLayer{ $layer } }, $svg ; } } # --------------------------------------------------------------------- sub writeMap { my $fileName = cv ('out') ; open (my $file, ">", $fileName) || die "can't open svg output file $fileName\n"; print $file "\n" ; print $file "\n" ; my $w = $sizeX / 300 * 2.54 ; # cm my $h = $sizeY / 300 * 2.54 ; my ($svg) = "\n" ; print $file $svg ; # definitions if ( defined @{$svgLayer{'definitions'}} ) { print $file "\n" ; foreach ( @{$svgLayer{'definitions'}} ) { print $file $_, "\n" ; } print $file "\n" ; } # below ways foreach my $layer (@belowWays) { if ( defined @{$svgLayer{$layer}} ) { print $file "\n" ; foreach ( @{$svgLayer{$layer}} ) { print $file $_, "\n" ; } print $file "\n" ; } } # ways foreach my $layer (sort {$a <=> $b} keys %wayLayer) { if ( defined @{$wayLayer{$layer}} ) { print $file "\n" ; foreach ( @{$wayLayer{$layer}} ) { print $file $_, "\n" ; } print $file "\n" ; } } # above of ways foreach my $layer (@aboveWays) { if ( defined @{$svgLayer{$layer}} ) { print $file "\n" ; foreach ( @{$svgLayer{$layer}} ) { print $file $_, "\n" ; } print $file "\n" ; } } foreach my $layer (@elements) { if (defined @{$svgLayer{$layer}}) { print $file "\n" ; foreach ( @{$svgLayer{$layer}} ) { print $file $_, "\n" ; } print $file "\n" ; } } print $file "\n" ; close ($file) ; if (cv('pdf') eq "1") { my ($pdfName) = $fileName ; $pdfName =~ s/\.svg/\.pdf/ ; print "creating pdf file $pdfName ...\n" ; `inkscape -A $pdfName $fileName` ; } if (cv('png') eq "1") { my ($pngName) = $fileName ; $pngName =~ s/\.svg/\.png/ ; my $dpi = cv('pngdpi') ; print "creating png file $pngName ($dpi dpi)...\n" ; `inkscape --export-dpi=$dpi -e $pngName $fileName` ; } } # ----------------------------------------------------------------------------------- sub drawGrid { # # draw grid on top of map. receives number of parts in x/lon direction # my $number = cv ('grid') ; my $color = cv ('gridcolor') ; my $part = $sizeX / $number ; my $numY = $sizeY / $part ; my $svgStringLine="stroke=\"$color\" stroke-width=\"5\" stroke-dasharray=\"30,30\"" ; my $svgStringText = mwMisc::createTextSVG ( cv('elementFontFamily'), cv('elementFont'), undef, undef, 60, $color, undef, undef) ; # vertical lines for (my $i = 1; $i <= $number; $i++) { my @coords = ($i*$part, 0, $i*$part, $sizeY) ; drawWay (\@coords, 0, $svgStringLine, "additional", undef) ; drawText ( ($i-1)*$part+$part/2, 160, 0, chr($i+64), $svgStringText, "additional") ; } # hor. lines for (my $i = 1; $i <= $numY; $i++) { my @coords = (0, $i*$part, $sizeX, $i*$part) ; drawWay (\@coords, 0, $svgStringLine, "additional", undef) ; drawText ( 20, ($i-1)*$part+$part/2, 0, $i, $svgStringText, "additional") ; } } sub drawCoords { # # draws coordinates grid on map # my $exp = cv('coordsexp') ; my $color = cv ('coordscolor'); my $step = 10 ** $exp ; # vert. lines my $start = int ($left / $step) + 1 ; my $actual = $start * $step ; my $svgStringLine="stroke=\"$color\" stroke-width=\"3\"" ; my $svgStringText = mwMisc::createTextSVG ( cv('elementFontFamily'), cv('elementFont'), undef, undef, 30, $color, undef, undef) ; while ($actual < $right) { my ($x1, $y1) = convert ($actual, 0) ; drawText ( $x1+10, $sizeY-50, 0, $actual, $svgStringText, "additional") ; my @coords = ($x1, 0, $x1, $sizeY) ; drawWay (\@coords, 0, $svgStringLine, "additional", undef) ; $actual += $step ; } # hor lines $start = int ($bottom / $step) + 1 ; $actual = $start * $step ; while ($actual < $top) { # print "actualY: $actual\n" ; my ($x1, $y1) = convert (0, $actual) ; drawText ( $sizeX-180, $y1+30, 0, $actual, $svgStringText, "additional") ; my @coords = (0, $y1, $sizeX, $y1) ; drawWay (\@coords, 0, $svgStringLine, "additional", undef) ; $actual += $step ; } } # ----------------------------------------------------------------------------------- sub convert { # converts real world coordinates to system graph pixel coordinates my ($x, $y) = @_ ; my ($x1, $y1) = $proj->forward($y, $x) ; # lat/lon!!! my $x2 = int ( ($x1 - $projLeft) / ($projRight - $projLeft) * $sizeX ) ; my $y2 = $sizeY - int ( ($y1 - $projBottom) / ($projTop - $projBottom) * $sizeY ) ; return ($x2, $y2) ; } sub simplifyPoints { my $ref = shift ; my @points = @$ref ; my @newPoints ; my $maxIndex = $#points ; if (scalar @points > 4) { # push first push @newPoints, $points[0], $points[1] ; # push other for (my $i=2; $i <= $maxIndex; $i+=2) { # $simplifyTotal++ ; if ( ($points[$i]==$points[$i-2]) and ($points[$i+1]==$points[$i-1]) ) { # same # $simplified++ ; } else { push @newPoints, $points[$i], $points[$i+1] ; } } return (\@newPoints) ; } else { return ($ref) ; } } sub drawRuler { # # draws ruler # my $col = cv('rulercolor') ; my $B ; my $B2 ; my $L ; my $Lpix ; my $x ; my $text ; my $lineThickness = 8 ; # at 300dpi my $textSize = 40 ; # at 300 dpi my $textDist = 60 ; # at 300 dpi my $lineLen = 40 ; # at 300 dpi my $xOffset = 2 * $lineThickness ; my $yOffset = 2 * $lineThickness ; $B = $right - $left ; # in degrees $B2 = $B * cos ($top/360*3.14*2) * 111.1 ; # in km $text = "50m" ; $x = 0.05 ; # default length ruler if ($B2 > 0.5) {$text = "100 m" ; $x = 0.1 ; } # enlarge ruler if ($B2 > 1) {$text = "500 m" ; $x = 0.5 ; } # enlarge ruler if ($B2 > 5) {$text = "1 km" ; $x = 1 ; } if ($B2 > 10) {$text = "5 km" ; $x = 5 ; } if ($B2 > 50) {$text = "10 km" ; $x = 10 ; } $L = $x / (cos ($top/360*3.14*2) * 111.1 ) ; # length ruler in km $Lpix = $L / $B * $sizeX ; # length ruler in pixels my $rSizeX = int ($Lpix + 2 * $xOffset) ; my $rSizeY = int ($lineLen + $textSize + 3 * $yOffset) ; addToLayer ("definitions", "") ; if ( cv('rulerbackground') ne "none" ) { my $color = cv ('rulerbackground') ; my $svgString = "fill=\"$color\"" ; drawRect (0, 0, $rSizeX, $rSizeY, 0, $svgString, "definitions") ; } my $svgString = "stroke=\"$col\" stroke-width=\"$lineThickness\" stroke-linecap=\"round\" " ; my @coords = ($xOffset, $yOffset, $xOffset+$Lpix, $yOffset) ; drawWay (\@coords, 0, $svgString, "definitions", undef) ; @coords = ($xOffset, $yOffset, $xOffset, $yOffset+$lineLen) ; drawWay (\@coords, 0, $svgString, "definitions", undef) ; @coords = ($xOffset+$Lpix, $yOffset, $xOffset+$Lpix, $yOffset+$lineLen) ; drawWay (\@coords, 0, $svgString, "definitions", undef) ; @coords = ($xOffset+$Lpix/2, $yOffset, $xOffset+$Lpix/2, $yOffset+$lineLen/2) ; drawWay (\@coords, 0, $svgString, "definitions", undef) ; my $scale= getScale() ; $text .= "(1:$scale)" ; $svgString = mwMisc::createTextSVG ( cv('elementFontFamily'), cv('elementFont'), undef, undef, 35, $col, undef, undef) ; drawText ($xOffset, $yOffset+$textDist+30, 0, $text, $svgString, "definitions") ; addToLayer ("definitions", "") ; my $posX = 40 ; my $posY = 40 ; if ( cv('ruler') eq "2") { $posX = $sizeX - 40 - $rSizeX ; $posY = 40 ; } if ( cv('ruler') eq "3") { $posX = 40 ; $posY = $sizeY - 40 - $rSizeY ; } if ( cv('ruler') eq "4") { $posX = $sizeX - 40 - $rSizeX ; $posY = $sizeY - 40 - $rSizeY ; } addToLayer ("ruler", "") ; } sub drawScale { # # draws scale value # my $col = cv('scalecolor') ; my $xOffset = 20 ; my $yOffset = 20 ; my $fontSize = 70 ; my $borderDist = 60 ; my $rSizeX = int (350 + 2 * $xOffset) ; my $rSizeY = int ($fontSize + 2 * $yOffset) ; addToLayer ("definitions", "") ; if ( cv('scalebackground') ne "none" ) { my $color = cv ('scalebackground') ; my $svgString = "fill=\"$color\"" ; drawRect (0, 0, $rSizeX, $rSizeY, 0, $svgString, "definitions") ; } my $scale= getScale() ; my $svgString = mwMisc::createTextSVG ( cv('elementFontFamily'), cv('elementFont'), undef, undef, $fontSize, $col, undef, undef) ; drawText ($xOffset, $fontSize + $yOffset, 0, "1:$scale", $svgString, "definitions") ; addToLayer ("definitions", "") ; my $posX = $borderDist ; my $posY = $borderDist ; if ( cv('scale') eq "2") { $posX = $sizeX - $borderDist - $rSizeX ; $posY = $borderDist ; } if ( cv('scale') eq "3") { $posX = $borderDist ; $posY = $sizeY - $borderDist - $rSizeY ; } if ( cv('scale') eq "4") { $posX = $sizeX - $borderDist - $rSizeX ; $posY = $sizeY - $borderDist - $rSizeY ; } addToLayer ("scale", "") ; } sub drawFoot { # # draws footer # my $col = cv('footcolor') ; my $text = cv('foot') ; my $len = length $text ; my $xOffset = 20 ; my $yOffset = 20 ; my $fontSize = cv('footsize') ; my $borderDistX = 60 ; my $borderDistY = $fontSize + 50 ; my $rSizeX = int ($len*cv('ppc')/10*$fontSize + 2 * $xOffset) ; my $rSizeY = int ($fontSize + 2 * $yOffset) ; addToLayer ("definitions", "") ; if ( cv('footbackground') ne "none" ) { my $color = cv ('footbackground') ; my $svgString = "fill=\"$color\"" ; drawRect (0, 0, $rSizeX, $rSizeY, 0, $svgString, "definitions") ; } my $svgString = mwMisc::createTextSVG ( cv('elementFontFamily'), cv('elementFont'), undef, undef, $fontSize, $col, undef, undef) ; drawText ($xOffset, $fontSize + $yOffset, 0, $text, $svgString, "definitions") ; addToLayer ("definitions", "") ; my $posX = $borderDistX ; my $posY = $sizeY - $borderDistY ; addToLayer ("footer", "") ; } sub drawHead { # # draws header # my $col = cv('headcolor') ; my $text = cv('head') ; my $len = length $text ; my $xOffset = 20 ; my $yOffset = 20 ; my $fontSize = cv('headsize') ; my $borderDistX = 60 ; my $borderDistY = 60 ; my $rSizeX = int ($len*cv('ppc')/10*$fontSize + 2 * $xOffset) ; my $rSizeY = int ($fontSize + 2 * $yOffset) ; addToLayer ("definitions", "") ; if ( cv('headbackground') ne "none" ) { my $color = cv ('headbackground') ; my $svgString = "fill=\"$color\"" ; drawRect (0, 0, $rSizeX, $rSizeY, 0, $svgString, "definitions") ; } my $svgString = mwMisc::createTextSVG ( cv('elementFontFamily'), cv('elementFont'), undef, undef, $fontSize, $col, undef, undef) ; drawText ($xOffset, $fontSize + $yOffset, 0, $text, $svgString, "definitions") ; addToLayer ("definitions", "") ; my $posX = $borderDistX ; my $posY = $borderDistY ; addToLayer ("header", "") ; } sub fitsPaper { # # calculates on what paper size the map will fit. sizes are taken from global variables # my $width = $sizeX / 300 * 2.54 ; my $height = $sizeY / 300 * 2.54 ; my $paper = "" ; my @sizes = () ; push @sizes, ["4A0", 168.2, 237.8] ; push @sizes, ["2A0", 118.9, 168.2] ; push @sizes, ["A0", 84.1, 118.9] ; push @sizes, ["A1", 59.4, 84.1] ; push @sizes, ["A2", 42, 59.4] ; push @sizes, ["A3", 29.7, 42] ; push @sizes, ["A4", 21, 29.7] ; push @sizes, ["A5", 14.8, 21] ; push @sizes, ["A6", 10.5, 14.8] ; push @sizes, ["A7", 7.4, 10.5] ; push @sizes, ["none", 0, 0] ; foreach my $size (@sizes) { if ( ( ($width<=$size->[1]) and ($height<=$size->[2]) ) or ( ($width<=$size->[2]) and ($height<=$size->[1]) ) ) { $paper = $size->[0] ; } } return ($paper, $width, $height) ; } sub getScale { # # calcs scale of map # my ($dpi) = 300 ; my $dist = distance ($left, $bottom, $right, $bottom) ; my $inches = $sizeX / $dpi ; my $cm = $inches * 2.54 ; my $scale = int ( $dist / ($cm/100/1000) ) ; $scale = int ($scale / 100) * 100 ; return ($scale) ; } sub gridSquare { # # returns grid square of given coordinates for directories # my ($lon, $lat) = @_ ; my $parts = cv('grid') ; my ($x, $y) = convert ($lon, $lat) ; my $xi = int ($x / ($sizeX / $parts)) + 1 ; my $yi = int ($y / ($sizeX / $parts)) + 1 ; if ( ($x >= 0) and ($x <= $sizeX) and ($y >= 0) and ($y <= $sizeY) ) { return (chr($xi+64) . $yi) ; } else { return undef ; } } sub getDimensions { return ($sizeX, $sizeY) ; } # ---------------------------------------------------------------------- sub initOneways { # # write marker defs to svg # my $color = cv('onewaycolor') ; my @svgOutputDef = () ; for (my $markerSize = 5; $markerSize <= 40; $markerSize++) { push @svgOutputDef, "" ; push @svgOutputDef, "" ; push @svgOutputDef, "" ; } foreach my $line (@svgOutputDef) { addToLayer ("definitions", $line) ; } } sub addOnewayArrows { # # adds oneway arrows to new pathes # my ($wayNodesRef, $direction, $thickness, $layer) = @_ ; my @wayNodes = @$wayNodesRef ; my ($lonRef, $latRef) = mwFile::getNodePointers() ; if ($direction == -1) { @wayNodes = reverse @wayNodes ; } my $minDist = cv('onewaysize') * 1.5 ; my $markerSize = cv('onewaySize') ; if ( cv('onewayAutoSize') != 0 ) { $markerSize = int ( $thickness / 100 * cv('onewayAutoSize') ) ; if ( $markerSize < 5 ) { $markerSize = 5 ; } if ( $markerSize > 40 ) { $markerSize = 40 ; } $minDist = $markerSize * 1.5 ; } # create new pathes with new nodes for (my $i = 0; $i < scalar( @wayNodes ) - 1; $i++ ) { my ($x1, $y1) = convert ($$lonRef{$wayNodes[$i]}, $$latRef{$wayNodes[$i]}) ; my ($x2, $y2) = convert ($$lonRef{$wayNodes[$i+1]}, $$latRef{$wayNodes[$i+1]}) ; my $xn = ($x2+$x1) / 2 ; my $yn = ($y2+$y1) / 2 ; if (sqrt (($x2-$x1)**2+($y2-$y1)**2) > $minDist) { # create path # use path my $svg = "" ; addToLayer ($layer+$thickness/100, $svg) ; } } } # ---------------------------------------------------------------------------- sub addAreaIcon { # # initial collection of area icons # my $fileNameOriginal = shift ; # print "AREA: $fileNameOriginal\n" ; my $result = open (my $file, "<", $fileNameOriginal) ; close ($file) ; if ($result) { my ($x, $y) ; if (grep /.svg/, $fileNameOriginal) { ($x, $y) = mwMisc::sizeSVG ($fileNameOriginal) ; if ( ($x == 0) or ($y == 0) ) { $x = 32 ; $y = 32 ; print "WARNING: size of file $fileNameOriginal could not be determined. Set to 32px x 32px\n" ; } } if (grep /.png/, $fileNameOriginal) { ($x, $y) = mwMisc::sizePNG ($fileNameOriginal) ; } if (!defined $areaDef{$fileNameOriginal}) { my $x1 = $x ; # scale area icons my $y1 = $y ; my $fx = $x1 / $x ; my $fy = $y1 / $y ; # add defs to svg output my $defName = "A" . $areaNum ; # print "INFO area icon $fileNameOriginal, $defName, $x, $y --- $x1, $y1 --- $fx, $fy --- processed.\n" ; $areaNum++ ; my $svgElement = "\n" ; $svgElement .= " \n" ; $svgElement .= "\n" ; addToLayer ("definitions", $svgElement) ; $defName = "#" . $defName ; $areaDef{$fileNameOriginal} = $defName ; } } else { print "WARNING: area icon $fileNameOriginal not found!\n" ; } } # ---------------------------------------------------------------------------- sub createShield { my ($name, $targetSize) = @_ ; my @a = split /:/, $name ; my $shieldFileName = $a[1] ; my $shieldText = $a[2] ; if (! defined $createdShields{$name}) { open (my $file, "<", $shieldFileName) or die ("ERROR: shield definition $shieldFileName not found.\n") ; my @defText = <$file> ; close ($file) ; # get size # calc scaling my $sizeX = 0 ; my $sizeY = 0 ; foreach my $line (@defText) { if (grep / $max) { $max = $shieldYSize{$name} ; } return $max ; } sub getShieldSizes { my $name = shift ; my $x = $shieldXSize{$name} ; my $y = $shieldYSize{$name} ; return $x, $y ; } sub getShieldId { my $name = shift ; return $createdShields{$name} ; } # -------------------------------------------------------------------- sub createLegendFile { my ($x, $y, $extension, $group) = @_ ; my $svgName = cv('out') ; $svgName =~ s/\.svg/$extension\.svg/i ; my $pngName = $svgName ; $pngName =~ s/\.svg/\.png/i ; my $pdfName = $svgName ; $pdfName =~ s/\.svg/\.pdf/i ; open (my $file, ">", $svgName) || die "can't open legend svg output file $svgName\n"; print $file "\n" ; print $file "\n" ; my $w = $x / 300 * 2.54 ; # cm my $h = $y / 300 * 2.54 ; my ($svg) = "\n" ; print $file $svg ; print $file "\n" ; foreach ( @{$svgLayer{'definitions'}} ) { print $file $_, "\n" ; } print $file "\n" ; print $file "\n" ; print $file "\n" ; close $file ; if (cv('pdf') eq "1") { print "creating pdf file $pdfName ...\n" ; `inkscape -A $pdfName $svgName` ; } if (cv('png') eq "1") { my $dpi = cv('pngdpi') ; print "creating png file $pngName ($dpi dpi)...\n" ; `inkscape --export-dpi=$dpi -e $pngName $svgName` ; } } sub coordsOut { my @points = @_ ; my $allOut = 0 ; my $outLeft = 1 ; my $outRight = 1 ; my $outTop = 1 ; my $outBottom = 1 ; for (my $i=0; $i < scalar(@points) - 1; $i += 2) { my $x = $points[$i] ; my $y = $points[$i+1] ; if ($x >= 0) { $outLeft = 0 ; } if ($x <= $sizeX) { $outRight = 0 ; } if ($y >= 0) { $outBottom = 0 ; } if ($y <= $sizeY) { $outTop = 0 ; } } if ( ($outLeft) or ($outRight) or ($outTop) or ($outBottom) ) { $allOut = 1 ; } return $allOut ; } 1 ;