2022-07-28 09:06:48 +00:00
#
# PERL mapweaver module by gary68
#
#
#
#
2022-07-28 10:32:59 +00:00
# Copyright(C)2011, Gerhard Schwanz
2022-07-28 09:06:48 +00:00
#
# 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
2022-07-28 10:32:59 +00:00
# Free Software Foundation; either version 3 of the License, or(at your option)any later version.
2022-07-28 09:06:48 +00:00
#
# 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 <http://www.gnu.org/licenses/>
#
2022-07-28 10:32:59 +00:00
package mwRelations ;
2022-07-28 09:06:48 +00:00
2022-07-28 10:32:59 +00:00
use strict ;
use warnings ;
2022-07-28 09:06:48 +00:00
2022-07-28 10:32:59 +00:00
use mwMap ;
use mwRules ;
use mwFile ;
use mwMisc ;
use mwLabel ;
use mwConfig ;
2022-07-28 09:06:48 +00:00
use vars qw( $VERSION @ISA @EXPORT @EXPORT_OK ) ;
2022-07-28 10:32:59 +00:00
require Exporter ;
2022-07-28 09:06:48 +00:00
2022-07-28 10:32:59 +00:00
@ ISA = qw( Exporter AutoLoader ) ;
2022-07-28 09:06:48 +00:00
2022-07-28 10:32:59 +00:00
@ EXPORT = qw( processRoutes
2022-07-28 09:06:48 +00:00
2022-07-28 10:32:59 +00:00
) ;
2022-07-28 09:06:48 +00:00
2022-07-28 10:32:59 +00:00
my $ pathNumber = 0 ;
2022-07-28 09:06:48 +00:00
2022-07-28 10:32:59 +00:00
my % iconSizeX = ( ) ;
my % iconSizeY = ( ) ;
2022-07-28 09:06:48 +00:00
# --------------------------------------------------------------------------
2022-07-28 10:32:59 +00:00
sub processRoutes { #
2022-07-28 09:06:48 +00:00
# process route data
#
2022-07-28 10:32:59 +00:00
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 ) ;
2022-07-28 09:06:48 +00:00
2022-07-28 10:32:59 +00:00
print "processing routes...\n" ;
2022-07-28 09:06:48 +00:00
# init before relation processing
# get colors per type and set actual index
2022-07-28 10:32:59 +00:00
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 ( ) ;
2022-07-28 09:06:48 +00:00
2022-07-28 10:32:59 +00:00
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 } ) ;
2022-07-28 09:06:48 +00:00
2022-07-28 10:32:59 +00:00
if ( defined $ ruleRef ) {
2022-07-28 09:06:48 +00:00
# new route detected
2022-07-28 10:32:59 +00:00
if ( cv ( 'debug' ) eq "1" ) { print "ROUTE: rule found for $relId, $$ruleRef{'type'}.\n" ; }
2022-07-28 09:06:48 +00:00
# try to get color from relation tags first
#
2022-07-28 10:32:59 +00:00
my $ color = getValue ( "color" , $$ relationTagsRef { $ relId } ) ;
if ( ! defined $ color ) { $ color = getValue ( "colour" , $$ relationTagsRef { $ relId } ) ;
}
2022-07-28 09:06:48 +00:00
# no color yet, then get color from rule
#
2022-07-28 10:32:59 +00:00
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" ; }
2022-07-28 09:06:48 +00:00
# find icon
2022-07-28 10:32:59 +00:00
my $ iconName = getValue ( "ref" , $$ relationTagsRef { $ relId } ) ;
if ( ! defined $ iconName ) { getValue ( "name" , $$ relationTagsRef { $ relId } ) } if ( ! defined $ iconName ) { $ iconName = "" ; }
2022-07-28 09:06:48 +00:00
# look for route icon. svg first, then png
2022-07-28 10:32:59 +00:00
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 ) ;
}
2022-07-28 09:06:48 +00:00
2022-07-28 10:32:59 +00:00
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" ;
2022-07-28 09:06:48 +00:00
}
}
2022-07-28 10:32:59 +00:00
if ( grep /.png/ , $ iconName ) { ( $ x , $ y ) = sizePNG ( $ iconName ) ;
2022-07-28 09:06:48 +00:00
}
2022-07-28 10:32:59 +00:00
$ iconSizeX { $ iconName } = $ x ;
$ iconSizeY { $ iconName } = $ y ;
}
my ( $ label , $ ref ) = createLabel ( $$ relationTagsRef { $ relId } , $$ ruleRef { 'label' } ) ;
2022-07-28 09:06:48 +00:00
2022-07-28 10:32:59 +00:00
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 ;
}
2022-07-28 09:06:48 +00:00
# collect ways
2022-07-28 10:32:59 +00:00
my $ mRef = getAllMembers ( $ relId , 0 ) ;
my @ tempMembers = @$ mRef ;
2022-07-28 09:06:48 +00:00
2022-07-28 10:32:59 +00:00
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 ] ; }
2022-07-28 09:06:48 +00:00
# TODO diversions, shortcuts?
# stops
2022-07-28 10:32:59 +00:00
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 ) ;
2022-07-28 09:06:48 +00:00
# collect labels and icons per way
#
2022-07-28 10:32:59 +00:00
$ wayRouteLabels { $ w } { $ label } = 1 ;
if ( $ iconResult ) {
$ wayRouteIcons { $ w } { $ iconName } = 1 ;
} }
} # rule found
if ( cv ( 'debug' ) eq "1" ) { print "\n" ; } } # rel route
} # relation
2022-07-28 09:06:48 +00:00
# label route ways after all relations have been processed
2022-07-28 10:32:59 +00:00
foreach my $ w ( keys % wayRouteLabels ) { if ( ( defined $$ wayNodesRef { $ w } ) and ( scalar @ { $$ wayNodesRef { $ w } } > 1 ) ) { my $ label = "" ;
foreach my $ l ( keys % { $ wayRouteLabels { $ w } } ) { $ label . = $ l . " " ;
2022-07-28 09:06:48 +00:00
}
2022-07-28 10:32:59 +00:00
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 + + ;
2022-07-28 09:06:48 +00:00
2022-07-28 10:32:59 +00:00
my @ points = nodes2Coordinates ( @ way ) ;
2022-07-28 09:06:48 +00:00
2022-07-28 10:32:59 +00:00
if ( ! coordsOut ( @ points ) ) {
createPath ( $ pathName , \ @ points , "definitions" ) ;
2022-07-28 09:06:48 +00:00
2022-07-28 10:32:59 +00:00
my $ size = cv ( 'routelabelsize' ) ;
my $ font = cv ( 'routelabelfont' ) ;
my $ fontFamily = cv ( 'routelabelfontfamily' ) ;
my $ color = cv ( 'routelabelcolor' ) ;
2022-07-28 09:06:48 +00:00
2022-07-28 10:32:59 +00:00
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' ) ;
} } } }
2022-07-28 09:06:48 +00:00
# --------------------------------------------------------------------------
2022-07-28 10:32:59 +00:00
sub getAllMembers { #
2022-07-28 09:06:48 +00:00
# get all members of a relation recursively
# takes rel id and nesting level
# retruns ref to array with all members
#
2022-07-28 10:32:59 +00:00
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 ;
2022-07-28 09:06:48 +00:00
}
2022-07-28 10:32:59 +00:00
sub labelFitsWay { my ( $ refWayNodes , $ text , $ font , $ size ) = @ _ ;
my @ wayNodes = @$ refWayNodes ;
2022-07-28 09:06:48 +00:00
2022-07-28 10:32:59 +00:00
my ( $ lonRef , $ latRef ) = getNodePointers ( ) ;
2022-07-28 09:06:48 +00:00
# calc waylen
2022-07-28 10:32:59 +00:00
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 ) ;
}
2022-07-28 09:06:48 +00:00
# calc label len
2022-07-28 10:32:59 +00:00
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";
2022-07-28 09:06:48 +00:00
2022-07-28 10:32:59 +00:00
if ( $ labelLength < $ wayLength ) { return 1 ;
} else { return 0 ;
} }
2022-07-28 09:06:48 +00:00
2022-07-28 10:32:59 +00:00
1 ;
2022-07-28 09:06:48 +00:00