329 lines
10 KiB
Perl
329 lines
10 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 mwLabel ;
|
||
|
|
||
|
use strict ;
|
||
|
use warnings ;
|
||
|
|
||
|
use mwConfig ;
|
||
|
use mwMap ;
|
||
|
# use mwMisc ;
|
||
|
use mwOccupy ;
|
||
|
|
||
|
my $labelPathId = 0 ;
|
||
|
|
||
|
my @lines = () ;
|
||
|
|
||
|
my $numIconsMoved = 0 ;
|
||
|
my $numLabels = 0 ;
|
||
|
my $numIcons = 0 ;
|
||
|
my $numLabelsOmitted = 0 ;
|
||
|
my $numLabelsMoved = 0 ;
|
||
|
my $numIconsOmitted = 0 ;
|
||
|
|
||
|
my %poiHash = () ;
|
||
|
|
||
|
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
|
||
|
|
||
|
require Exporter ;
|
||
|
|
||
|
@ISA = qw ( Exporter AutoLoader ) ;
|
||
|
|
||
|
@EXPORT = qw (
|
||
|
placeLabelAndIcon
|
||
|
addToPoiHash
|
||
|
getPoiHash
|
||
|
) ;
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
sub placeLabelAndIcon {
|
||
|
#
|
||
|
# intelligent icon and label placement alg.
|
||
|
#
|
||
|
my ($lon, $lat, $offset, $thickness, $text, $svgText, $icon, $iconSizeX, $iconSizeY, $layer) = @_ ;
|
||
|
|
||
|
if (cv('debug') eq "1") { print "PLAI: $lon, $lat, $offset, $thickness, $text, $svgText, $icon, $iconSizeX, $iconSizeY, $layer\n" ; }
|
||
|
|
||
|
my ($x, $y) = mwMap::convert ($lon, $lat) ; # center !
|
||
|
|
||
|
if ( ! coordsOut ($x, $y) ) {
|
||
|
|
||
|
$y = $y + $offset ;
|
||
|
|
||
|
my ($ref) = splitLabel ($text) ;
|
||
|
my (@lines) = @$ref ;
|
||
|
my $numLines = scalar @lines ;
|
||
|
my $maxTextLenPix = 0 ;
|
||
|
my $orientation = "" ;
|
||
|
my $lineDist = cv ('linedist') ; ;
|
||
|
my $tries = 0 ;
|
||
|
my $allowIconMove = cv ('allowiconmove') ;
|
||
|
|
||
|
my ($textSize) = ( $svgText =~ /font-size=\"(\d+)\"/ ) ;
|
||
|
if ( ! defined $textSize ) { die ("ERROR: font size could not be determined from svg format string \"$svgText\"\n") ; }
|
||
|
|
||
|
foreach my $line (@lines) {
|
||
|
my $len = length ($line) * cv('ppc') / 10 * $textSize ; # in pixels
|
||
|
if ($len > $maxTextLenPix) { $maxTextLenPix = $len ; }
|
||
|
}
|
||
|
my $spaceTextX = $maxTextLenPix ;
|
||
|
my $spaceTextY = $numLines * ($lineDist+$textSize) ;
|
||
|
|
||
|
|
||
|
if ($icon ne "none") {
|
||
|
$numIcons++ ;
|
||
|
# space for icon?
|
||
|
my $sizeX1 = $iconSizeX ; if ($sizeX1 == 0) { $sizeX1 = 20 ; }
|
||
|
my $sizeY1 = $iconSizeY ; if ($sizeY1 == 0) { $sizeY1 = 20 ; }
|
||
|
my $iconX = $x - $sizeX1/2 ; # top left corner
|
||
|
my $iconY = $y - $sizeY1/2 ;
|
||
|
|
||
|
my @shifts = (0) ;
|
||
|
if ($allowIconMove eq "1") {
|
||
|
@shifts = ( 0, -15, 15 ) ;
|
||
|
}
|
||
|
my $posFound = 0 ; my $posCount = 0 ;
|
||
|
my ($iconAreaX1, $iconAreaY1, $iconAreaX2, $iconAreaY2) ;
|
||
|
LABAB: foreach my $xShift (@shifts) {
|
||
|
foreach my $yShift (@shifts) {
|
||
|
$posCount++ ;
|
||
|
if ( ( ! boxAreaOccupied ($iconX+$xShift, $iconY+$sizeY1+$yShift, $iconX+$sizeX1+$xShift, $iconY+$yShift) ) or ( cv('forcenodes') eq "1" ) ) {
|
||
|
placeIcon ($iconX+$xShift, $iconY+$yShift, $icon, $sizeX1, $sizeY1, "nodes") ;
|
||
|
$iconAreaX1 = $iconX+$xShift ;
|
||
|
$iconAreaY1 = $iconY+$sizeY1+$yShift ;
|
||
|
$iconAreaX2 = $iconX+$sizeX1+$xShift ;
|
||
|
$iconAreaY2 = $iconY+$yShift ;
|
||
|
|
||
|
$posFound = 1 ;
|
||
|
if ($posCount > 1) { $numIconsMoved++ ; }
|
||
|
$iconX = $iconX + $xShift ; # for later use with label
|
||
|
$iconY = $iconY + $yShift ;
|
||
|
last LABAB ;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if ($posFound == 1) {
|
||
|
|
||
|
# label text?
|
||
|
if ($text ne "") {
|
||
|
$numLabels++ ;
|
||
|
|
||
|
|
||
|
$sizeX1 += 1 ; $sizeY1 += 1 ;
|
||
|
|
||
|
my ($x1, $x2, $y1, $y2) ;
|
||
|
# $x, $y centered
|
||
|
# yes, check if space for label, choose position, draw
|
||
|
# no, count omitted text
|
||
|
|
||
|
my @positions = () ; my $positionFound = 0 ;
|
||
|
# pos 1 centered below
|
||
|
$x1 = $x - $spaceTextX/2 ; $x2 = $x + $spaceTextX/2 ; $y1 = $y + $sizeY1/2 + $spaceTextY ; $y2 = $y + $sizeY1/2 ; $orientation = "centered" ;
|
||
|
push @positions, [$x1, $x2, $y1, $y2, $orientation] ;
|
||
|
|
||
|
# pos 2/3 to the right, bottom, top
|
||
|
$x1 = $x + $sizeX1/2 ; $x2 = $x + $sizeX1/2 + $spaceTextX ; $y1 = $y + $sizeY1/2 ; $y2 = $y1 - $spaceTextY ; $orientation = "left" ;
|
||
|
push @positions, [$x1, $x2, $y1, $y2, $orientation] ;
|
||
|
$x1 = $x + $sizeX1/2 ; $x2 = $x + $sizeX1/2 + $spaceTextX ; $y2 = $y - $sizeY1/2 ; $y1 = $y2 + $spaceTextY ; $orientation = "left" ;
|
||
|
push @positions, [$x1, $x2, $y1, $y2, $orientation] ;
|
||
|
|
||
|
# pos 4 centered upon
|
||
|
$x1 = $x - $spaceTextX/2 ; $x2 = $x + $spaceTextX/2 ; $y1 = $y - $sizeY1/2 ; $y2 = $y - $sizeY1/2 - $spaceTextY ; $orientation = "centered" ;
|
||
|
push @positions, [$x1, $x2, $y1, $y2, $orientation] ;
|
||
|
|
||
|
# pos 5/6 to the right, below and upon
|
||
|
$x1 = $x + $sizeX1/2 ; $x2 = $x + $sizeX1/2 + $spaceTextX ; $y2 = $y + $sizeY1/2 ; $y1 = $y2 + $spaceTextY ; $orientation = "left" ;
|
||
|
push @positions, [$x1, $x2, $y1, $y2, $orientation] ;
|
||
|
$x1 = $x + $sizeX1/2 ; $x2 = $x + $sizeX1/2 + $spaceTextX ; $y1 = $y - $sizeY1/2 ; $y2 = $y1 - $spaceTextY ; $orientation = "left" ;
|
||
|
push @positions, [$x1, $x2, $y1, $y2, $orientation] ;
|
||
|
|
||
|
# left normal, bottom, top
|
||
|
$x1 = $x - $sizeX1/2 - $spaceTextX ; $x2 = $x - $sizeX1/2 ; $y1 = $y + $sizeY1/2 ; $y2 = $y1 - $spaceTextY ; $orientation = "right" ;
|
||
|
push @positions, [$x1, $x2, $y1, $y2, $orientation] ;
|
||
|
$x1 = $x - $sizeX1/2 - $spaceTextX ; $x2 = $x - $sizeX1/2 ; $y2 = $y - $sizeY1/2 ; $y1 = $y2 + $spaceTextY ; $orientation = "right" ;
|
||
|
push @positions, [$x1, $x2, $y1, $y2, $orientation] ;
|
||
|
|
||
|
# left corners, bottom, top
|
||
|
$x1 = $x - $sizeX1/2 - $spaceTextX ; $x2 = $x - $sizeX1/2 ; $y2 = $y + $sizeY1/2 ; $y1 = $y2 + $spaceTextY ; $orientation = "right" ;
|
||
|
push @positions, [$x1, $x2, $y1, $y2, $orientation] ;
|
||
|
$x1 = $x - $sizeX1/2 - $spaceTextX ; $x2 = $x - $sizeX1/2 ; $y1 = $y - $sizeY1/2 ; $y2 = $y1 - $spaceTextY ; $orientation = "right" ;
|
||
|
push @positions, [$x1, $x2, $y1, $y2, $orientation] ;
|
||
|
|
||
|
|
||
|
$tries = 0 ;
|
||
|
LABB: foreach my $pos (@positions) {
|
||
|
$tries++ ;
|
||
|
|
||
|
$positionFound = checkAndDrawText ($pos->[0], $pos->[1], $pos->[2], $pos->[3], $pos->[4], \@lines, $svgText, $layer) ;
|
||
|
|
||
|
if ($positionFound == 1) {
|
||
|
last LABB ;
|
||
|
}
|
||
|
}
|
||
|
if ($positionFound == 0) { $numLabelsOmitted++ ; }
|
||
|
if ($tries > 1) { $numLabelsMoved++ ; }
|
||
|
} # label
|
||
|
|
||
|
boxOccupyArea ($iconAreaX1, $iconAreaY1, $iconAreaX2, $iconAreaY2, 0, 2) ;
|
||
|
} # pos found
|
||
|
else {
|
||
|
# no, count omitted
|
||
|
$numIconsOmitted++ ;
|
||
|
}
|
||
|
}
|
||
|
else { # only text
|
||
|
my ($x1, $x2, $y1, $y2) ;
|
||
|
# x1, x2, y1, y2
|
||
|
# left, right, bottom, top
|
||
|
# choose space for text, draw
|
||
|
# count omitted
|
||
|
|
||
|
$numLabels++ ;
|
||
|
my @positions = () ;
|
||
|
$x1 = $x + $thickness ; $x2 = $x + $thickness + $spaceTextX ; $y1 = $y ; $y2 = $y - $spaceTextY ; $orientation = "left" ;
|
||
|
push @positions, [$x1, $x2, $y1, $y2, $orientation] ;
|
||
|
$x1 = $x + $thickness ; $x2 = $x + $thickness + $spaceTextX ; $y1 = $y + $spaceTextY ; $y2 = $y ; $orientation = "left" ;
|
||
|
push @positions, [$x1, $x2, $y1, $y2, $orientation] ;
|
||
|
|
||
|
$x1 = $x - ($thickness + $spaceTextX) ; $x2 = $x - $thickness ; $y1 = $y ; $y2 = $y - $spaceTextY ; $orientation = "right" ;
|
||
|
push @positions, [$x1, $x2, $y1, $y2, $orientation] ;
|
||
|
$x1 = $x - ($thickness + $spaceTextX) ; $x2 = $x - $thickness ; $y1 = $y ; $y2 = $y - $spaceTextY ; $orientation = "right" ;
|
||
|
push @positions, [$x1, $x2, $y1, $y2, $orientation] ;
|
||
|
|
||
|
$x1 = $x - $spaceTextX/2 ; $x2 = $x + $spaceTextX/2 ; $y1 = $y - $thickness ; $y2 = $y - ($thickness + $spaceTextY) ; $orientation = "centered" ;
|
||
|
push @positions, [$x1, $x2, $y1, $y2, $orientation] ;
|
||
|
$x1 = $x - $spaceTextX/2 ; $x2 = $x + $spaceTextX/2 ; $y1 = $y + $thickness + $spaceTextY ; $y2 = $y + $thickness ; $orientation = "centered" ;
|
||
|
push @positions, [$x1, $x2, $y1, $y2, $orientation] ;
|
||
|
|
||
|
my $positionFound = 0 ;
|
||
|
$tries = 0 ;
|
||
|
LABA: foreach my $pos (@positions) {
|
||
|
$tries++ ;
|
||
|
# print "$lines[0] $pos->[0], $pos->[1], $pos->[2], $pos->[3], $pos->[4], $numLines\n" ;
|
||
|
|
||
|
$positionFound = checkAndDrawText ($pos->[0], $pos->[1], $pos->[2], $pos->[3], $pos->[4], \@lines, $svgText, $layer) ;
|
||
|
|
||
|
if ($positionFound == 1) {
|
||
|
last LABA ;
|
||
|
}
|
||
|
}
|
||
|
if ($positionFound == 0) { $numLabelsOmitted++ ; }
|
||
|
if ($tries > 1) { $numLabelsMoved++ ; }
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
sub checkAndDrawText {
|
||
|
#
|
||
|
# checks if area available and if so draws text
|
||
|
#
|
||
|
my ($x1, $x2, $y1, $y2, $orientation, $refLines, $svgText, $layer) = @_ ;
|
||
|
|
||
|
if (cv('debug') eq "1") { print "CADT: $x1, $x2, $y1, $y2, $orientation, $refLines, $svgText, $layer\n" ; }
|
||
|
|
||
|
my @lines = @$refLines ;
|
||
|
my $numLines = scalar @lines ;
|
||
|
my $lineDist = cv ('linedist') ;
|
||
|
|
||
|
my ($size) = ( $svgText =~ /font-size=\"(\d+)\"/ ) ;
|
||
|
if ( ! defined $size ) { die ("ERROR: font size could not be determined from svg format string \"$svgText\"\n") ; }
|
||
|
|
||
|
|
||
|
# WATCH for variable sequence!
|
||
|
if (
|
||
|
( ! boxAreaOccupied ($x1, $y1, $x2, $y2) ) or
|
||
|
( cv('forcenodes') eq "1" )
|
||
|
) {
|
||
|
|
||
|
for (my $i=0; $i<=$#lines; $i++) {
|
||
|
|
||
|
my @points = ($x1, $y2+($i+1)*($size+$lineDist), $x2, $y2+($i+1)*($size+$lineDist)) ;
|
||
|
my $pathName = "LabelPath" . $labelPathId ;
|
||
|
$labelPathId++ ;
|
||
|
createPath ($pathName, \@points, "definitions") ;
|
||
|
|
||
|
if ($orientation eq "centered") {
|
||
|
pathText ($svgText, $lines[$i], $pathName, 0, "middle", 50, $layer)
|
||
|
}
|
||
|
if ($orientation eq "left") {
|
||
|
pathText ($svgText, $lines[$i], $pathName, 0, "start", 0, $layer)
|
||
|
}
|
||
|
if ($orientation eq "right") {
|
||
|
pathText ($svgText, $lines[$i], $pathName, 0, "end", 100, $layer)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
boxOccupyArea ($x1, $y1, $x2, $y2, 0, 2) ;
|
||
|
|
||
|
return (1) ;
|
||
|
}
|
||
|
else {
|
||
|
return 0 ;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sub splitLabel {
|
||
|
#
|
||
|
# split label text at space locations and then merge new parts if new part will be smaller than XX chars
|
||
|
#
|
||
|
my $text = shift ;
|
||
|
my @lines = split / /, $text ;
|
||
|
my $merged = 1 ;
|
||
|
while ($merged) {
|
||
|
$merged = 0 ;
|
||
|
LAB2: for (my $i=0; $i<$#lines; $i++) {
|
||
|
if (length ($lines[$i] . " " . $lines[$i+1]) <= cv ('maxcharperline') ) {
|
||
|
$lines[$i] = $lines[$i] . " " . $lines[$i+1] ;
|
||
|
splice (@lines, $i+1, 1) ;
|
||
|
$merged = 1 ;
|
||
|
last LAB2 ;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return (\@lines) ;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
# ------------------------------------------------------------
|
||
|
|
||
|
sub addToPoiHash {
|
||
|
my ($name, $sq) = @_ ;
|
||
|
if (defined $sq) {
|
||
|
$poiHash{$name}{$sq} = 1 ;
|
||
|
}
|
||
|
else {
|
||
|
$poiHash{$name} = 1 ;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
sub getPoiHash {
|
||
|
return \%poiHash ;
|
||
|
}
|
||
|
|
||
|
|
||
|
1 ;
|
||
|
|
||
|
|