mapweaver/mwRelations.pm

327 lines
9.7 KiB
Perl
Raw Normal View History

2022-07-28 09:06:48 +00:00
#
# 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 <http://www.gnu.org/licenses/>
#
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 ;