source: subversion/applications/utils/gary68/mwLabel.pm @ 34714

Last change on this file since 34714 was 28787, checked in by gary68, 7 years ago

fixed more errors

File size: 10.3 KB
Line 
1#
2# PERL mapweaver module by gary68
3#
4#
5#
6#
7# Copyright (C) 2011, Gerhard Schwanz
8#
9# 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
10# Free Software Foundation; either version 3 of the License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License along with this program; if not, see <http://www.gnu.org/licenses/>
16#
17
18
19package mwLabel ; 
20
21use strict ;
22use warnings ;
23
24use mwConfig ;
25use mwMap ;
26# use mwMisc ;
27use mwOccupy ;
28
29my $labelPathId = 0 ;
30
31my @lines = () ;
32
33my $numIconsMoved = 0 ;
34my $numLabels = 0 ;
35my $numIcons = 0 ;
36my $numLabelsOmitted = 0 ;
37my $numLabelsMoved = 0 ;
38my $numIconsOmitted = 0 ;
39
40my %poiHash = () ;
41
42use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
43
44require Exporter ;
45
46@ISA = qw ( Exporter AutoLoader ) ;
47
48@EXPORT = qw (
49                        placeLabelAndIcon
50                        addToPoiHash
51                        getPoiHash
52                 ) ;
53
54
55
56
57sub placeLabelAndIcon {
58#
59# intelligent icon and label placement alg.
60#
61        my ($lon, $lat, $offset, $thickness, $text, $svgText, $icon, $iconSizeX, $iconSizeY, $layer) = @_ ;
62
63        if (cv('debug') eq "1") { print "PLAI: $lon, $lat, $offset, $thickness, $text, $svgText, $icon, $iconSizeX, $iconSizeY, $layer\n" ; }
64
65        my ($x, $y) = mwMap::convert ($lon, $lat) ; # center !
66
67        if ( ! coordsOut ($x, $y) ) {
68
69                $y = $y + $offset ;
70
71                my ($ref) = splitLabel ($text) ;
72                my (@lines) = @$ref ;
73                my $numLines = scalar @lines ;
74                my $maxTextLenPix = 0 ;
75                my $orientation = "" ;
76                my $lineDist = cv ('linedist') ; ;
77                my $tries = 0 ;
78                my $allowIconMove = cv ('allowiconmove') ;
79
80                my ($textSize) = ( $svgText =~ /font-size=\"(\d+)\"/ ) ;
81                if ( ! defined $textSize ) { die ("ERROR: font size could not be determined from svg format string \"$svgText\"\n") ; }
82
83                foreach my $line (@lines) {
84                        my $len = length ($line) * cv('ppc') / 10 * $textSize ; # in pixels
85                        if ($len > $maxTextLenPix) { $maxTextLenPix = $len ; }
86                }
87                my $spaceTextX = $maxTextLenPix ;
88                my $spaceTextY = $numLines * ($lineDist+$textSize) ;
89
90
91                if ($icon ne "none") {
92                        $numIcons++ ;
93                        # space for icon?
94                                my $sizeX1 = $iconSizeX ; if ($sizeX1 == 0) { $sizeX1 = 20 ; }
95                                my $sizeY1 = $iconSizeY ; if ($sizeY1 == 0) { $sizeY1 = 20 ; }
96                                my $iconX = $x - $sizeX1/2 ; # top left corner
97                                my $iconY = $y - $sizeY1/2 ; 
98
99                                my @shifts = (0) ;
100                                if ($allowIconMove eq "1") {
101                                        @shifts = ( 0, -15, 15 ) ;
102                                }
103                                my $posFound = 0 ; my $posCount = 0 ;
104                                my ($iconAreaX1, $iconAreaY1, $iconAreaX2, $iconAreaY2) ;
105                                LABAB: foreach my $xShift (@shifts) {
106                                        foreach my $yShift (@shifts) {
107                                                $posCount++ ;
108                                                if ( ( ! boxAreaOccupied ($iconX+$xShift, $iconY+$sizeY1+$yShift, $iconX+$sizeX1+$xShift, $iconY+$yShift) ) or ( cv('forcenodes') eq "1" )  ) {
109                                                        placeIcon ($iconX+$xShift, $iconY+$yShift, $icon, $sizeX1, $sizeY1, "nodes") ;
110                                                        $iconAreaX1 = $iconX+$xShift ;
111                                                        $iconAreaY1 = $iconY+$sizeY1+$yShift ;
112                                                        $iconAreaX2 = $iconX+$sizeX1+$xShift ;
113                                                        $iconAreaY2 = $iconY+$yShift ;
114
115                                                        $posFound = 1 ;
116                                                        if ($posCount > 1) { $numIconsMoved++ ; }
117                                                        $iconX = $iconX + $xShift ; # for later use with label
118                                                        $iconY = $iconY + $yShift ;
119                                                        last LABAB ;
120                                                }
121                                        }
122                                }
123                                if ($posFound == 1) {
124
125                                        # label text?
126                                        if ($text ne "") {
127                                                $numLabels++ ;
128
129
130                                                $sizeX1 += 1 ; $sizeY1 += 1 ;
131
132                                                my ($x1, $x2, $y1, $y2) ;
133                                                # $x, $y centered
134                                                # yes, check if space for label, choose position, draw
135                                                # no, count omitted text
136
137                                                my @positions = () ; my $positionFound = 0 ;
138                                                # pos 1 centered below
139                                                $x1 = $x - $spaceTextX/2 ; $x2 = $x + $spaceTextX/2 ; $y1 = $y + $sizeY1/2 + $spaceTextY ; $y2 = $y + $sizeY1/2 ; $orientation = "centered" ; 
140                                                push @positions, [$x1, $x2, $y1, $y2, $orientation] ;
141
142                                                # pos 2/3 to the right, bottom, top
143                                                $x1 = $x + $sizeX1/2 ; $x2 = $x + $sizeX1/2 + $spaceTextX ; $y1 = $y + $sizeY1/2 ; $y2 = $y1 - $spaceTextY ; $orientation = "left" ; 
144                                                push @positions, [$x1, $x2, $y1, $y2, $orientation] ;
145                                                $x1 = $x + $sizeX1/2 ; $x2 = $x + $sizeX1/2 + $spaceTextX ; $y2 = $y - $sizeY1/2 ; $y1 = $y2 + $spaceTextY ; $orientation = "left" ; 
146                                                push @positions, [$x1, $x2, $y1, $y2, $orientation] ;
147
148                                                # pos 4 centered upon
149                                                $x1 = $x - $spaceTextX/2 ; $x2 = $x + $spaceTextX/2 ; $y1 = $y - $sizeY1/2 ; $y2 = $y - $sizeY1/2 - $spaceTextY ; $orientation = "centered" ; 
150                                                push @positions, [$x1, $x2, $y1, $y2, $orientation] ;
151
152                                                # pos 5/6 to the right, below and upon
153                                                $x1 = $x + $sizeX1/2 ; $x2 = $x + $sizeX1/2 + $spaceTextX ; $y2 = $y + $sizeY1/2 ; $y1 = $y2 + $spaceTextY ; $orientation = "left" ; 
154                                                push @positions, [$x1, $x2, $y1, $y2, $orientation] ;
155                                                $x1 = $x + $sizeX1/2 ; $x2 = $x + $sizeX1/2 + $spaceTextX ; $y1 = $y - $sizeY1/2 ; $y2 = $y1 - $spaceTextY ; $orientation = "left" ; 
156                                                push @positions, [$x1, $x2, $y1, $y2, $orientation] ;
157
158                                                # left normal, bottom, top
159                                                $x1 = $x - $sizeX1/2 - $spaceTextX ; $x2 = $x - $sizeX1/2 ; $y1 = $y + $sizeY1/2 ; $y2 = $y1 - $spaceTextY ; $orientation = "right" ; 
160                                                push @positions, [$x1, $x2, $y1, $y2, $orientation] ;
161                                                $x1 = $x - $sizeX1/2 - $spaceTextX ; $x2 = $x - $sizeX1/2 ; $y2 = $y - $sizeY1/2 ; $y1 = $y2 + $spaceTextY ; $orientation = "right" ; 
162                                                push @positions, [$x1, $x2, $y1, $y2, $orientation] ;
163
164                                                # left corners, bottom, top
165                                                $x1 = $x - $sizeX1/2 - $spaceTextX ; $x2 = $x - $sizeX1/2 ; $y2 = $y + $sizeY1/2 ; $y1 = $y2 + $spaceTextY ; $orientation = "right" ; 
166                                                push @positions, [$x1, $x2, $y1, $y2, $orientation] ;
167                                                $x1 = $x - $sizeX1/2 - $spaceTextX ; $x2 = $x - $sizeX1/2 ; $y1 = $y - $sizeY1/2 ; $y2 = $y1 - $spaceTextY ; $orientation = "right" ; 
168                                                push @positions, [$x1, $x2, $y1, $y2, $orientation] ;
169
170
171                                                $tries = 0 ;
172                                                LABB: foreach my $pos (@positions) {
173                                                        $tries++ ;
174
175                                                        $positionFound = checkAndDrawText ($pos->[0], $pos->[1], $pos->[2], $pos->[3], $pos->[4], \@lines, $svgText, $layer) ;
176
177                                                        if ($positionFound == 1) {
178                                                                last LABB ;
179                                                        }
180                                                }
181                                                if ($positionFound == 0) { $numLabelsOmitted++ ; }
182                                                if ($tries > 1) { $numLabelsMoved++ ; }
183                                        } # label
184
185                                        boxOccupyArea ($iconAreaX1, $iconAreaY1, $iconAreaX2, $iconAreaY2, 0, 2) ;
186                                } # pos found
187                                else {
188                                        # no, count omitted
189                                        $numIconsOmitted++ ;
190                                }
191                }
192                else { # only text
193                        my ($x1, $x2, $y1, $y2) ;
194                        # x1, x2, y1, y2
195                        # left, right, bottom, top             
196                        # choose space for text, draw
197                        # count omitted
198
199                        $numLabels++ ;
200                        my @positions = () ;
201                        $x1 = $x + $thickness ; $x2 = $x + $thickness + $spaceTextX ; $y1 = $y ; $y2 = $y - $spaceTextY ; $orientation = "left" ; 
202                        push @positions, [$x1, $x2, $y1, $y2, $orientation] ;
203                        $x1 = $x + $thickness ; $x2 = $x + $thickness + $spaceTextX ; $y1 = $y + $spaceTextY ; $y2 = $y ; $orientation = "left" ; 
204                        push @positions, [$x1, $x2, $y1, $y2, $orientation] ;
205
206                        $x1 = $x - ($thickness + $spaceTextX) ; $x2 = $x - $thickness ; $y1 = $y ; $y2 = $y - $spaceTextY ; $orientation = "right" ; 
207                        push @positions, [$x1, $x2, $y1, $y2, $orientation] ;
208                        $x1 = $x - ($thickness + $spaceTextX) ; $x2 = $x - $thickness ; $y1 = $y ; $y2 = $y - $spaceTextY ; $orientation = "right" ; 
209                        push @positions, [$x1, $x2, $y1, $y2, $orientation] ;
210
211                        $x1 = $x - $spaceTextX/2 ; $x2 = $x + $spaceTextX/2 ; $y1 = $y - $thickness ; $y2 = $y - ($thickness + $spaceTextY) ; $orientation = "centered" ; 
212                        push @positions, [$x1, $x2, $y1, $y2, $orientation] ;
213                        $x1 = $x - $spaceTextX/2 ; $x2 = $x + $spaceTextX/2 ; $y1 = $y + $thickness + $spaceTextY ; $y2 = $y + $thickness ; $orientation = "centered" ; 
214                        push @positions, [$x1, $x2, $y1, $y2, $orientation] ;
215
216                        my $positionFound = 0 ;
217                        $tries = 0 ;
218                        LABA: foreach my $pos (@positions) {
219                                $tries++ ;
220                                # print "$lines[0]   $pos->[0], $pos->[1], $pos->[2], $pos->[3], $pos->[4], $numLines\n" ;
221
222                                $positionFound = checkAndDrawText ($pos->[0], $pos->[1], $pos->[2], $pos->[3], $pos->[4], \@lines, $svgText, $layer) ;
223
224                                if ($positionFound == 1) {
225                                        last LABA ;
226                                }
227                        }
228                        if ($positionFound == 0) { $numLabelsOmitted++ ; }
229                        if ($tries > 1) { $numLabelsMoved++ ; }
230                }
231        }
232}
233
234
235sub checkAndDrawText {
236#
237# checks if area available and if so draws text
238#
239        my ($x1, $x2, $y1, $y2, $orientation, $refLines, $svgText, $layer) = @_ ;
240
241        if (cv('debug') eq "1") { print "CADT: $x1, $x2, $y1, $y2, $orientation, $refLines, $svgText, $layer\n" ; }
242
243        my @lines = @$refLines ;
244        my $numLines = scalar @lines ;
245        my $lineDist = cv ('linedist') ;
246
247        my ($size) = ( $svgText =~ /font-size=\"(\d+)\"/ ) ;
248        if ( ! defined $size ) { die ("ERROR: font size could not be determined from svg format string \"$svgText\"\n") ; }
249
250
251        # WATCH for variable sequence!
252        if ( 
253        ( ! boxAreaOccupied ($x1, $y1, $x2, $y2) ) or 
254        ( cv('forcenodes') eq "1" ) 
255        )  {
256
257                for (my $i=0; $i<=$#lines; $i++) {
258
259                        my @points = ($x1, $y2+($i+1)*($size+$lineDist), $x2, $y2+($i+1)*($size+$lineDist)) ;
260                        my $pathName = "LabelPath" . $labelPathId ; 
261                        $labelPathId++ ;
262                        createPath ($pathName, \@points, "definitions") ;
263
264                        if ($orientation eq "centered") {
265                                pathText ($svgText, $lines[$i], $pathName, 0, "middle", 50, $layer)
266                        }
267                        if ($orientation eq "left") {
268                                pathText ($svgText, $lines[$i], $pathName, 0, "start", 0, $layer)
269                        }
270                        if ($orientation eq "right") {
271                                pathText ($svgText, $lines[$i], $pathName, 0, "end", 100, $layer)
272                        }
273                }
274
275                boxOccupyArea ($x1, $y1, $x2, $y2, 0, 2) ;
276               
277                return (1) ;
278        }
279        else {
280                return 0 ;
281        }
282}
283
284sub splitLabel {
285#
286# split label text at space locations and then merge new parts if new part will be smaller than XX chars
287#
288        my $text = shift ;
289        my @lines = split / /, $text ;
290        my $merged = 1 ;
291        while ($merged) {
292                $merged = 0 ;
293                LAB2: for (my $i=0; $i<$#lines; $i++) {
294                        if (length ($lines[$i] . " " . $lines[$i+1]) <= cv ('maxcharperline') ) {       
295                                $lines[$i] = $lines[$i] . " " . $lines[$i+1] ;
296                                splice (@lines, $i+1, 1) ;
297                                $merged = 1 ;
298                                last LAB2 ;
299                        }
300                }
301        }
302        return (\@lines) ;
303}
304
305
306
307
308# ------------------------------------------------------------
309
310sub addToPoiHash {
311        my ($name, $sq) = @_ ;
312        if (defined $sq) {
313                $poiHash{$name}{$sq} = 1 ;
314        }
315        else {
316                $poiHash{$name} = 1 ;
317        }
318}
319
320
321sub getPoiHash {
322        return \%poiHash ;
323}
324
325
3261 ;
327
328
Note: See TracBrowser for help on using the repository browser.