mapweaver/mwRules.pm

910 lines
28 KiB
Perl

#
# 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 mwRules ;
use strict ;
use warnings ;
use mwConfig ;
use mwMap ;
use mwMisc ;
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
require Exporter ;
@ISA = qw ( Exporter AutoLoader ) ;
@EXPORT = qw ( readRules
getNodeRule
printNodeRules
getWayRule
printWayRules
getAreaRule
printAreaRules
printValidObjectProperties
getRouteColors
getRouteRule
printRouteRules
adaptRuleSizes
createLegend
) ;
my @validNodeProperties = (
["keyValue","key and value like [amenity=hospital]"],
["color","color of node i.e. [black]"],
["size","size of node i.e. [50]"],
["shape","shape of node [circle|disc|triangle|diamond|rectangle]"],
["svgString","svg format of shape [valid svg string]"],
["circle","add a circle to the node [yes|no]"],
["circleColor","color of the circle i.e. [blue]"],
["circleRadius","circle radius in meters i.e. [1000]"],
["circleThickness","thickness of the circle i.e. [5]"],
["circleSVGString","format of the circle []"],
["disc","add a disc to the node [yes|no]"],
["discColor","color of the disc i.e. [green]"],
["discOpacity","opacity of the disc [0..100]"],
["discRadius","radius of disc in meters i.e. [5000]"],
["discSVGString","format of the disc []"],
["label","label for the node like [name|ref]"],
["labelColor","color for label text i.e. [white]"],
["labelSize","size of label text i.e. [20]"],
["labelFont","font for label"],
["labelFontFamily","font family for label"],
["labelOffset","distance of label to node i.e. [10]"],
["labelBold","bold font for label"],
["labelItalic","italic font for label"],
["labelHalo","halo for label, width in pixels"],
["labelHaloColor","color for halo"],
["labelTransform","perl code for label name transformation"],
["legend","is this object to be listed in map legend? [yes|no]"],
["legendLabel","label text of object in legend i.e. [city]"],
["icon","icon to use for node, overrides shape i.e. [icondir/icon.svg]"],
["iconSize","size of the icon i.e. [40]"],
["shieldName","NOT YET IMPLEMENTED"],
["shieldSize","NOT YET IMPLEMENTED"],
["shieldLabel","NOT YET IMPLEMENTED"],
["fromScale","rule will only applied if scale is bigger than fromScale i.e. [5000]"],
["toScale","rule will only applied if scale is lower than fromScale i.e. [25000]"],
["direxclude","should these objects be excluded from directory? [yes|no]"]
) ;
my @validWayProperties = (
["keyValue","key and value like [highway=residential]"],
["color","color for the way i.e. [gray]"],
["size","size of the way i.e. [15]"],
["dash","svg dash array for the way i.e. [20,20]; old mapgen values are also possible"],
["dashCap","linecap shape for dashes like [butt|round|square]"],
["borderColor","color of the border of the way i.e. [black]"],
["borderSize","thickness os the border i.e. [2]"],
["label","label to be used i.e. [name|ref]"],
["labelColor","color of label text i.e. [blue]"],
["labelSize","size of the label i.e. [20]"],
["labelFont","font for label"],
["labelFontFamily","font family for label"],
["labelOffset","distance of label to middle of way i.e. [5]"],
["labelBold","bold font for label"],
["labelItalic","italic font for label"],
["labelHalo","halo for label, width in pixels"],
["labelHaloColor","color for halo"],
["labelTransform","perl code for label name transformation"],
["legend","is this object to be listed in map legend? [yes|no]"],
["legendLabel","label text of object in legend i.e. [Highway]"],
["svgStringBottom","format of lower way part (i.e. border) []"],
["svgStringTop","format of upper way part []"],
["bottomBorder","NOT YET IMPLEMENTED"],
["fromScale","rule will only applied if scale is bigger than fromScale i.e. [5000]"],
["toScale","rule will only applied if scale is lower than fromScale i.e. [25000]"],
["direxclude","should these objects be excluded from directory? [yes|no]"]
) ;
my @validAreaProperties = (
["keyValue","key and value of object i.e. [amenity=parking]"],
["color","color of area i.e. [lightgrey]"],
["icon","icon for fill pattern to be used i.e. [icondir/parking.svg]"],
["label", "label text to be rendered i.e. [name]"] ,
["labelFont","font for label"],
["labelFontFamily","font family for label"],
["labelColor", "color of label i.e. [green]"] ,
["labelSize", "size of label text i.e. [20]"] ,
["labelBold","bold font for label"],
["labelItalic","italic font for label"],
["labelHalo","halo for label, width in pixels"],
["labelHaloColor","color for halo"],
["labelTransform","perl code for label name transformation"],
["base","should this object be drawn underneath other objects? (applies for landuse residential i.e.) [yes|no]"],
["svgString","format of area []"],
["legend","is this object to be listed in map legend? [yes|no]"],
["legendLabel","label text of object in legend i.e. [Parking]"],
["fromScale","rule will only applied if scale is bigger than fromScale i.e. [5000]"],
["toScale","rule will only applied if scale is lower than fromScale i.e. [25000]"]
) ;
my @validRouteProperties = (
["type","type of route like [bus|hiking]"],
["color","color of route like [red]"],
["size","size of route i.e. [10]"],
["dash","svg dash array style like [20,20]"],
["linecap","linecap style [butt|round|square]"],
["opacity","opacity of the route [0..100]"],
["label","label to be used like [ref]"],
["labelFont","font for label"],
["labelFontFamily","font family for label"],
["labelSize","size of the label i.e. [15]"],
["nodeSize","size of nodes belonging to route i.e. [20]"],
["fromScale","rule will only applied if scale is bigger than fromScale i.e. [5000]"],
["toScale","rule will only applied if scale is lower than fromScale i.e. [25000]"]
) ;
my %nodeRules = () ;
my %areaRules = () ;
my %wayRules = () ;
my %routeRules = () ;
my $nodeNr = 0 ;
my $areaNr = 0 ;
my $wayNr = 0 ;
my $routeNr = 0 ;
my $line ;
my $ruleFile ;
# ---------------------------------------------------------------------------------------
sub printValidObjectProperties {
print "\nValid Object Properties\n" ;
print "\nNodes\n-----\n" ;
foreach my $p (sort {$a->[0] cmp $b->[0]} @validNodeProperties) {
printf "%-20s %s\n", $p->[0], $p->[1] ;
}
print "\nWays\n----\n" ;
foreach my $p (sort {$a->[0] cmp $b->[0]} @validWayProperties) {
printf "%-20s %s\n", $p->[0], $p->[1] ;
}
print "\nAreas\n-----\n" ;
foreach my $p (sort {$a->[0] cmp $b->[0]} @validAreaProperties) {
printf "%-20s %s\n", $p->[0], $p->[1] ;
}
print "\nRoutes\n-----\n" ;
foreach my $p (sort {$a->[0] cmp $b->[0]} @validRouteProperties) {
printf "%-20s %s\n", $p->[0], $p->[1] ;
}
print "\n" ;
}
# ---------------------------------------------------------------------------------------
sub readRules {
my $fileName = cv('style') ;
my $nrr = 0 ; my $wrr = 0 ; my $arr = 0 ; my $rrr = 0 ; my $crr = 0 ;
print "reading rule file $fileName\n" ;
my %vnp = () ;
foreach my $p ( @validNodeProperties ) { $vnp{ lc ( $p->[0] ) } = 1 ; }
my %vwp = () ;
foreach my $p ( @validWayProperties ) { $vwp{ lc ( $p->[0] ) } = 1 ; }
my %vap = () ;
foreach my $p ( @validAreaProperties ) { $vap{ lc ( $p->[0] ) } = 1 ; }
my %vrp = () ;
foreach my $p ( @validRouteProperties ) { $vrp{ lc ( $p->[0] ) } = 1 ; }
openRuleFile($fileName) ;
while (defined $line) {
if ( grep /^rule node/i, $line ) {
$nodeNr++ ;
$nrr++ ;
getRuleLine() ;
# set defaults first
$nodeRules{ $nodeNr }{ 'size' } = cv( 'ruleDefaultNodeSize' ) ;
$nodeRules{ $nodeNr }{ 'color' } = cv( 'ruleDefaultNodeColor' ) ;
$nodeRules{ $nodeNr }{ 'shape' } = cv( 'ruleDefaultNodeShape' ) ;
$nodeRules{ $nodeNr }{ 'label' } = cv( 'ruleDefaultNodeLabel' ) ;
$nodeRules{ $nodeNr }{ 'labelfont' } = cv( 'ruleDefaultNodeLabelFont' ) ;
$nodeRules{ $nodeNr }{ 'labelfontfamily' } = cv( 'ruleDefaultNodeLabelFontFamily' ) ;
$nodeRules{ $nodeNr }{ 'labelsize' } = cv( 'ruleDefaultNodeLabelSize' ) ;
$nodeRules{ $nodeNr }{ 'labelitalic' } = "no" ;
$nodeRules{ $nodeNr }{ 'labelbold' } = "no" ;
$nodeRules{ $nodeNr }{ 'labelhalo' } = 0 ;
$nodeRules{ $nodeNr }{ 'labelhalocolor' } = "white" ;
$nodeRules{ $nodeNr }{ 'labeltransform' } = "" ;
$nodeRules{ $nodeNr }{ 'icon' } = "none" ;
$nodeRules{ $nodeNr }{ 'iconsize' } = cv( 'ruleDefaultNodeIconSize' ) ;
$nodeRules{ $nodeNr }{ 'legend' } = "no" ;
$nodeRules{ $nodeNr }{ 'shieldname' } = "none" ;
$nodeRules{ $nodeNr }{ 'svgstring' } = "" ;
$nodeRules{ $nodeNr }{ 'legend' } = "no" ;
$nodeRules{ $nodeNr }{ 'legendlabel' } = "" ;
$nodeRules{ $nodeNr }{ 'circle' } = 'no' ;
$nodeRules{ $nodeNr }{ 'circlecolor' } = 'black' ;
$nodeRules{ $nodeNr }{ 'circleradius' } = 1000 ;
$nodeRules{ $nodeNr }{ 'circlethickness' } = 10 ;
$nodeRules{ $nodeNr }{ 'circlesvgstring' } = "" ;
$nodeRules{ $nodeNr }{ 'disc' } = 'no' ;
$nodeRules{ $nodeNr }{ 'disccolor' } = 'red' ;
$nodeRules{ $nodeNr }{ 'discopacity' } = 50 ;
$nodeRules{ $nodeNr }{ 'discradius' } = 1000 ;
$nodeRules{ $nodeNr }{ 'discradius' } = 1000 ;
$nodeRules{ $nodeNr }{ 'discsvgstring' } = '' ;
$nodeRules{ $nodeNr }{ 'fromscale' } = cv ('ruledefaultnodefromscale') ;
$nodeRules{ $nodeNr }{ 'toscale' } = cv ('ruledefaultnodetoscale') ;
$nodeRules{ $nodeNr }{ 'direxclude' } = cv('direxcludedefault') ;
while ( ( defined $line) and ( ! grep /^rule/i, $line) ) {
my ($k, $v) = ( $line =~ /(.+?)=(.+)/ ) ;
if ( ( ! defined $k ) or ( ! defined $v ) ) {
print "WARNING: could not parse rule line: $line" ;
}
else {
$k = lc ( $k ) ;
$nodeRules{ $nodeNr }{ $k } = $v ;
if ( ! defined $vnp{$k} ) { print "WARNING: $k is not a valid node property!\n" ; }
}
getRuleLine() ;
}
if ( ! defined $nodeRules{ $nodeNr }{ 'keyvalue' } ) { die "ERROR: rule without keyValue detected!\n" ; }
} # node
elsif ( grep /^rule way/i, $line ) {
$wayNr++ ;
$wrr++ ;
getRuleLine() ;
# set defaults first
$wayRules{ $wayNr }{ 'label' } = cv( 'ruleDefaultWayLabel' ) ;
$wayRules{ $wayNr }{ 'labelfont' } = cv( 'ruleDefaultWayLabelFont' ) ;
$wayRules{ $wayNr }{ 'labelfontfamily' } = cv( 'ruleDefaultWayLabelFontFamily' ) ;
$wayRules{ $wayNr }{ 'labelsize' } = cv( 'ruleDefaultWayLabelSize' ) ;
$wayRules{ $wayNr }{ 'labelcolor' } = cv( 'ruleDefaultWayLabelColor' ) ;
$wayRules{ $wayNr }{ 'labelfont' } = cv( 'ruleDefaultWayLabelFont' ) ;
$wayRules{ $wayNr }{ 'labeloffset' } = cv( 'ruleDefaultWayLabelOffset' ) ;
$wayRules{ $wayNr }{ 'labelitalic' } = "no" ;
$wayRules{ $wayNr }{ 'labelbold' } = "no" ;
$wayRules{ $wayNr }{ 'labelhalo' } = 0 ;
$wayRules{ $wayNr }{ 'labelhalocolor' } = "white" ;
$wayRules{ $wayNr }{ 'labeltransform' } = "" ;
$wayRules{ $wayNr }{ 'legend' } = "no" ;
$wayRules{ $wayNr }{ 'legendlabel' } = "" ;
$wayRules{ $wayNr }{ 'color' } = cv( 'ruleDefaultWayColor' ) ;
$wayRules{ $wayNr }{ 'size' } = cv( 'ruleDefaultWaySize' ) ;
$wayRules{ $wayNr }{ 'bordercolor' } = cv( 'ruleDefaultWayBorderColor' ) ;
$wayRules{ $wayNr }{ 'bordersize' } = cv( 'ruleDefaultWayBorderSize' ) ;
$wayRules{ $wayNr }{ 'dash' } = cv( 'ruleDefaultWayDash' ) ;
$wayRules{ $wayNr }{ 'dashcap' } = cv( 'ruleDefaultWayDashCap' ) ;
$wayRules{ $wayNr }{ 'svgstringtop' } = "" ;
$wayRules{ $wayNr }{ 'svgstringbottom' } = "" ;
$wayRules{ $wayNr }{ 'fromscale' } = cv ('ruledefaultwayfromscale') ;
$wayRules{ $wayNr }{ 'toscale' } = cv ('ruledefaultwaytoscale') ;
$wayRules{ $wayNr }{ 'direxclude' } = cv('direxcludedefault') ;
while ( ( defined $line) and ( ! grep /^rule/i, $line) ) {
my ($k, $v) = ( $line =~ /(.+?)=(.+)/ ) ;
if ( ( ! defined $k ) or ( ! defined $v ) ) {
print "WARNING: could not parse rule line: $line" ;
}
else {
$k = lc ( $k ) ;
$wayRules{ $wayNr }{ $k } = $v ;
if ( ! defined $vwp{$k} ) { print "WARNING: $k is not a valid way property!\n" ; }
}
getRuleLine() ;
}
if ( ! defined $wayRules{ $wayNr }{ 'keyvalue' } ) { die "ERROR: rule without keyValue detected!\n" ; }
} # way
elsif ( grep /^rule area/i, $line ) {
$areaNr++ ;
$arr++ ;
getRuleLine() ;
# set defaults first
$areaRules{ $areaNr }{ 'label' } = "none" ;
$areaRules{ $areaNr }{ 'labelfont' } = cv( 'ruleDefaultAreaLabelFont' ) ;
$areaRules{ $areaNr }{ 'labelfontfamily' } = cv( 'ruleDefaultAreaLabelFontFamily' ) ;
$areaRules{ $areaNr }{ 'labelcolor' } = "black" ;
$areaRules{ $areaNr }{ 'labelsize' } = 30 ;
$areaRules{ $areaNr }{ 'labelitalic' } = "no" ;
$areaRules{ $areaNr }{ 'labelbold' } = "no" ;
$areaRules{ $areaNr }{ 'labelhalo' } = 0 ;
$areaRules{ $areaNr }{ 'labelhalocolor' } = "white" ;
$areaRules{ $areaNr }{ 'labeltransform' } = "" ;
$areaRules{ $areaNr }{ 'color' } = cv( 'ruleDefaultAreaColor') ;
$areaRules{ $areaNr }{ 'icon' } = "none" ;
$areaRules{ $areaNr }{ 'base' } = "no" ;
$areaRules{ $areaNr }{ 'svgstring' } = "" ;
$areaRules{ $areaNr }{ 'minsize' } = cv ('ruledefaultareaminsize') ;
$areaRules{ $areaNr }{ 'legend' } = "no" ;
$areaRules{ $areaNr }{ 'legendlabel' } = "" ;
$areaRules{ $areaNr }{ 'fromscale' } = cv ('ruledefaultareafromscale') ;
$areaRules{ $areaNr }{ 'toscale' } = cv ('ruledefaultareatoscale') ;
while ( ( defined $line) and ( ! grep /^rule/i, $line) ) {
my ($k, $v) = ( $line =~ /(.+?)=(.+)/ ) ;
if ( ( ! defined $k ) or ( ! defined $v ) ) {
print "WARNING: could not parse rule line: $line" ;
}
else {
$k = lc ( $k ) ;
$areaRules{ $areaNr }{ $k } = $v ;
if ( ! defined $vap{$k} ) { print "WARNING: $k is not a valid area property!\n" ; }
if ($k eq "icon") { mwMap::addAreaIcon ($v) ; }
}
getRuleLine() ;
}
if ( ! defined $areaRules{ $areaNr }{ 'keyvalue' } ) { die "ERROR: rule without keyValue detected!\n" ; }
} # area
elsif ( grep /^rule route/i, $line ) {
$routeNr++ ;
$rrr++ ;
getRuleLine() ;
# set defaults first
$routeRules{ $routeNr }{ 'color' } = cv( 'ruleDefaultRouteColor' ) ;
$routeRules{ $routeNr }{ 'size' } = cv( 'ruleDefaultRouteSize' ) ;
$routeRules{ $routeNr }{ 'dash' } = cv( 'ruleDefaultRouteDash' ) ;
$routeRules{ $routeNr }{ 'linecap' } = cv( 'ruleDefaultRouteLinecap' ) ;
$routeRules{ $routeNr }{ 'opacity' } = cv( 'ruleDefaultRouteOpacity' ) ;
$routeRules{ $routeNr }{ 'label' } = cv( 'ruleDefaultRouteLabel' ) ;
# $routeRules{ $routeNr }{ 'labelfont' } = cv( 'ruleDefaultRouteLabelFont' ) ;
# $routeRules{ $routeNr }{ 'labelfontfamily' } = cv( 'ruleDefaultRouteLabelFontFamily' ) ;
# $routeRules{ $routeNr }{ 'labelsize' } = cv( 'ruleDefaultRouteLabelSize' ) ;
$routeRules{ $routeNr }{ 'nodesize' } = cv( 'ruleDefaultRouteNodeSize' ) ;
$routeRules{ $routeNr }{ 'fromscale' } = cv( 'ruleDefaultRouteFromScale' ) ;
$routeRules{ $routeNr }{ 'toscale' } = cv( 'ruleDefaultRouteToScale' ) ;
while ( ( defined $line) and ( ! grep /^rule/i, $line) ) {
my ($k, $v) = ( $line =~ /(.+?)=(.+)/ ) ;
if ( ( ! defined $k ) or ( ! defined $v ) ) {
print "WARNING: could not parse rule line: $line" ;
}
else {
$k = lc ( $k ) ;
$routeRules{ $routeNr }{ $k } = $v ;
if ( ! defined $vrp{$k} ) { print "WARNING: $k is not a valid route property!\n" ; }
}
getRuleLine() ;
}
if ( ! defined $routeRules{ $routeNr }{ 'type' } ) { die "ERROR: route rule without type detected!\n" ; }
} # route
elsif ( grep /^rule config/i, $line ) {
$crr++ ;
my ($key, $value) = ( $line =~ /^rule config\s+(.+)=(.+)/i ) ;
if ( (defined $key) and (defined $value) ) {
setConfigValue ($key, $value) ;
if ( cv('debug') eq "1" ) {
print "RULES: config changed $key=$value\n" ;
}
}
getRuleLine() ;
} # config
else {
getRuleLine() ;
}
}
close ($ruleFile) ;
print "rules read: $nrr nodes, $wrr ways, $arr areas, $rrr routes and $crr configs\n\n" ;
}
sub getNodeRule {
# takes tagref and returns hashref to rule properties
my $tagRef = shift ;
my $scale = getScale() ;
if ( cv('rulescaleset') != 0 ) { $scale = cv('rulescaleset') ; }
# print "GNR: scale: $scale\n" ;
my $ruleFound ; undef $ruleFound ;
# print "\n" ;
RUL2: foreach my $rule ( sort { $a <=> $b } keys %nodeRules) {
# print "rule $rule\n" ;
if ( ( $nodeRules{$rule}{'fromscale'} <= $scale) and ( $nodeRules{$rule}{'toscale'} >= $scale) ) {
my @kvs = split /;/, $nodeRules{$rule}{'keyvalue'} ;
my $allValid = 1 ;
RUL1: foreach my $kv1 ( @kvs ) { # for each needed
my ($k, $v) = ( $kv1 =~ /(.+)=(.+)/ ) ;
# print " looking for $k=$v\n" ;
my $found = 0 ;
RUL3: foreach my $tag ( @$tagRef) {
# print " actual kvs: $tag->[0]=$tag->[1]\n" ;
if ( ( $tag->[0] eq $k) and ( ( $tag->[1] eq $v) or ( $v eq "*") ) ) {
$found = 1 ;
# print " FOUND\n" ;
last RUL3 ;
}
} # tags
if ( ! $found ) {
$allValid = 0 ;
last RUL1 ;
}
} # kv1
if ( $allValid ) {
# print "ALL VALID\n" ;
# return the first rule found
$ruleFound = \%{ $nodeRules{ $rule } } ;
last RUL2 ;
}
} # scale
} # all rules
return ($ruleFound) ;
}
sub printNodeRules {
foreach my $n ( sort { $a <=> $b } keys %nodeRules) {
print "node rule $n\n" ;
foreach my $v (sort keys %{$nodeRules{$n}}) {
print " $v=$nodeRules{$n}{$v}\n" ;
}
print "\n" ;
}
}
# ---------------------------------------------------------------------------------------
sub getWayRule {
# takes tagref and returns hashref to rule properties
my $tagRef = shift ;
my $scale = getScale() ;
if ( cv('rulescaleset') != 0 ) { $scale = cv('rulescaleset') ; }
my $ruleFound ; undef $ruleFound ;
RUL5: foreach my $rule ( sort { $a <=> $b } keys %wayRules) {
# print "rule $rule\n" ;
if ( ( $wayRules{$rule}{'fromscale'} <= $scale) and ( $wayRules{$rule}{'toscale'} >= $scale) ) {
my @kvs = split /;/, $wayRules{$rule}{'keyvalue'} ;
my $allValid = 1 ;
RUL4: foreach my $kv1 ( @kvs ) { # for each needed
my ($k, $v) = ( $kv1 =~ /(.+)=(.+)/ ) ;
# print " looking for $k=$v\n" ;
my $found = 0 ;
RUL6: foreach my $tag ( @$tagRef) {
# print " actual kvs: $tag->[0]=$tag->[1]\n" ;
if ( ( $tag->[0] eq $k) and ( ( $tag->[1] eq $v) or ( $v eq "*") ) ) {
$found = 1 ;
# print " FOUND\n" ;
last RUL6 ;
}
} # tags
if ( ! $found ) {
$allValid = 0 ;
last RUL4 ;
}
} # kv1
if ( $allValid ) {
# print "ALL VALID\n" ;
# return the first rule found
$ruleFound = \%{ $wayRules{ $rule } } ;
last RUL5 ;
}
} # scale
} # all rules
return ($ruleFound) ;
}
sub printWayRules {
foreach my $n ( sort { $a <=> $b } keys %wayRules) {
print "way rule $n\n" ;
foreach my $v (sort keys %{$wayRules{$n}}) {
print " $v=$wayRules{$n}{$v}\n" ;
}
print "\n" ;
}
}
# ---------------------------------------------------------------------------------------
sub getAreaRule {
# takes tagref and returns hashref to rule properties
my $tagRef = shift ;
my $scale = getScale() ;
if ( cv('rulescaleset') != 0 ) { $scale = cv('rulescaleset') ; }
my $ruleFound ; undef $ruleFound ;
RUL8: foreach my $rule ( sort { $a <=> $b } keys %areaRules) {
# print "rule $rule\n" ;
if ( ( $areaRules{$rule}{'fromscale'} <= $scale) and ( $areaRules{$rule}{'toscale'} >= $scale) ) {
my @kvs = split /;/, $areaRules{$rule}{'keyvalue'} ;
my $allValid = 1 ;
RUL7: foreach my $kv1 ( @kvs ) { # for each needed
my ($k, $v) = ( $kv1 =~ /(.+)=(.+)/ ) ;
# print " looking for $k=$v\n" ;
my $found = 0 ;
RUL9: foreach my $tag ( @$tagRef) {
# print " actual kvs: $tag->[0]=$tag->[1]\n" ;
if ( ( $tag->[0] eq $k) and ( ( $tag->[1] eq $v) or ( $v eq "*") ) ) {
$found = 1 ;
# print " FOUND\n" ;
last RUL9 ;
}
} # tags
if ( ! $found ) {
$allValid = 0 ;
last RUL7 ;
}
} # kv1
if ( $allValid ) {
# print "ALL VALID\n" ;
# return the first rule found
$ruleFound = \%{ $areaRules{ $rule } } ;
last RUL8 ;
}
} # scale
} # all rules
return ($ruleFound) ;
}
sub printAreaRules {
foreach my $n ( sort { $a <=> $b } keys %areaRules) {
print "area rule $n\n" ;
foreach my $v (sort keys %{$areaRules{$n}}) {
print " $v=$areaRules{$n}{$v}\n" ;
}
print "\n" ;
}
}
# --------------------------------------------------------------------------------
sub getRouteRule {
my $tagRef = shift ;
my $scale = getScale() ;
if ( cv('rulescaleset') != 0 ) { $scale = cv('rulescaleset') ; }
my $ruleFound ; undef $ruleFound ;
my $type = getValue ("route", $tagRef) ;
if (defined $type) {
# print " GRR: $type \n" ;
RULA: foreach my $r ( sort { $a <=> $b } keys %routeRules) {
# print " GRR: $routeRules{$r}{'type'}\n" ;
if ($routeRules{$r}{'type'} eq $type) {
if ( ( $routeRules{$r}{'fromscale'} <= $scale) and ( $routeRules{$r}{'toscale'} >= $scale) ) {
$ruleFound = \%{ $routeRules{ $r } } ;
last RULA ;
}
}
}
}
return $ruleFound ;
}
sub getRouteColors {
my %routeColors = () ;
foreach my $n (keys %routeRules) {
my $type = $routeRules{$n}{'type'} ;
my $color = $routeRules{$n}{'color'} ;
@{$routeColors{$type}} = split ( /;/, $color ) ;
}
return \%routeColors ;
}
sub printRouteRules {
foreach my $n ( sort { $a <=> $b } keys %routeRules) {
print "route rule $n\n" ;
foreach my $v (sort keys %{$routeRules{$n}}) {
print " $v=$routeRules{$n}{$v}\n" ;
}
print "\n" ;
}
}
# --------------------------------------------------------------------------------
sub openRuleFile {
my $fileName = shift ;
open ($ruleFile, "<", $fileName) or die ("ERROR: could not open rule file $fileName\n") ;
getRuleLine() ;
}
sub getRuleLine {
$line = <$ruleFile> ;
if (defined $line) {
$line =~ s/\r//g ; # remove dos/win char at line end
}
while ( (defined $line) and ( (length $line < 2) or ( grep /^comment/i, $line) or ( grep /^\#/i, $line) ) ) {
$line = <$ruleFile> ;
}
return $line ;
}
sub adaptRuleSizes {
foreach my $r ( keys %nodeRules ) {
foreach my $p ( qw (iconSize labelOffset labelSize shieldSize size) ) {
if ( defined $nodeRules{ $r }{ $p } ) {
if ( grep /:/, $nodeRules{ $r }{ $p } ) {
my $old = $nodeRules{ $r }{ $p } ;
my $new = scaleSize ($nodeRules{ $r }{ $p }, $nodeRules{ $r }{ 'fromscale' }, $nodeRules{ $r }{ 'toscale' }) ;
$nodeRules{ $r }{ $p } = $new ;
if ( cv('debug') eq "1" ) {
print "RULES/scale/node: $old -> $new\n" ;
}
}
}
}
}
foreach my $r ( keys %wayRules ) {
foreach my $p ( qw (bordersize labelsize labeloffset size ) ) {
if ( defined $wayRules{ $r }{ $p } ) {
if ( grep /:/, $wayRules{ $r }{ $p } ) {
my $kv = $wayRules{ $r }{ 'keyvalue' } ;
my $old = $wayRules{ $r }{ $p } ;
my $new = 0 ;
$new = scaleSize ($wayRules{ $r }{ $p }, $wayRules{ $r }{ 'fromscale' }, $wayRules{ $r }{ 'toscale' }) ;
$wayRules{ $r }{ $p } = $new ;
if ( cv('debug') eq "1" ) {
print "RULES/scale/way: $kv $p $old to $new\n" ;
}
}
}
}
}
}
sub scaleSize {
my ($str, $fromScale, $toScale) = @_ ;
my @tmp = split /:/, $str ;
my $lower = $tmp[0] ;
my $upper = $tmp[1] ;
my $newSize = 0 ;
my $scale = getScale() ;
if ( cv('rulescaleset') ne "0" ) { $scale = cv('rulescaleset') } ;
if ( $scale < $fromScale) {
$newSize = $upper ;
}
elsif ( $scale > $toScale ) {
$newSize = $lower ;
}
else {
my $percent = ( $scale - $fromScale ) / ($toScale - $fromScale) ;
$newSize = $upper - $percent * ($upper - $lower) ;
}
$newSize = int ( $newSize * 10 ) / 10 ;
return $newSize ;
}
sub createLegend {
# TODO Auto size
my $nx = 80 ;
my $ny = 80 ;
my $ey = 1.5 * $ny ;
my $sx = 700 ;
my $tx = 200 ;
my $ty = $ey / 2 ;
my $fs = 40 ;
my $actualLine = 0 ;
my $preCount = 0 ;
foreach my $n (keys %nodeRules) {
if ( $nodeRules{$n}{"legend"} eq "yes" ) { $preCount++ ; }
}
foreach my $n (keys %wayRules) {
if ( $wayRules{$n}{"legend"} eq "yes" ) { $preCount++ ; }
}
foreach my $n (keys %areaRules) {
if ( $areaRules{$n}{"legend"} eq "yes" ) { $preCount++ ; }
}
if ( cv('debug') eq "1" ) { print "LEGEND: $preCount elements found\n" ; }
my $sy = $preCount * $ey ;
addToLayer ("definitions", "<g id=\"legenddef\" width=\"$sx\" height=\"$sy\" >") ;
my $color = "white" ;
my $svgString = "fill=\"$color\"" ;
drawRect (0, 0, $sx, $sy, 0, $svgString, "definitions") ;
foreach my $n (keys %nodeRules) {
if ( $nodeRules{$n}{"legend"} eq "yes" ) {
my $x = $nx ;
my $y = $actualLine * $ey + $ny ;
if ( ($nodeRules{$n}{'size'} > 0) and ($nodeRules{$n}{'icon'} eq "none") ) {
my $svgString = "" ;
if ( $nodeRules{$n}{'svgstring'} ne "" ) {
$svgString = $nodeRules{$n}{'svgstring'} ;
}
else {
$svgString = "fill=\"$nodeRules{$n}{'color'}\"" ;
}
if ( $nodeRules{$n}{'shape'} eq "circle") {
drawCircle ($x, $y, 0, $nodeRules{$n}{'size'}, 0, $svgString, 'definitions') ;
}
elsif ( $nodeRules{$n}{'shape'} eq "square") {
drawSquare ($x, $y, 0, $nodeRules{$n}{'size'}, 0, $svgString, 'definitions') ;
}
elsif ( $nodeRules{$n}{'shape'} eq "triangle") {
drawTriangle ($x, $y, 0, $nodeRules{$n}{'size'}, 0, $svgString, 'definitions') ;
}
elsif ( $nodeRules{$n}{'shape'} eq "diamond") {
drawDiamond ($x, $y, 0, $nodeRules{$n}{'size'}, 0, $svgString, 'definitions') ;
}
my $textSvgString = createTextSVG ( cv('elementFontFamily'), cv('elementFont'), $fs, "black", undef, undef ) ;
drawText ($tx, ($actualLine+0.5) * $ey + $fs/2, 0, $nodeRules{$n}{'legendlabel'}, $textSvgString, "definitions") ;
}
else {
# TODO icon
}
$actualLine ++ ;
}
}
foreach my $w (keys %wayRules) {
if ( $wayRules{$w}{"legend"} eq "yes" ) {
my ($x1, $x2) ;
$x1 = 0.5 * $nx ;
$x2 = 1.5 * $nx ;
my $y = $actualLine * $ey + $ny ;
my ($svg1, $layer1, $svg2, $layer2) = mwWays::createWayParameters ($wayRules{$w}, 0, 0, 0) ;
my @coords = ($x1, $y, $x2, $y) ;
if ($svg2 ne "") {
drawWay ( \@coords, 0, $svg2, "definitions", undef ) ;
}
drawWay ( \@coords, 0, $svg1, "definitions", undef ) ;
my $textSvgString = createTextSVG ( cv('elementFontFamily'), cv('elementFont'), $fs, "black", undef, undef ) ;
drawText ($tx, ($actualLine+0.5)*$ey + $fs/2, 0, $wayRules{$w}{'legendlabel'}, $textSvgString, "definitions") ;
$actualLine++ ;
}
}
foreach my $a (keys %areaRules) {
if ( $areaRules{$a}{"legend"} eq "yes" ) {
my ($x1, $x2) ;
my ($y1, $y2) ;
$x1 = 0.7 * $nx ;
$x2 = 1.3 * $nx ;
$y1 = $actualLine * $ey + 0.7 * $ny ;
$y2 = $actualLine * $ey + 1.3 * $ny ;
my $color = $areaRules{$a}{'color'} ;
my $icon = $areaRules{$a}{'icon'} ;
my $base = $areaRules{$a}{'base'} ;
my $svgString = $areaRules{$a}{'svgstring'} ;
if ( ($svgString eq "") and ($icon eq "none") ) {
$svgString = "fill=\"$color\" " ;
}
my @coords = ([$x1, $y1, $x2, $y1, $x2, $y2, $x1, $y2, $x1, $y1]) ;
drawArea ($svgString, $icon, \@coords, 0, "definitions") ;
my $textSvgString = createTextSVG ( cv('elementFontFamily'), cv('elementFont'), $fs, "black", undef, undef ) ;
drawText ($tx, ($actualLine+0.5)*$ey + $fs/2, 0, $areaRules{$a}{'legendlabel'}, $textSvgString, "definitions") ;
$actualLine++ ;
}
}
addToLayer ("definitions", "</g>") ;
my $posX = 0 ;
my $posY = 0 ;
my ($sizeX, $sizeY) = getDimensions() ;
if ( cv('legend') eq "2") {
$posX = $sizeX - $sx ;
$posY = 0 ;
}
if ( cv('legend') eq "3") {
$posX = 0 ;
$posY = $sizeY - $sy ;
}
if ( cv('legend') eq "4") {
$posX = $sizeX - $sx ;
$posY = $sizeY - $sy ;
}
if ( (cv('legend') >=1) and (cv('legend')<=4) ) {
addToLayer ("legend", "<use x=\"$posX\" y=\"$posY\" xlink:href=\"#legenddef\" />") ;
}
elsif (cv('legend') == 5) {
# separate file
createLegendFile($sx, $sy, "_legend", "#legenddef") ;
}
}
1 ;