# # 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 mwRelations ; use strict ; use warnings ; use mwMap ; use mwRules ; use mwFile ; use mwMisc ; use mwLabel ; use mwConfig ; use vars qw($VERSION @ISA @EXPORT @EXPORT_OK); require Exporter ; @ISA = qw ( Exporter AutoLoader ) ; @EXPORT = qw ( processRoutes ) ; my $pathNumber = 0 ; my %iconSizeX = () ; my %iconSizeY = () ; # -------------------------------------------------------------------------- sub processRoutes { # # process route data # my %routeColors = () ; # will point to arrays of colors per route type my %actualColorIndex = () ; # which color is next my %colorNumber = () ; # number of colors per route type my %wayRouteLabels = () ; # labels to be used per way my %wayRouteIcons = () ; # icons to be used per way my (%iconSizeX, %iconSizeY) ; print "processing routes...\n" ; # init before relation processing # get colors per type and set actual index my $ref = getRouteColors() ; %routeColors = %$ref ; foreach my $type (keys %routeColors) { $colorNumber{$type} = scalar @{$routeColors{$type}} ; $actualColorIndex{$type} = 0 ; } my ($lonRef, $latRef) = getNodePointers() ; my ($wayNodesRef, $wayTagsRef) = getWayPointers() ; my ($relationMembersRef, $relationTagsRef) = getRelationPointers() ; foreach my $relId (keys %$relationTagsRef) { my $relationType = getValue ("type", $$relationTagsRef{$relId} ) ; if ( ! defined $relationType ) { $relationType = "" ; } if ( ( $relationType eq "route" ) and ( (cv('relid') == $relId) or (cv('relid') == 0) ) ) { my $ruleRef = getRouteRule( $$relationTagsRef{$relId} ) ; if (defined $ruleRef) { # new route detected if (cv('debug') eq "1" ) { print "ROUTE: rule found for $relId, $$ruleRef{'type'}.\n" ; } # try to get color from relation tags first # my $color = getValue ("color", $$relationTagsRef{$relId} ) ; if ( ! defined $color) { $color = getValue ("colour", $$relationTagsRef{$relId} ) ; } # no color yet, then get color from rule # if ( ! defined $color) { if (cv('debug') eq "1" ) { print "ROUTE: actual color index: $actualColorIndex{ $$ruleRef{'type'} }\n" ; } $color = $routeColors{ $$ruleRef{'type'} }[$actualColorIndex{ $$ruleRef{'type'} }] ; $actualColorIndex{ $$ruleRef{'type'} } = ($actualColorIndex{ $$ruleRef{'type'} } + 1) % $colorNumber{ $$ruleRef{'type'} } ; } if (cv('debug') eq "1" ) { print "ROUTE: $relId final color: $color\n" ; } # find icon my $iconName = getValue ("ref", $$relationTagsRef{$relId} ) ; if ( ! defined $iconName ) { getValue ("name", $$relationTagsRef{$relId} ) } if ( ! defined $iconName) { $iconName = "" ; } # look for route icon. svg first, then png my $file ; $iconName = cv('routeicondir') . $$ruleRef{'type'} . "-" . $iconName . ".svg" ; my $iconResult = open ($file, "<", $iconName) ; # print " trying $iconName\n" ; if ($iconResult) { if (cv('debug') eq "1") { print "ROUTE: icon $iconName found!\n" ; } close ($file) ; } if ( ! $iconResult) { $iconName =~ s/.svg/.png/ ; # print " trying $iconName\n" ; $iconResult = open ($file, "<", $iconName) ; if ($iconResult) { if (cv('debug') eq "1") { print "ROUTE: icon $iconName found!\n" ; } close ($file) ; } } if ($iconResult) { my ($x, $y) ; undef $x ; undef $y ; if (grep /.svg/, $iconName) { ($x, $y) = sizeSVG ($iconName) ; if ( ($x == 0) or ($y == 0) ) { $x = 32 ; $y = 32 ; print "WARNING: size of file $iconName could not be determined. Set to 32px x 32px\n" ; } } if (grep /.png/, $iconName) { ($x, $y) = sizePNG ($iconName) ; } $iconSizeX{$iconName} = $x ; $iconSizeY{$iconName} = $y ; } my ($label, $ref) = createLabel ( $$relationTagsRef{$relId}, $$ruleRef{'label'} ) ; my $printIcon = "" ; if ($iconResult) { $printIcon = $iconName ; } if (cv('verbose') eq "1" ) { printf "ROUTE: route %10s %10s %10s %30s %40s\n", $relId, $$ruleRef{'type'}, $color, $label, $printIcon ; } # collect ways my $mRef = getAllMembers ($relId, 0) ; my @tempMembers = @$mRef ; my @relWays = () ; foreach my $member (@tempMembers) { if ( ( ($member->[2] eq "none") or ($member->[2] eq "route") ) and ($member->[0] eq "way") ) { push @relWays, $member->[1] ; } if ( ( ($member->[2] eq "forward") or ($member->[2] eq "backward") ) and ($member->[0] eq "way") ) { push @relWays, $member->[1] ; } # TODO diversions, shortcuts? # stops if ( (grep /stop/, $member->[2]) and ($member->[0] eq "node") ) { if ( ( $$ruleRef{'nodesize'} > 0) and (defined $$latRef{$member->[1]}) and (defined $$lonRef{$member->[1]}) ) { my $svgString = "fill=\"$color\" " ; drawCircle ($$lonRef{$member->[1]}, $$latRef{$member->[1]}, 1, $$ruleRef{'nodesize'}, 0, $svgString, 'routes') ; } } } if (cv('debug') eq "1" ) { print "ROUTE: ways: @relWays\n" ; } foreach my $w (@relWays) { my $op = $$ruleRef{'opacity'} / 100 ; my $width = $$ruleRef{'size'} ; my $linecap = $$ruleRef{'linecap'} ; my $dashString = "" ; my $dash = $$ruleRef{'dash'} ; if ( $dash ne "") { $dashString = "stroke-dasharray=\"$dash\" " ; } my $svgString = "stroke=\"$color\" stroke-opacity=\"$op\" stroke-width=\"$width\" fill=\"none\" stroke-linejoin=\"round\" stroke-linecap=\"$linecap\" " . $dashString ; drawWay ($$wayNodesRef{$w}, 1, $svgString, "routes", undef) ; # collect labels and icons per way # $wayRouteLabels{$w}{$label} = 1 ; if ($iconResult) { $wayRouteIcons{$w}{$iconName} = 1 ; } } } # rule found if (cv('debug') eq "1") { print "\n" ; } } # rel route } # relation # label route ways after all relations have been processed foreach my $w (keys %wayRouteLabels) { if ( (defined $$wayNodesRef{$w}) and (scalar @{$$wayNodesRef{$w}} > 1) ) { my $label = "" ; foreach my $l (keys %{$wayRouteLabels{$w}}) { $label .= $l . " " ; } my @way = @{$$wayNodesRef{$w}} ; if ($$lonRef{$way[0]} > $$lonRef{$way[-1]}) { @way = reverse (@way) ; } if (labelFitsWay ( \@way, $label, cv('routelabelfont'), cv('routelabelsize') ) ) { my $pathName = "RoutePath" . $pathNumber ; $pathNumber++ ; my @points = nodes2Coordinates( @way ) ; if ( ! coordsOut (@points) ) { createPath ($pathName, \@points, "definitions") ; my $size = cv('routelabelsize') ; my $font = cv('routelabelfont') ; my $fontFamily = cv('routelabelfontfamily') ; my $color = cv('routelabelcolor') ; my $svgText = createTextSVG ( $fontFamily, $font, $size, $color, undef, undef) ; pathText ($svgText, $label, $pathName, cv('routelabeloffset'), "middle", 50, "routes") ; } } } } # place icons foreach my $w (keys %wayRouteIcons) { my $offset = 0 ; my $nodeNumber = scalar @{$$wayNodesRef{$w}} ; if ($nodeNumber > 1) { my $node = $$wayNodesRef{$w}[int ($nodeNumber / 2)] ; my $num = scalar (keys %{$wayRouteIcons{$w}}) ; $offset = int (-($num-1)* cv('routeicondist') / 2) ; foreach my $iconName (keys %{$wayRouteIcons{$w}}) { my $size = 40 ; placeLabelAndIcon ($$lonRef{$node}, $$latRef{$node}, $offset, $size, "", "", $iconName, $iconSizeX{$iconName}, $iconSizeY{$iconName}, "routes") ; $offset += cv('routeicondist') ; } } } } # -------------------------------------------------------------------------- sub getAllMembers { # # get all members of a relation recursively # takes rel id and nesting level # retruns ref to array with all members # my ($relId, $nestingLevel) = @_ ; my @allMembers = () ; my $maxNestingLevel = 20 ; my ($relationMembersRef, $relationTagsRef) = getRelationPointers() ; if ($nestingLevel > $maxNestingLevel) { print "ERROR/WARNING nesting level of relations too deep. recursion stopped at depth $maxNestingLevel! relId=$relId\n" ; } else { foreach my $member ( @{$$relationMembersRef{$relId}} ) { if ( ($member->[0] eq "way") or ($member->[0] eq "node") ) { push @allMembers, $member ; } if ( $member->[0] eq "relation" ) { my $ref = getAllMembers ($member->[1], $nestingLevel+1) ; push @allMembers, @$ref ; } } } return \@allMembers ; } sub labelFitsWay { my ($refWayNodes, $text, $font, $size) = @_ ; my @wayNodes = @$refWayNodes ; my ($lonRef, $latRef) = getNodePointers() ; # calc waylen my $wayLength = 0 ; # in pixels for (my $i=0; $i<$#wayNodes; $i++) { my ($x1, $y1) = convert ($$lonRef{$wayNodes[$i]}, $$latRef{$wayNodes[$i]}) ; my ($x2, $y2) = convert ($$lonRef{$wayNodes[$i+1]}, $$latRef{$wayNodes[$i+1]}) ; $wayLength += sqrt ( ($x2-$x1)**2 + ($y2-$y1)**2 ) ; } # calc label len my $labelLength = length ($text) * cv('ppc') / 10 * $size ; # in pixels my $fit ; if ($labelLength < $wayLength) { $fit="fit" ; } else { $fit = "NOFIT" ; } # print "labelFitsWay: $fit, $text, labelLen = $labelLength, wayLen = $wayLength\n" ; if ($labelLength < $wayLength) { return 1 ; } else { return 0 ; } } 1 ;