source: subversion/applications/rendering/osmarender6/osmarender.xsl @ 7967

Last change on this file since 7967 was 7967, checked in by martinvoosterhout, 11 years ago

Fix for batik applied for the XSLT version.

File size: 170.7 KB
Line 
1<?xml version="1.0" encoding="UTF-8"?>
2<!--
3==============================================================================
4
5Osmarender 6.0 Alpha 6
6    with - orig area generation
7         - one node way filtered out
8         - filtered out missing multipolygon relation members from areas
9         - filtered out missing node ref from ways
10
11==============================================================================
12
13Copyright (C) 2006-2007  Etienne Cherdlu, Jochen Topf
14
15This program is free software; you can redistribute it and/or modify
16it under the terms of the GNU General Public License as published by
17the Free Software Foundation; either version 2 of the License, or
18(at your option) any later version.
19
20This program is distributed in the hope that it will be useful,
21but WITHOUT ANY WARRANTY; without even the implied warranty of
22MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23GNU General Public License for more details.
24
25You should have received a copy of the GNU General Public License
26along with this program; if not, write to the Free Software
27Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
28
29==============================================================================
30-->
31<xsl:stylesheet
32  xmlns="http://www.w3.org/2000/svg"
33  xmlns:svg="http://www.w3.org/2000/svg"
34  xmlns:xlink="http://www.w3.org/1999/xlink"
35  xmlns:xi="http://www.w3.org/2001/XInclude"
36  xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
37  xmlns:cc="http://web.resource.org/cc/"
38  xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
39  xmlns:dc="http://purl.org/dc/elements/1.1/"
40  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
41  xmlns:exslt="http://exslt.org/common"
42  xmlns:msxsl="urn:schemas-microsoft-com:xslt"
43  exclude-result-prefixes="exslt msxsl" 
44  version="1.0">
45
46  <xsl:output method="xml" omit-xml-declaration="no" indent="yes" encoding="UTF-8"/>
47
48  <!-- This msxsl script extension fools msxsl into interpreting exslt extensions as msxsl ones, so
49       we can write code using exslt extensions even though msxsl only recognises the msxsl extension
50       namespace.  Thanks to David Carlisle for this: http://dpcarlisle.blogspot.com/2007/05/exslt-node-set-function.html -->
51  <msxsl:script language="JScript" implements-prefix="exslt">
52    this['node-set'] =  function (x) {
53    return x;
54    }
55  </msxsl:script>
56
57  <xsl:param name="osmfile" select="/rules/@data"/>
58  <xsl:param name="title" select="/rules/@title"/>
59
60  <xsl:param name="scale" select="/rules/@scale"/>
61  <xsl:param name="symbolScale" select="/rules/@symbolScale"/>
62  <xsl:param name='textAttenuation' select='/rules/@textAttenuation'/>
63  <xsl:param name="withOSMLayers" select="/rules/@withOSMLayers"/>
64  <xsl:param name="svgBaseProfile" select="/rules/@svgBaseProfile"/>
65  <xsl:param name="symbolsDir" select="/rules/@symbolsDir"/>
66
67  <xsl:param name="showGrid" select="/rules/@showGrid"/>
68  <xsl:param name="showBorder" select="/rules/@showBorder"/>
69  <xsl:param name="showScale" select="/rules/@showScale"/>
70  <xsl:param name="showLicense" select="/rules/@showLicense"/>
71
72  <xsl:key name="nodeById" match="/osm/node" use="@id"/>
73  <xsl:key name="wayById" match="/osm/way" use="@id"/>
74  <xsl:key name="wayByNode" match="/osm/way" use="nd/@ref"/>
75  <xsl:key name="relationByWay" match="/osm/relation" use="member/@ref"/>
76
77  <xsl:variable name="data" select="document($osmfile)"/>
78
79  <!-- Use a web-service (if available) to get the current date -->
80  <xsl:variable name="now" select="document('http://xobjex.com/service/date.xsl')" />
81  <xsl:variable name="date">
82    <xsl:choose>
83      <xsl:when test="$now">
84        <xsl:value-of select="substring($now/date/utc/@stamp,1,10)" />
85        <!-- Assumes 4 digit year -->
86      </xsl:when>
87      <xsl:otherwise>2007-01-01</xsl:otherwise>
88    </xsl:choose>
89  </xsl:variable>
90  <xsl:variable name="year">
91    <xsl:choose>
92      <xsl:when test="$now">
93        <xsl:value-of select="$now/date/utc/year" />
94      </xsl:when>
95      <xsl:otherwise>2007</xsl:otherwise>
96    </xsl:choose>
97  </xsl:variable>
98
99  <!-- extra height for marginalia at top -->
100  <xsl:variable name="marginaliaTopHeight">
101    <xsl:choose>
102      <xsl:when test="$title != ''">40</xsl:when>
103      <xsl:when test="($title = '') and ($showBorder = 'yes')">1.5</xsl:when>
104      <xsl:otherwise>0</xsl:otherwise>
105    </xsl:choose>
106  </xsl:variable>
107
108  <!-- extra height for marginalia at bottom -->
109  <xsl:variable name="marginaliaBottomHeight">
110    <xsl:choose>
111      <xsl:when test="($showScale = 'yes') or ($showLicense = 'yes')">45</xsl:when>
112      <xsl:when test="($showScale != 'yes') and ($showLicense != 'yes') and ($showBorder = 'yes')">1.5</xsl:when>
113      <xsl:otherwise>0</xsl:otherwise>
114    </xsl:choose>
115  </xsl:variable>
116
117  <!-- extra width for border -->
118  <xsl:variable name="extraWidth">
119    <xsl:choose>
120      <xsl:when test="$showBorder = 'yes'">3</xsl:when>
121      <xsl:otherwise>0</xsl:otherwise>
122    </xsl:choose>
123  </xsl:variable>
124
125  <!-- extra height for border -->
126  <xsl:variable name="extraHeight">
127    <xsl:choose>
128      <xsl:when test="($title = '') and ($showBorder = 'yes')">3</xsl:when>
129      <xsl:otherwise>0</xsl:otherwise>
130    </xsl:choose>
131  </xsl:variable>
132
133  <!-- Calculate the size of the bounding box based on the file content -->
134  <xsl:variable name="bllat">
135    <xsl:for-each select="$data/osm/node/@lat">
136      <xsl:sort data-type="number" order="ascending"/>
137      <xsl:if test="position()=1">
138        <xsl:value-of select="."/>
139      </xsl:if>
140    </xsl:for-each>
141  </xsl:variable>
142  <xsl:variable name="bllon">
143    <xsl:for-each select="$data/osm/node/@lon">
144      <xsl:sort data-type="number" order="ascending"/>
145      <xsl:if test="position()=1">
146        <xsl:value-of select="."/>
147      </xsl:if>
148    </xsl:for-each>
149  </xsl:variable>
150  <xsl:variable name="trlat">
151    <xsl:for-each select="$data/osm/node/@lat">
152      <xsl:sort data-type="number" order="descending"/>
153      <xsl:if test="position()=1">
154        <xsl:value-of select="."/>
155      </xsl:if>
156    </xsl:for-each>
157  </xsl:variable>
158  <xsl:variable name="trlon">
159    <xsl:for-each select="$data/osm/node/@lon">
160      <xsl:sort data-type="number" order="descending"/>
161      <xsl:if test="position()=1">
162        <xsl:value-of select="."/>
163      </xsl:if>
164    </xsl:for-each>
165  </xsl:variable>
166  <xsl:variable name="bottomLeftLatitude">
167    <xsl:choose>
168      <xsl:when test="/rules/bounds">
169        <xsl:value-of select="/rules/bounds/@minlat"/>
170      </xsl:when>
171      <xsl:when test="$data/osm/bounds">
172        <xsl:value-of select="$data/osm/bounds/@request_minlat"/>
173      </xsl:when>
174      <xsl:otherwise>
175        <xsl:value-of select="$bllat"/>
176      </xsl:otherwise>
177    </xsl:choose>
178  </xsl:variable>
179  <xsl:variable name="bottomLeftLongitude">
180    <xsl:choose>
181      <xsl:when test="/rules/bounds">
182        <xsl:value-of select="/rules/bounds/@minlon"/>
183      </xsl:when>
184      <xsl:when test="$data/osm/bounds">
185        <xsl:value-of select="$data/osm/bounds/@request_minlon"/>
186      </xsl:when>
187      <xsl:otherwise>
188        <xsl:value-of select="$bllon"/>
189      </xsl:otherwise>
190    </xsl:choose>
191  </xsl:variable>
192  <xsl:variable name="topRightLatitude">
193    <xsl:choose>
194      <xsl:when test="/rules/bounds">
195        <xsl:value-of select="/rules/bounds/@maxlat"/>
196      </xsl:when>
197      <xsl:when test="$data/osm/bounds">
198        <xsl:value-of select="$data/osm/bounds/@request_maxlat"/>
199      </xsl:when>
200      <xsl:otherwise>
201        <xsl:value-of select="$trlat"/>
202      </xsl:otherwise>
203    </xsl:choose>
204  </xsl:variable>
205  <xsl:variable name="topRightLongitude">
206    <xsl:choose>
207      <xsl:when test="/rules/bounds">
208        <xsl:value-of select="/rules/bounds/@maxlon"/>
209      </xsl:when>
210      <xsl:when test="$data/osm/bounds">
211        <xsl:value-of select="$data/osm/bounds/@request_maxlon"/>
212      </xsl:when>
213      <xsl:otherwise>
214        <xsl:value-of select="$trlon"/>
215      </xsl:otherwise>
216    </xsl:choose>
217  </xsl:variable>
218
219  <!-- Derive the latitude of the middle of the map -->
220  <xsl:variable name="middleLatitude" select="($topRightLatitude + $bottomLeftLatitude) div 2.0"/>
221  <!--woohoo lets do trigonometry in xslt -->
222  <!--convert latitude to radians -->
223  <xsl:variable name="latr" select="$middleLatitude * 3.1415926 div 180.0"/>
224  <!--taylor series: two terms is 1% error at lat<68 and 10% error lat<83. we probably need polar projection by then -->
225  <xsl:variable name="coslat" select="1 - ($latr * $latr) div 2 + ($latr * $latr * $latr * $latr) div 24"/>
226  <xsl:variable name="projection" select="1 div $coslat"/>
227
228  <xsl:variable name="dataWidth" select="(number($topRightLongitude)-number($bottomLeftLongitude))*10000*$scale"/>
229  <xsl:variable name="dataHeight" select="(number($topRightLatitude)-number($bottomLeftLatitude))*10000*$scale*$projection"/>
230  <xsl:variable name="km" select="(0.0089928*$scale*10000*$projection)"/>
231
232  <xsl:variable name="documentWidth">
233    <xsl:choose>
234      <xsl:when test="$dataWidth &gt; (number(/rules/@minimumMapWidth) * $km)">
235        <xsl:value-of select="$dataWidth"/>
236      </xsl:when>
237      <xsl:otherwise>
238        <xsl:value-of select="number(/rules/@minimumMapWidth) * $km"/>
239      </xsl:otherwise>
240    </xsl:choose>
241  </xsl:variable>
242
243  <xsl:variable name="documentHeight">
244    <xsl:choose>
245      <xsl:when test="$dataHeight &gt; (number(/rules/@minimumMapHeight) * $km)">
246        <xsl:value-of select="$dataHeight"/>
247      </xsl:when>
248      <xsl:otherwise>
249        <xsl:value-of select="number(/rules/@minimumMapHeight) * $km"/>
250      </xsl:otherwise>
251    </xsl:choose>
252  </xsl:variable>
253
254  <xsl:variable name="width" select="($documentWidth div 2) + ($dataWidth div 2)"/>
255  <xsl:variable name="height" select="($documentHeight div 2) + ($dataHeight div 2)"/>
256
257
258
259  <!-- Main template -->
260  <xsl:template match="/rules">
261
262    <!-- Include an external css stylesheet if one was specified in the rules file -->
263    <xsl:if test="@xml-stylesheet">
264      <xsl:processing-instruction name="xml-stylesheet">
265        href="<xsl:value-of select="@xml-stylesheet"/>" type="text/css"
266      </xsl:processing-instruction>
267    </xsl:if>
268
269    <xsl:variable name="svgWidth" select="$documentWidth + $extraWidth"/>
270    <xsl:variable name="svgHeight" select="$documentHeight + $marginaliaTopHeight + $marginaliaBottomHeight"/>
271
272    <svg id="main"
273  version="1.1"
274  baseProfile="{$svgBaseProfile}"
275  width="{$svgWidth}px"
276  height="{$svgHeight}px"
277  preserveAspectRatio="none"
278  viewBox="{-$extraWidth div 2} {-$extraHeight div 2} {$svgWidth} {$svgHeight}">
279      <xsl:if test="/rules/@interactive='yes'">
280        <xsl:attribute name="onscroll">fnOnScroll(evt)</xsl:attribute>
281        <xsl:attribute name="onzoom">fnOnZoom(evt)</xsl:attribute>
282        <xsl:attribute name="onload">fnOnLoad(evt)</xsl:attribute>
283        <xsl:attribute name="onmousedown">fnOnMouseDown(evt)</xsl:attribute>
284        <xsl:attribute name="onmousemove">fnOnMouseMove(evt)</xsl:attribute>
285        <xsl:attribute name="onmouseup">fnOnMouseUp(evt)</xsl:attribute>
286      </xsl:if>
287
288      <xsl:call-template name="metadata"/>
289
290      <!-- Include javaScript functions for all the dynamic stuff -->
291      <xsl:if test="/rules/@interactive='yes'">
292        <xsl:call-template name="javaScript"/>
293      </xsl:if>
294
295
296      <defs id="defs-rulefile">
297        <!-- Get any <defs> and styles from the rules file -->
298        <xsl:copy-of select="defs/*"/>
299      </defs>
300
301
302      <xsl:if test="$symbolsDir != ''">
303        <!-- Get all symbols mentioned in the rules file from the symbolsDir -->
304        <defs id="defs-symbols">
305          <xsl:for-each select="/rules//symbol/@ref">
306            <xsl:copy-of select="document(concat($symbolsDir,'/', ., '.svg'))/svg:svg/svg:defs/svg:symbol"/>
307          </xsl:for-each>
308        </defs>
309      </xsl:if>
310
311      <!-- Pre-generate named path definitions for all ways -->
312      <xsl:variable name="allWays" select="$data/osm/way"/>
313      <defs id="defs-ways">
314        <xsl:for-each select="$allWays">
315          <xsl:call-template name="generateWayPaths"/>
316        </xsl:for-each>
317      </defs>
318
319      <!-- Clipping rectangle for map -->
320      <clipPath id="map-clipping">
321        <rect id="map-clipping-rect" x="0px" y="0px" height="{$documentHeight}px" width="{$documentWidth}px"/>
322      </clipPath>
323
324      <g id="map" clip-path="url(#map-clipping)" inkscape:groupmode="layer" inkscape:label="Map" transform="translate(0,{$marginaliaTopHeight})">
325        <!-- Draw a nice background layer -->
326        <rect id="background" x="0px" y="0px" height="{$documentHeight}px" width="{$documentWidth}px" class="map-background"/>
327
328        <!-- Process all the rules drawing all map features -->
329        <xsl:call-template name="processRules"/>
330      </g>
331
332      <!-- Draw map decoration -->
333      <g id="map-decoration" inkscape:groupmode="layer" inkscape:label="Map decoration" transform="translate(0,{$marginaliaTopHeight})">
334        <!-- Draw a grid if required -->
335        <xsl:if test="$showGrid='yes'">
336          <xsl:call-template name="drawGrid"/>
337        </xsl:if>
338
339        <!-- Draw a border if required -->
340        <xsl:if test="$showBorder='yes'">
341          <xsl:call-template name="drawBorder"/>
342        </xsl:if>
343      </g>
344
345      <!-- Draw map marginalia -->
346      <xsl:if test="($title != '') or ($showScale = 'yes') or ($showLicense = 'yes')">
347        <g id="marginalia" inkscape:groupmode="layer" inkscape:label="Marginalia">
348          <!-- Draw the title -->
349          <xsl:if test="$title!=''">
350            <xsl:call-template name="drawTitle">
351              <xsl:with-param name="title" select="$title"/>
352            </xsl:call-template>
353          </xsl:if>
354
355          <xsl:if test="($showScale = 'yes') or ($showLicense = 'yes')">
356            <g id="marginalia-bottom" inkscape:groupmode="layer" inkscape:label="Marginalia (Bottom)" transform="translate(0,{$marginaliaTopHeight})">
357              <!-- Draw background for marginalia at bottom -->
358              <rect id="marginalia-background" x="0px" y="{$documentHeight + 5}px" height="40px" width="{$documentWidth}px" class="map-marginalia-background"/>
359
360              <!-- Draw the scale in the bottom left corner -->
361              <xsl:if test="$showScale='yes'">
362                <xsl:call-template name="drawScale"/>
363              </xsl:if>
364
365              <!-- Draw Creative commons license -->
366              <xsl:if test="$showLicense='yes'">
367                <xsl:call-template name="in-image-license">
368                  <xsl:with-param name="dx" select="$documentWidth"/>
369                  <xsl:with-param name="dy" select="$documentHeight"/>
370                </xsl:call-template>
371              </xsl:if>
372            </g>
373          </xsl:if>
374        </g>
375      </xsl:if>
376
377      <!-- Draw labels and controls that are in a static position -->
378      <g id="staticElements" transform="scale(1) translate(0,0)">
379        <!-- Draw the +/- zoom controls -->
380        <xsl:if test="/rules/@interactive='yes'">
381          <xsl:call-template name="zoomControl"/>
382        </xsl:if>
383      </g>
384    </svg>
385
386  </xsl:template>
387
388  <!-- Path Fragment Drawing -->
389  <xsl:template name="drawPath">
390    <xsl:param name='instruction' />
391    <xsl:param name='pathId'/>
392    <xsl:param name='extraClasses'/>
393
394    <xsl:variable name="maskId" select="concat('mask_',$pathId)"/>
395
396    <xsl:call-template name='generateMask'>
397      <xsl:with-param name='instruction' select='$instruction'/>
398      <xsl:with-param name='pathId' select='$pathId'/>
399      <xsl:with-param name='maskId' select='$maskId'/>
400    </xsl:call-template>
401
402    <use xlink:href="#{$pathId}">
403      <!-- Copy all attributes from instruction -->
404      <xsl:apply-templates select="$instruction/@*" mode="copyAttributes" />
405      <!-- Add in any extra classes -->
406      <xsl:attribute name="class">
407        <xsl:value-of select='$instruction/@class'/>
408        <xsl:text> </xsl:text>
409        <xsl:value-of select="$extraClasses"/>
410      </xsl:attribute>
411      <!-- If there is a mask class then include the mask attribute -->
412      <xsl:if test='$instruction/@mask-class'>
413        <xsl:attribute name="mask">
414          url(#<xsl:value-of select="$maskId"/>)
415        </xsl:attribute>
416      </xsl:if>
417      <xsl:call-template name="getSvgAttributesFromOsmTags"/>
418    </use>
419  </xsl:template>
420
421
422  <xsl:template name='generateMask'>
423    <xsl:param name='instruction' />
424    <xsl:param name='pathId'/>
425    <xsl:param name='maskId'/>
426
427    <!-- If the instruction has a mask class -->
428    <xsl:if test='$instruction/@mask-class'>
429      <mask id="{$maskId}" maskUnits="userSpaceOnUse">
430        <use xlink:href="#{$pathId}" class="{$instruction/@mask-class} osmarender-mask-black" />
431        <!-- Required for Inkscape bug -->
432        <use xlink:href="#{$pathId}" class="{$instruction/@class} osmarender-mask-white" />
433        <use xlink:href="#{$pathId}" class="{$instruction/@mask-class} osmarender-mask-black" />
434      </mask>
435    </xsl:if>
436  </xsl:template>
437
438
439
440  <!-- Draw a line for the current <way> element using the formatting of the current <line> instruction -->
441  <xsl:template name="drawWay">
442    <xsl:param name="instruction"/>
443    <xsl:param name="way"/>
444    <!-- The current way element if applicable -->
445    <xsl:param name="layer"/>
446
447    <xsl:choose>
448      <xsl:when test="$instruction/@smart-linecap='no'">
449        <xsl:call-template name='drawPath'>
450          <xsl:with-param name='pathId' select="concat('way_normal_',$way/@id)"/>
451          <xsl:with-param name='instruction' select='$instruction'/>
452        </xsl:call-template>
453      </xsl:when>
454      <xsl:otherwise>
455        <xsl:call-template name="drawWayWithSmartLinecaps">
456          <xsl:with-param name="instruction" select="$instruction"/>
457          <xsl:with-param name="way" select="$way"/>
458          <xsl:with-param name="layer" select="$layer"/>
459        </xsl:call-template>
460      </xsl:otherwise>
461    </xsl:choose>
462  </xsl:template>
463
464
465  <xsl:template name="drawWayWithSmartLinecaps">
466    <xsl:param name="instruction"/>
467    <xsl:param name="way"/>
468    <!-- The current way element if applicable -->
469    <xsl:param name="layer"/>
470
471    <!-- The first half of the first segment and the last half of the last segment are treated differently from the main
472                        part of the way path.  The main part is always rendered with a butt line-cap.  Each end fragement is rendered with
473                        either a round line-cap, if it connects to some other path, or with its default line-cap if it is not connected
474                        to anything.  That way, cul-de-sacs etc are terminated with round, square or butt as specified in the style for the
475                        way. -->
476
477    <!-- First draw the middle section of the way with round linejoins and butt linecaps -->
478    <xsl:if test="count($way/nd) &gt; 1">
479      <xsl:call-template name='drawPath'>
480        <xsl:with-param name='pathId' select="concat('way_mid_',$way/@id)"/>
481        <xsl:with-param name='instruction' select='$instruction'/>
482        <xsl:with-param name='extraClasses'>osmarender-stroke-linecap-butt osmarender-no-marker-start osmarender-no-marker-end</xsl:with-param>
483      </xsl:call-template>
484    </xsl:if>
485
486
487    <!-- For the first half segment in the way, count the number of segments that link to the from-node of this segment.
488                        Also count links where the layer tag is less than the layer of this way, if there are links on a lower layer then
489                        we can safely draw a butt line-cap because the lower layer will already have a round line-cap. -->
490    <!-- Process the first segment in the way -->
491    <xsl:variable name="firstNode" select="key('nodeById',$way/nd[1]/@ref)"/>
492
493    <!-- Count the number of segments connecting to the from node. If there is only one (the current segment) then draw a default line.  -->
494    <xsl:variable name="firstNodeConnectionCount" select="count(key('wayByNode',$firstNode/@id))" />
495
496    <!-- Count the number of connectors at a layer lower than the current layer -->
497    <xsl:variable name="firstNodeLowerLayerConnectionCount" select="
498                        count(key('wayByNode',$firstNode/@id)/tag[@k='layer' and @v &lt; $layer]) +
499                        count(key('wayByNode',$firstNode/@id)[count(tag[@k='layer'])=0 and $layer &gt; 0])
500                        " />
501    <xsl:choose>
502      <xsl:when test="$firstNodeConnectionCount=1">
503        <xsl:call-template name='drawPath'>
504          <xsl:with-param name='pathId' select="concat('way_start_',$way/@id)"/>
505          <xsl:with-param name='instruction' select='$instruction'/>
506          <xsl:with-param name="extraClasses">osmarender-no-marker-end</xsl:with-param>
507        </xsl:call-template>
508      </xsl:when>
509      <xsl:when test="$firstNodeLowerLayerConnectionCount>0">
510        <xsl:call-template name='drawPath'>
511          <xsl:with-param name='pathId' select="concat('way_start_',$way/@id)"/>
512          <xsl:with-param name='instruction' select='$instruction'/>
513          <xsl:with-param name="extraClasses">osmarender-stroke-linecap-butt osmarender-no-marker-end</xsl:with-param>
514        </xsl:call-template>
515      </xsl:when>
516      <xsl:otherwise>
517        <xsl:call-template name='drawPath'>
518          <xsl:with-param name='pathId' select="concat('way_start_',$way/@id)"/>
519          <xsl:with-param name='instruction' select='$instruction'/>
520          <xsl:with-param name="extraClasses">osmarender-stroke-linecap-round osmarender-no-marker-end</xsl:with-param>
521        </xsl:call-template>
522      </xsl:otherwise>
523
524    </xsl:choose>
525
526
527    <!-- Process the last segment in the way -->
528    <xsl:variable name="lastNode" select="key('nodeById',$way/nd[last()]/@ref)"/>
529
530    <!-- Count the number of segments connecting to the last node. If there is only one (the current segment) then draw
531                     a default line.  -->
532    <xsl:variable name="lastNodeConnectionCount" select="count(key('wayByNode',$lastNode/@id))" />
533    <!-- Count the number of connectors at a layer lower than the current layer -->
534    <xsl:variable name="lastNodeLowerLayerConnectionCount" select="
535                        count(key('wayByNode',$lastNode/@id)/tag[@k='layer' and @v &lt; $layer]) +
536                        count(key('wayByNode',$lastNode/@id)[count(tag[@k='layer'])=0 and $layer &gt; 0])
537                        " />
538
539
540    <xsl:choose>
541      <xsl:when test="$lastNodeConnectionCount=1">
542        <xsl:call-template name='drawPath'>
543          <xsl:with-param name='pathId' select="concat('way_end_',$way/@id)"/>
544          <xsl:with-param name='instruction' select='$instruction'/>
545          <xsl:with-param name="extraClasses">osmarender-no-marker-start</xsl:with-param>
546        </xsl:call-template>
547      </xsl:when>
548      <xsl:when test="$lastNodeLowerLayerConnectionCount>0">
549        <xsl:call-template name='drawPath'>
550          <xsl:with-param name='pathId' select="concat('way_end_',$way/@id)"/>
551          <xsl:with-param name='instruction' select='$instruction'/>
552          <xsl:with-param name="extraClasses">osmarender-stroke-linecap-butt osmarender-no-marker-start</xsl:with-param>
553        </xsl:call-template>
554      </xsl:when>
555      <xsl:otherwise>
556        <xsl:call-template name='drawPath'>
557          <xsl:with-param name='pathId' select="concat('way_end_',$way/@id)"/>
558          <xsl:with-param name='instruction' select='$instruction'/>
559          <xsl:with-param name="extraClasses">osmarender-stroke-linecap-round osmarender-no-marker-start</xsl:with-param>
560        </xsl:call-template>
561      </xsl:otherwise>
562
563    </xsl:choose>
564
565  </xsl:template>
566
567
568  <!-- Draw a circle for the current <node> element using the formatting of the current <circle> instruction -->
569  <xsl:template name="drawCircle">
570    <xsl:param name="instruction"/>
571
572    <xsl:variable name="x" select="($width)-((($topRightLongitude)-(@lon))*10000*$scale)"/>
573    <xsl:variable name="y" select="($height)+((($bottomLeftLatitude)-(@lat))*10000*$scale*$projection)"/>
574
575    <circle cx="{$x}" cy="{$y}">
576      <xsl:apply-templates select="$instruction/@*" mode="copyAttributes"/>
577      <!-- Copy all the svg attributes from the <circle> instruction -->
578    </circle>
579
580  </xsl:template>
581
582
583  <!-- Draw a symbol for the current <node> element using the formatting of the current <symbol> instruction -->
584  <xsl:template name="drawSymbol">
585    <xsl:param name="instruction"/>
586
587    <xsl:variable name="x" select="($width)-((($topRightLongitude)-(@lon))*10000*$scale)"/>
588    <xsl:variable name="y" select="($height)+((($bottomLeftLatitude)-(@lat))*10000*$scale*$projection)"/>
589
590    <g transform="translate({$x},{$y}) scale({$symbolScale})">
591      <use>
592        <xsl:if test="$instruction/@ref">
593          <xsl:attribute name="xlink:href">
594            <xsl:value-of select="concat('#symbol-', $instruction/@ref)"/>
595          </xsl:attribute>
596        </xsl:if>
597        <xsl:apply-templates select="$instruction/@*" mode="copyAttributes"/>
598        <!-- Copy all the attributes from the <symbol> instruction -->
599      </use>
600    </g>
601  </xsl:template>
602
603
604  <!-- Render the appropriate attribute of the current <node> element using the formatting of the current <text> instruction -->
605  <xsl:template name="renderText">
606    <xsl:param name="instruction"/>
607
608    <xsl:variable name="x" select="($width)-((($topRightLongitude)-(@lon))*10000*$scale)"/>
609    <xsl:variable name="y" select="($height)+((($bottomLeftLatitude)-(@lat))*10000*$scale*$projection)"/>
610
611    <text>
612      <xsl:apply-templates select="$instruction/@*" mode="copyAttributes"/>
613      <xsl:attribute name="x">
614        <xsl:value-of select="$x"/>
615      </xsl:attribute>
616      <xsl:attribute name="y">
617        <xsl:value-of select="$y"/>
618      </xsl:attribute>
619      <xsl:call-template name="getSvgAttributesFromOsmTags"/>
620      <xsl:value-of select="tag[@k=$instruction/@k]/@v"/>
621    </text>
622  </xsl:template>
623
624
625  <!-- Render the appropriate attribute of the current <segment> element using the formatting of the current <textPath> instruction -->
626  <xsl:template name="renderTextPath">
627    <xsl:param name="instruction"/>
628    <xsl:param name="pathId"/>
629    <xsl:param name="pathDirection"/>
630    <xsl:param name='text'/>
631
632    <xsl:variable name='pathLengthSquared'>
633      <xsl:call-template name='getPathLength'>
634        <xsl:with-param name='pathLengthMultiplier'>
635          <!-- This factor is used to adjust the path-length for comparison with text along a path to determine whether it will fit. -->
636          <xsl:choose>
637            <xsl:when test='$instruction/@textAttenuation'>
638              <xsl:value-of select='$instruction/@textAttenuation'/>
639            </xsl:when>
640            <xsl:when test='string($textAttenuation)'>
641              <xsl:value-of select='$textAttenuation'/>
642            </xsl:when>
643            <xsl:otherwise>99999999</xsl:otherwise>
644          </xsl:choose>
645        </xsl:with-param>
646        <xsl:with-param name='nodes' select='nd'/>
647      </xsl:call-template>
648    </xsl:variable>
649
650    <xsl:variable name='textLength' select='string-length($text)' />
651    <xsl:variable name='textLengthSquared100' select='($textLength)*($textLength)' />
652    <xsl:variable name='textLengthSquared90' select='($textLength *.9)*($textLength*.9)' />
653    <xsl:variable name='textLengthSquared80' select='($textLength *.8)*($textLength*.8)' />
654    <xsl:variable name='textLengthSquared70' select='($textLength *.7)*($textLength*.7)' />
655
656    <xsl:choose>
657      <xsl:when test='($pathLengthSquared) > $textLengthSquared100'>
658        <text>
659          <xsl:apply-templates select="$instruction/@*" mode="renderTextPath-text"/>
660          <textPath xlink:href="#{$pathId}">
661            <xsl:apply-templates select="$instruction/@*" mode="renderTextPath-textPath"/>
662            <xsl:call-template name="getSvgAttributesFromOsmTags"/>
663            <xsl:value-of select="$text"/>
664          </textPath>
665        </text>
666      </xsl:when>
667      <xsl:when test='($pathLengthSquared) > ($textLengthSquared90)'>
668        <text>
669          <xsl:apply-templates select="$instruction/@*" mode="renderTextPath-text"/>
670          <textPath xlink:href="#{$pathId}">
671            <xsl:attribute name='font-size'>90%</xsl:attribute>
672            <xsl:apply-templates select="$instruction/@*" mode="renderTextPath-textPath"/>
673            <xsl:call-template name="getSvgAttributesFromOsmTags"/>
674            <xsl:value-of select="$text"/>
675          </textPath>
676        </text>
677      </xsl:when>
678      <xsl:when test='($pathLengthSquared) > ($textLengthSquared80)'>
679        <text>
680          <xsl:apply-templates select="$instruction/@*" mode="renderTextPath-text"/>
681          <textPath xlink:href="#{$pathId}">
682            <xsl:attribute name='font-size'>80%</xsl:attribute>
683            <xsl:apply-templates select="$instruction/@*" mode="renderTextPath-textPath"/>
684            <xsl:call-template name="getSvgAttributesFromOsmTags"/>
685            <xsl:value-of select="$text"/>
686          </textPath>
687        </text>
688      </xsl:when>
689      <xsl:when test='($pathLengthSquared) > ($textLengthSquared70)'>
690        <text>
691          <xsl:apply-templates select="$instruction/@*" mode="renderTextPath-text"/>
692          <textPath xlink:href="#{$pathId}">
693            <xsl:attribute name='font-size'>70%</xsl:attribute>
694            <xsl:apply-templates select="$instruction/@*" mode="renderTextPath-textPath"/>
695            <xsl:call-template name="getSvgAttributesFromOsmTags"/>
696            <xsl:value-of select="$text"/>
697          </textPath>
698        </text>
699      </xsl:when>
700      <xsl:otherwise />
701      <!-- Otherwise don't render the text -->
702    </xsl:choose>
703  </xsl:template>
704
705
706  <xsl:template name='getPathLength'>
707    <xsl:param name='sumLon' select='number("0")' />
708    <!-- initialise sum to zero -->
709    <xsl:param name='sumLat' select='number("0")' />
710    <!-- initialise sum to zero -->
711    <xsl:param name='nodes'/>
712    <xsl:param name='pathLengthMultiplier'/>
713    <xsl:choose>
714      <xsl:when test='$nodes[1] and $nodes[2]'>
715        <xsl:variable name='fromNode' select='key("nodeById",$nodes[1]/@ref)'/>
716        <xsl:variable name='toNode' select='key("nodeById",$nodes[2]/@ref)'/>
717        <xsl:variable name='lengthLon' select='($fromNode/@lon)-($toNode/@lon)'/>
718        <xsl:variable name='absLengthLon'>
719          <xsl:choose>
720            <xsl:when test='$lengthLon &lt; 0'>
721              <xsl:value-of select='$lengthLon * -1'/>
722            </xsl:when>
723            <xsl:otherwise>
724              <xsl:value-of select='$lengthLon'/>
725            </xsl:otherwise>
726          </xsl:choose>
727        </xsl:variable>
728        <xsl:variable name='lengthLat' select='($fromNode/@lat)-($toNode/@lat)'/>
729        <xsl:variable name='absLengthLat'>
730          <xsl:choose>
731            <xsl:when test='$lengthLat &lt; 0'>
732              <xsl:value-of select='$lengthLat * -1'/>
733            </xsl:when>
734            <xsl:otherwise>
735              <xsl:value-of select='$lengthLat'/>
736            </xsl:otherwise>
737          </xsl:choose>
738        </xsl:variable>
739        <xsl:call-template name='getPathLength'>
740          <xsl:with-param name='sumLon' select='$sumLon+$absLengthLon'/>
741          <xsl:with-param name='sumLat' select='$sumLat+$absLengthLat'/>
742          <xsl:with-param name='nodes' select='$nodes[position()!=1]'/>
743          <xsl:with-param name='pathLengthMultiplier' select='$pathLengthMultiplier'/>
744        </xsl:call-template>
745      </xsl:when>
746      <xsl:otherwise>
747        <!-- Add the square of the total horizontal length to the square of the total vertical length to get the square of
748                                     the total way length.  We don't have a sqrt() function so leave it squared.
749                                     Multiply by 1,000 so that we are usually dealing with a values greater than 1.  Squares of values between 0 and 1
750                                     are smaller and so not very useful.
751                                     Multiply the latitude component by $projection to adjust for Mercator projection issues.
752                                     -->
753        <xsl:value-of select='(
754                                        (($sumLon*1000*$pathLengthMultiplier)*($sumLon*1000*$pathLengthMultiplier))+
755                                        (($sumLat*1000*$pathLengthMultiplier*$projection)*($sumLat*1000*$pathLengthMultiplier*$projection))
756                                        )'/>
757      </xsl:otherwise>
758    </xsl:choose>
759  </xsl:template>
760
761
762  <!-- Suppress the following attributes, allow everything else -->
763  <xsl:template match="@startOffset|@method|@spacing|@lengthAdjust|@textLength|@k" mode="renderTextPath-text" />
764
765  <xsl:template match="@*" mode="renderTextPath-text">
766    <xsl:copy/>
767  </xsl:template>
768
769
770  <!-- Allow the following attributes, suppress everything else -->
771  <xsl:template match="@startOffset|@method|@spacing|@lengthAdjust|@textLength" mode="renderTextPath-textPath">
772    <xsl:copy/>
773  </xsl:template>
774
775  <xsl:template match="@*" mode="renderTextPath-textPath" />
776
777
778  <!-- If there are any tags like <tag k="svg:font-size" v="5"/> then add these as attributes of the svg output -->
779  <xsl:template name="getSvgAttributesFromOsmTags">
780    <xsl:for-each select="tag[contains(@k,'svg:')]">
781      <xsl:attribute name="{substring-after(@k,'svg:')}">
782        <xsl:value-of select="@v"/>
783      </xsl:attribute>
784    </xsl:for-each>
785  </xsl:template>
786
787
788  <xsl:template name="renderArea">
789    <xsl:param name="instruction"/>
790    <xsl:param name="pathId"/>
791
792    <use xlink:href="#{$pathId}">
793      <xsl:apply-templates select="$instruction/@*" mode="copyAttributes"/>
794    </use>
795  </xsl:template>
796
797
798  <!-- Templates to process line, circle, text, etc. instructions -->
799  <!-- Each template is passed a variable containing the set of elements that need to
800         be processed.  The set of elements is already determined by the rules, so
801         these templates don't need to know anything about the rules context they are in. -->
802
803  <!-- Process a <line> instruction -->
804  <xsl:template match="line">
805    <xsl:param name="elements"/>
806    <xsl:param name="layer"/>
807
808    <!-- This is the instruction that is currently being processed -->
809    <xsl:variable name="instruction" select="."/>
810
811    <g>
812      <xsl:apply-templates select="@*" mode="copyAttributes" />
813      <!-- Add all the svg attributes of the <line> instruction to the <g> element -->
814
815      <!-- For each way -->
816      <xsl:apply-templates select="$elements" mode="line">
817        <xsl:with-param name="instruction" select="$instruction"/>
818        <xsl:with-param name="layer" select="$layer"/>
819      </xsl:apply-templates>
820
821    </g>
822  </xsl:template>
823
824
825  <!-- Suppress output of any unhandled elements -->
826  <xsl:template match="*" mode="line"/>
827
828
829  <!-- Draw lines for a way  -->
830  <xsl:template match="way" mode="line">
831    <xsl:param name="instruction"/>
832    <xsl:param name="layer"/>
833
834    <!-- The current <way> element -->
835    <xsl:variable name="way" select="."/>
836
837    <!-- DODI: !!!WORKAROUND!!! skip one node ways-->
838    <xsl:if test="count($way/nd) &gt; 1">
839      <xsl:call-template name="drawWay">
840        <xsl:with-param name="instruction" select="$instruction"/>
841        <xsl:with-param name="way" select="$way"/>
842        <xsl:with-param name="layer" select="$layer"/>
843      </xsl:call-template>
844    </xsl:if >
845  </xsl:template>
846
847
848  <!-- Process an <area> instruction -->
849  <xsl:template match="area">
850    <xsl:param name="elements"/>
851
852    <!-- This is the instruction that is currently being processed -->
853    <xsl:variable name="instruction" select="."/>
854
855    <g>
856      <xsl:apply-templates select="@*" mode="copyAttributes"/>
857      <!-- Add all the svg attributes of the <line> instruction to the <g> element -->
858
859      <!-- For each way -->
860      <xsl:apply-templates select="$elements" mode="area">
861        <xsl:with-param name="instruction" select="$instruction"/>
862      </xsl:apply-templates>
863    </g>
864  </xsl:template>
865
866
867  <!-- Discard anything that is not matched by a more specific template -->
868  <xsl:template match="*" mode="area"/>
869
870
871  <!-- Draw area for a <way> -->
872  <xsl:template match="way" mode="area">
873    <xsl:param name="instruction"/>
874
875    <!-- DODI:  removed because duplicate definition generated if area referenced 2 or more times -->
876    <!-- DODI:  reenabled because of "duplicate point detection in lines2curves.pl " -->
877    <!-- <xsl:call-template name="generateAreaPath"/> -->
878
879    <xsl:variable name="pathArea">
880      <xsl:call-template name="generateAreaPath"/>
881    </xsl:variable>
882
883    <!-- DODI: do now draw empty ways/areas-->
884    <xsl:if test ="$pathArea!=''">
885      <path id="area_{@id}" d="{$pathArea}"/>
886      <xsl:call-template name="renderArea">
887        <xsl:with-param name="instruction" select="$instruction"/>
888        <xsl:with-param name="pathId" select="concat('area_',@id)"/>
889      </xsl:call-template>
890    </xsl:if>
891  </xsl:template>
892
893
894  <!-- Process <circle> instruction -->
895  <xsl:template match="circle">
896    <xsl:param name="elements"/>
897
898    <!-- This is the instruction that is currently being processed -->
899    <xsl:variable name="instruction" select="."/>
900
901    <xsl:for-each select="$elements[name()='node']">
902      <xsl:call-template name="drawCircle">
903        <xsl:with-param name="instruction" select="$instruction"/>
904      </xsl:call-template>
905    </xsl:for-each>
906  </xsl:template>
907
908
909  <!-- Process a <symbol> instruction -->
910  <xsl:template match="symbol">
911    <xsl:param name="elements"/>
912
913    <!-- This is the instruction that is currently being processed -->
914    <xsl:variable name="instruction" select="."/>
915
916    <xsl:for-each select="$elements[name()='node']">
917      <xsl:call-template name="drawSymbol">
918        <xsl:with-param name="instruction" select="$instruction"/>
919      </xsl:call-template>
920    </xsl:for-each>
921
922  </xsl:template>
923
924  <!-- wayMarker instruction.  Draws a marker on a node that is perpendicular to a way that passes through the node.
925       If more than one way passes through the node then the result is a bit unspecified.  -->
926  <xsl:template match="wayMarker">
927    <xsl:param name="elements"/>
928   
929    <!-- This is the instruction that is currently being processed -->
930    <xsl:variable name="instruction" select="."/>
931   
932    <g>
933      <!-- Add all the svg attributes of the <wayMarker> instruction to the <g> element -->
934      <xsl:apply-templates select="@*" mode="copyAttributes" />
935     
936      <!-- Process each matched node in turn -->
937      <xsl:for-each select="$elements[name()='node']">
938        <xsl:variable name='nodeId' select="@id" />
939       
940        <xsl:variable name='way' select="key('wayByNode', @id)" />
941        <xsl:variable name='previousNode' select="key('nodeById', $way/nd[@ref=$nodeId]/preceding-sibling::nd[1]/@ref)" />
942        <xsl:variable name='nextNode' select="key('nodeById', $way/nd[@ref=$nodeId]/following-sibling::nd[1]/@ref)" />
943       
944        <xsl:variable name='path'>
945          <xsl:choose>
946            <xsl:when test='$previousNode and $nextNode'>
947              <xsl:call-template name="moveToNode">
948                <xsl:with-param name="node" select="$previousNode"/>
949              </xsl:call-template>
950              <xsl:call-template name="lineToNode">
951                <xsl:with-param name="node" select="."/>
952              </xsl:call-template>
953              <xsl:call-template name="lineToNode">
954                <xsl:with-param name="node" select="$nextNode"/>
955              </xsl:call-template>
956            </xsl:when>
957
958            <xsl:when test='$previousNode'>
959              <xsl:call-template name="moveToNode">
960                <xsl:with-param name="node" select="$previousNode"/>
961              </xsl:call-template>
962              <xsl:call-template name="lineToNode">
963                <xsl:with-param name="node" select="."/>
964              </xsl:call-template>
965              <xsl:call-template name="lineToNode">
966                <xsl:with-param name="node" select="."/>
967              </xsl:call-template>
968            </xsl:when>
969
970            <xsl:when test='$nextNode'>
971              <xsl:call-template name="moveToNode">
972                <xsl:with-param name="node" select="."/>
973              </xsl:call-template>
974              <xsl:call-template name="lineToNode">
975                <xsl:with-param name="node" select="$nextNode"/>
976              </xsl:call-template>
977              <xsl:call-template name="lineToNode">
978                <xsl:with-param name="node" select="$nextNode"/>
979              </xsl:call-template>
980            </xsl:when>
981          </xsl:choose>
982        </xsl:variable>
983       
984        <path id="nodePath_{@id}" d="{$path}"/>
985       
986        <use xlink:href="#nodePath_{@id}">
987          <xsl:apply-templates select="$instruction/@*" mode="copyAttributes" />
988        </use>
989      </xsl:for-each>
990    </g>
991   
992  </xsl:template>
993
994  <!-- Process an <areaText> instruction -->
995  <xsl:template match="areaText">
996    <xsl:param name="elements"/>
997
998    <!-- This is the instruction that is currently being processed -->
999    <xsl:variable name="instruction" select="."/>
1000
1001    <!-- Select all <way> elements that have a key that matches the k attribute of the text instruction -->
1002    <xsl:apply-templates select="$elements[name()='way'][tag[@k=$instruction/@k]]" mode="areaTextPath">
1003      <xsl:with-param name="instruction" select="$instruction"/>
1004    </xsl:apply-templates>
1005  </xsl:template>
1006
1007
1008  <xsl:template match="*" mode="areaTextPath"/>
1009
1010
1011  <xsl:template match="way" mode="areaTextPath">
1012    <xsl:param name="instruction"/>
1013
1014    <!-- The current <way> element -->
1015    <xsl:variable name="way" select="."/>
1016
1017    <xsl:call-template name="renderAreaText">
1018      <xsl:with-param name="instruction" select="$instruction"/>
1019      <xsl:with-param name="pathId" select="concat('way_normal_',@id)"/>
1020    </xsl:call-template>
1021
1022  </xsl:template>
1023
1024
1025  <xsl:template name="renderAreaText">
1026    <xsl:param name="instruction"/>
1027
1028    <xsl:variable name='center'>
1029      <xsl:call-template name="areaCenter">
1030        <xsl:with-param name="element" select="." />
1031      </xsl:call-template>
1032    </xsl:variable>
1033
1034    <xsl:variable name="centerLon" select="substring-before($center, ',')" />
1035    <xsl:variable name="centerLat" select="substring-after($center, ',')" />
1036
1037    <xsl:variable name="x" select="($width)-((($topRightLongitude)-($centerLon))*10000*$scale)"/>
1038    <xsl:variable name="y" select="($height)+((($bottomLeftLatitude)-($centerLat))*10000*$scale*$projection)"/>
1039
1040    <text>
1041      <xsl:apply-templates select="$instruction/@*" mode="copyAttributes"/>
1042      <xsl:attribute name="x">
1043        <xsl:value-of select="$x"/>
1044      </xsl:attribute>
1045      <xsl:attribute name="y">
1046        <xsl:value-of select="$y"/>
1047      </xsl:attribute>
1048      <xsl:call-template name="getSvgAttributesFromOsmTags"/>
1049      <xsl:value-of select="tag[@k=$instruction/@k]/@v"/>
1050    </text>
1051  </xsl:template>
1052
1053  <!-- Process an <areaSymbol> instruction -->
1054  <xsl:template match="areaSymbol">
1055    <xsl:param name="elements"/>
1056
1057    <!-- This is the instruction that is currently being processed -->
1058    <xsl:variable name="instruction" select="."/>
1059
1060    <!-- Select all <way> elements -->
1061    <xsl:apply-templates select="$elements[name()='way']" mode="areaSymbolPath">
1062      <xsl:with-param name="instruction" select="$instruction"/>
1063    </xsl:apply-templates>
1064  </xsl:template>
1065
1066
1067  <xsl:template match="*" mode="areaSymbolPath"/>
1068
1069
1070  <xsl:template match="way" mode="areaSymbolPath">
1071    <xsl:param name="instruction"/>
1072
1073    <!-- The current <way> element -->
1074    <xsl:variable name="way" select="."/>
1075
1076    <xsl:call-template name="renderAreaSymbol">
1077      <xsl:with-param name="instruction" select="$instruction"/>
1078      <xsl:with-param name="pathId" select="concat('way_normal_',@id)"/>
1079    </xsl:call-template>
1080
1081  </xsl:template>
1082
1083
1084  <xsl:template name="renderAreaSymbol">
1085    <xsl:param name="instruction"/>
1086
1087    <xsl:variable name='center'>
1088      <xsl:call-template name="areaCenter">
1089        <xsl:with-param name="element" select="." />
1090      </xsl:call-template>
1091    </xsl:variable>
1092
1093    <xsl:message>
1094      areaCenter: <xsl:value-of select="$center" />
1095    </xsl:message>
1096
1097    <xsl:variable name="centerLon" select="substring-before($center, ',')" />
1098    <xsl:variable name="centerLat" select="substring-after($center, ',')" />
1099
1100    <xsl:variable name="x" select="($width)-((($topRightLongitude)-($centerLon))*10000*$scale)"/>
1101    <xsl:variable name="y" select="($height)+((($bottomLeftLatitude)-($centerLat))*10000*$scale*$projection)"/>
1102
1103    <g transform="translate({$x},{$y}) scale({$symbolScale})">
1104      <use>
1105        <xsl:if test="$instruction/@ref">
1106          <xsl:attribute name="xlink:href">
1107            <xsl:value-of select="concat('#symbol-', $instruction/@ref)"/>
1108          </xsl:attribute>
1109        </xsl:if>
1110        <xsl:apply-templates select="$instruction/@*" mode="copyAttributes"/>
1111        <!-- Copy all the attributes from the <symbol> instruction -->
1112      </use>
1113    </g>
1114  </xsl:template>
1115
1116  <!--
1117      areaCenter: Find a good center point for label/icon placement inside of polygon.
1118      Algorithm is described at http://bob.cakebox.net/poly-center.php
1119  -->
1120  <xsl:template name="areaCenter">
1121    <xsl:param name="element" />
1122
1123    <!-- Get multipolygon relation for areas with holes -->
1124    <xsl:variable name='holerelation' select="key('relationByWay',$element/@id)[tag[@k='type' and @v='multipolygon']]"/>
1125
1126    <!-- A semicolon-separated list of x,y coordinate pairs of points lying halfway into the polygon at angles to the vertex -->
1127    <xsl:variable name="points">
1128      <xsl:call-template name="areacenterPointsInside">
1129        <xsl:with-param name="element" select="$element" />
1130        <xsl:with-param name="holerelation" select="$holerelation" />
1131      </xsl:call-template>
1132    </xsl:variable>
1133
1134    <!-- x,y calculated by a simple average over all x/y's in points -->
1135    <xsl:variable name="mediumpoint">
1136      <xsl:call-template name="areacenterMediumOfPoints">
1137        <xsl:with-param name="points" select="$points" />
1138      </xsl:call-template>
1139    </xsl:variable>
1140    <xsl:variable name="mediumpoint_x" select="substring-before($mediumpoint, ',')" />
1141    <xsl:variable name="mediumpoint_y" select="substring-before(substring-after($mediumpoint, ','), ',')" />
1142    <xsl:variable name="medium_dist" select="substring-after(substring-after($mediumpoint, ','), ',')" />
1143
1144    <!-- Find out if mediumpoint is inside or outside the polygon -->
1145    <xsl:variable name="intersection">
1146      <xsl:call-template name="areacenterNearestIntersectionInside">
1147        <xsl:with-param name="x" select="$mediumpoint_x" />
1148        <xsl:with-param name="y" select="$mediumpoint_y" />
1149        <xsl:with-param name="edgestart" select="$element/nd[1]" />
1150        <xsl:with-param name="linepoint_x" select="$mediumpoint_x" />
1151        <xsl:with-param name="linepoint_y" select="$mediumpoint_y + 1" />
1152        <xsl:with-param name="holerelation" select="$holerelation" />
1153      </xsl:call-template>
1154    </xsl:variable>
1155    <xsl:variable name="intersection_count" select="substring-before($intersection, ';')" />
1156
1157    <xsl:variable name="nearestEdge">
1158      <xsl:call-template name="areacenterNearestEdge">
1159        <xsl:with-param name="x" select="$mediumpoint_x" />
1160        <xsl:with-param name="y" select="$mediumpoint_y" />
1161        <xsl:with-param name="edgestart" select="$element/nd[1]" />
1162        <xsl:with-param name="holerelation" select="$holerelation" />
1163      </xsl:call-template>
1164    </xsl:variable>
1165
1166    <xsl:choose>
1167      <xsl:when test="$intersection_count mod 2 = 0 or $nearestEdge div 2 * 1.20 &gt; $medium_dist">
1168        <!-- Find the best point in $points to use -->
1169        <xsl:call-template name="areacenterBestPoint">
1170          <xsl:with-param name="points" select="$points" />
1171          <xsl:with-param name="x" select="$mediumpoint_x" />
1172          <xsl:with-param name="y" select="$mediumpoint_y" />
1173          <xsl:with-param name="medium_dist" select="$medium_dist" />
1174        </xsl:call-template>
1175      </xsl:when>
1176      <xsl:otherwise>
1177        <xsl:value-of select="$mediumpoint_x"/>,<xsl:value-of select="$mediumpoint_y"/>
1178      </xsl:otherwise>
1179    </xsl:choose>
1180  </xsl:template>
1181
1182  <!-- Returns a semicolon-separated list of x,y pairs -->
1183  <xsl:template name="areacenterPointsInside">
1184    <xsl:param name="element" />
1185    <xsl:param name="holerelation" />
1186
1187    <!-- iterate over every vertex except the first one, which is also the last -->
1188    <xsl:for-each select="$element/nd[position() &gt; 1]">
1189      <xsl:variable name="vertex" select="." />
1190      <xsl:variable name="prev" select="$vertex/preceding-sibling::nd[1]" />
1191      <xsl:variable name="nextId">
1192        <xsl:choose>
1193          <xsl:when test="position() &lt; last()">
1194            <xsl:value-of select="$vertex/following-sibling::nd[1]/@ref" />
1195          </xsl:when>
1196          <xsl:otherwise>
1197            <xsl:value-of select="$vertex/../nd[2]/@ref" />
1198          </xsl:otherwise>
1199        </xsl:choose>
1200      </xsl:variable>
1201      <xsl:variable name="next" select="$vertex/../nd[@ref=$nextId]" />
1202
1203      <!-- Angle at between $prev and $next in $vertex -->
1204      <xsl:variable name="angle">
1205        <xsl:call-template name="angleThroughPoints">
1206          <xsl:with-param name="from" select="key('nodeById', $prev/@ref)" />
1207          <xsl:with-param name="through" select="key('nodeById', $vertex/@ref)" />
1208          <xsl:with-param name="to" select="key('nodeById', $next/@ref)" />
1209        </xsl:call-template>
1210      </xsl:variable>
1211
1212      <!-- Calculate a point on the line going through $vertex at $angle -->
1213      <xsl:variable name="linepoint">
1214        <xsl:call-template name="areacenterLinepoint">
1215          <xsl:with-param name="point" select="key('nodeById', $vertex/@ref)" />
1216          <xsl:with-param name="angle" select="$angle" />
1217        </xsl:call-template>
1218      </xsl:variable>
1219      <xsl:variable name="linepoint_x" select="substring-before($linepoint, ',')" />
1220      <xsl:variable name="linepoint_y" select="substring-after($linepoint, ',')" />
1221
1222      <!-- Find the nearest intersection between the line vertex-linepoint and the nearest edge inwards into the polygon -->
1223      <xsl:variable name="intersection">
1224        <xsl:call-template name="areacenterNearestIntersectionInside">
1225          <xsl:with-param name="x" select="key('nodeById', $vertex/@ref)/@lon" />
1226          <xsl:with-param name="y" select="key('nodeById', $vertex/@ref)/@lat" />
1227          <xsl:with-param name="edgestart" select="../nd[1]" />
1228          <xsl:with-param name="linepoint_x" select="$linepoint_x" />
1229          <xsl:with-param name="linepoint_y" select="$linepoint_y" />
1230          <xsl:with-param name="holerelation" select="$holerelation" />
1231        </xsl:call-template>
1232      </xsl:variable>
1233      <xsl:variable name="intersection_count" select="substring-before($intersection, ';')" />
1234      <xsl:variable name="intersection_data">
1235        <xsl:choose>
1236          <xsl:when test="$intersection_count mod 2 != 0">
1237            <xsl:value-of select="substring-before(substring-after($intersection, ';'), ';')" />
1238          </xsl:when>
1239          <xsl:otherwise>
1240            <xsl:value-of select="substring-after(substring-after($intersection, ';'), ';')" />
1241          </xsl:otherwise>
1242        </xsl:choose>
1243      </xsl:variable>
1244      <xsl:variable name="intersection_x" select="substring-before($intersection_data, ',')" />
1245      <xsl:variable name="intersection_y" select="substring-before(substring-after($intersection_data, ','), ',')" />
1246      <xsl:variable name="intersection_dist" select="substring-before(substring-after(substring-after($intersection_data, ','), ','), ',')" />
1247
1248      <xsl:variable name="point_x" select="key('nodeById', $vertex/@ref)/@lon + ( $intersection_x - key('nodeById', $vertex/@ref)/@lon ) div 2" />
1249      <xsl:variable name="point_y" select="key('nodeById', $vertex/@ref)/@lat + ( $intersection_y - key('nodeById', $vertex/@ref)/@lat ) div 2" />
1250     
1251      <xsl:if test="($point_x &lt;= 0 or $point_x &gt; 0)  and ($point_y &lt;= 0 or $point_y &gt; 0)"> <!-- Only return anything if we actually have a result -->
1252        <!-- Note: this will produce trailing semicolon, which is nice as it simplifies looping over this later -->
1253        <xsl:value-of select="$point_x" />,<xsl:value-of select="$point_y" />,<xsl:value-of select="$intersection_dist" />;
1254      </xsl:if>
1255    </xsl:for-each>
1256  </xsl:template>
1257
1258  <!-- Calculate the angle between $from and $to in $through. Returns answer in radians -->
1259  <xsl:template name="angleThroughPoints">
1260    <xsl:param name="from" />
1261    <xsl:param name="through" />
1262    <xsl:param name="to" />
1263
1264    <xsl:variable name="from_x" select="($from/@lon) - ($through/@lon)" />
1265    <xsl:variable name="from_y" select="$from/@lat - $through/@lat" />
1266    <xsl:variable name="to_x" select="$to/@lon - $through/@lon" />
1267    <xsl:variable name="to_y" select="$to/@lat - $through/@lat" />
1268
1269    <xsl:variable name="from_angle_">
1270      <xsl:call-template name="atan2">
1271        <xsl:with-param name="x" select="$from_x" />
1272        <xsl:with-param name="y" select="$from_y" />
1273      </xsl:call-template>
1274    </xsl:variable>
1275    <xsl:variable name="from_angle" select="$from_angle_ + $pi" />
1276    <xsl:variable name="to_angle_">
1277      <xsl:call-template name="atan2">
1278        <xsl:with-param name="x" select="$to_x" />
1279        <xsl:with-param name="y" select="$to_y" />
1280      </xsl:call-template>
1281    </xsl:variable>
1282    <xsl:variable name="to_angle" select="$to_angle_ + $pi" />
1283
1284    <xsl:variable name="min_angle">
1285      <xsl:choose>
1286        <xsl:when test="$from_angle &gt; $to_angle">
1287          <xsl:value-of select="$to_angle" />
1288        </xsl:when>
1289        <xsl:otherwise>
1290          <xsl:value-of select="$from_angle" />
1291        </xsl:otherwise>
1292      </xsl:choose>
1293    </xsl:variable>
1294    <xsl:variable name="max_angle">
1295      <xsl:choose>
1296        <xsl:when test="$from_angle &gt; $to_angle">
1297          <xsl:value-of select="$from_angle" />
1298        </xsl:when>
1299        <xsl:otherwise>
1300          <xsl:value-of select="$to_angle" />
1301        </xsl:otherwise>
1302      </xsl:choose>
1303    </xsl:variable>
1304
1305    <xsl:value-of select="$min_angle + ($max_angle - $min_angle) div 2" />
1306  </xsl:template>
1307
1308  <!-- atan2 implementation from http://lists.fourthought.com/pipermail/exslt/2007-March/001540.html -->
1309  <xsl:template name="atan2">
1310    <xsl:param name="y"/>
1311    <xsl:param name="x"/>
1312    <!-- http://lists.apple.com/archives/PerfOptimization-dev/2005/Jan/msg00051.html -->
1313    <xsl:variable name="PI"    select="number(3.1415926535897)"/>
1314    <xsl:variable name="PIBY2" select="$PI div 2.0"/>
1315    <xsl:choose>
1316      <xsl:when test="$x = 0.0">
1317        <xsl:choose>
1318          <xsl:when test="($y &gt; 0.0)">
1319            <xsl:value-of select="$PIBY2"/>
1320          </xsl:when>
1321          <xsl:when test="($y &lt; 0.0)">
1322            <xsl:value-of select="-$PIBY2"/>
1323          </xsl:when>
1324          <xsl:otherwise>
1325            <!-- Error: Degenerate x == y == 0.0 -->
1326            <xsl:value-of select="number(NaN)"/>
1327          </xsl:otherwise>
1328        </xsl:choose>
1329      </xsl:when>
1330      <xsl:otherwise>
1331        <xsl:variable name="z" select="$y div $x"/>
1332        <xsl:variable name="absZ">
1333          <!-- inline abs function -->
1334          <xsl:choose>
1335            <xsl:when test="$z &lt; 0.0">
1336              <xsl:value-of select="- number($z)"/>
1337            </xsl:when>
1338            <xsl:otherwise>
1339              <xsl:value-of select="number($z)"/>
1340            </xsl:otherwise>
1341          </xsl:choose>
1342        </xsl:variable>
1343        <xsl:choose>
1344          <xsl:when test="($absZ &lt; 1.0)">
1345            <xsl:variable name="f1Z" select="$z div (1.0 + 0.28*$z*$z)"/>
1346            <xsl:choose>
1347              <xsl:when test="($x &lt; 0.0) and ($y &lt; 0.0)">
1348                <xsl:value-of select="$f1Z - $PI"/>
1349              </xsl:when>
1350              <xsl:when test="($x &lt; 0.0)">
1351                <xsl:value-of select="$f1Z + $PI"/>
1352              </xsl:when>
1353              <xsl:otherwise>
1354                <xsl:value-of select="$f1Z"/>
1355              </xsl:otherwise>
1356            </xsl:choose>
1357          </xsl:when>
1358          <xsl:otherwise>
1359            <xsl:variable name="f2Z" select="$PIBY2 - ($z div ($z*$z +
13600.28))"/>
1361            <xsl:choose>
1362              <xsl:when test="($y &lt; 0.0)">
1363                <xsl:value-of select="$f2Z - $PI"/>
1364              </xsl:when>
1365              <xsl:otherwise>
1366                <xsl:value-of select="$f2Z"/>
1367              </xsl:otherwise>
1368            </xsl:choose>
1369          </xsl:otherwise>
1370        </xsl:choose>
1371      </xsl:otherwise>
1372    </xsl:choose>
1373  </xsl:template>
1374
1375  <!-- Find a point on the line going through $point at $angle that's guaranteed to be outside the polygon -->
1376  <xsl:template name="areacenterLinepoint">
1377    <xsl:param name="point" />
1378    <xsl:param name="angle" />
1379
1380    <xsl:variable name="cos_angle">
1381      <xsl:call-template name="cos">
1382        <xsl:with-param name="angle" select="$angle"/>
1383      </xsl:call-template>
1384    </xsl:variable>
1385   
1386    <xsl:variable name="sin_angle">
1387      <xsl:call-template name="sin">
1388        <xsl:with-param name="angle" select="$angle"/>
1389      </xsl:call-template>
1390    </xsl:variable>
1391   
1392    <xsl:value-of select="$point/@lon + $cos_angle"/>, <xsl:value-of select="$point/@lat + $sin_angle"/>
1393  </xsl:template>
1394 
1395  <!-- Constants for trig templates -->
1396  <xsl:variable name="pi" select="3.1415926535897"/>
1397  <xsl:variable name="halfPi" select="$pi div 2"/>
1398  <xsl:variable name="twicePi" select="$pi*2"/>
1399
1400  <xsl:template name="sin">
1401    <xsl:param name="angle" />
1402    <xsl:param name="precision" select="0.00000001"/>
1403
1404    <xsl:variable name="y">
1405      <xsl:choose>
1406        <xsl:when test="not(0 &lt;= $angle and $twicePi > $angle)">
1407          <xsl:call-template name="cutIntervals">
1408            <xsl:with-param name="length" select="$twicePi"/>
1409            <xsl:with-param name="angle" select="$angle"/>
1410          </xsl:call-template>
1411        </xsl:when>
1412        <xsl:otherwise>
1413          <xsl:value-of select="$angle"/>
1414        </xsl:otherwise>
1415      </xsl:choose>
1416    </xsl:variable>
1417
1418    <xsl:call-template name="sineIter">
1419      <xsl:with-param name="angle2" select="$y*$y"/>
1420      <xsl:with-param name="res" select="$y"/>
1421      <xsl:with-param name="elem" select="$y"/>
1422      <xsl:with-param name="n" select="1"/>
1423      <xsl:with-param name="precision" select="$precision" />
1424    </xsl:call-template>
1425  </xsl:template>
1426
1427  <xsl:template name="sineIter">
1428    <xsl:param name="angle2" />
1429    <xsl:param name="res" />
1430    <xsl:param name="elem" />
1431    <xsl:param name="n" />
1432    <xsl:param name="precision"/>
1433
1434    <xsl:variable name="nextN" select="$n+2" />
1435    <xsl:variable name="newElem" select="-$elem*$angle2 div ($nextN*($nextN - 1))" />
1436    <xsl:variable name="newResult" select="$res + $newElem" />
1437    <xsl:variable name="diffResult" select="$newResult - $res" />
1438
1439    <xsl:choose>
1440      <xsl:when test="$diffResult > $precision or $diffResult &lt; -$precision">
1441        <xsl:call-template name="sineIter">
1442          <xsl:with-param name="angle2" select="$angle2" />
1443          <xsl:with-param name="res" select="$newResult" />
1444          <xsl:with-param name="elem" select="$newElem" />
1445          <xsl:with-param name="n" select="$nextN" />
1446          <xsl:with-param name="precision" select="$precision" />
1447        </xsl:call-template>
1448      </xsl:when>
1449      <xsl:otherwise>
1450        <xsl:value-of select="$newResult"/>
1451      </xsl:otherwise>
1452    </xsl:choose>
1453  </xsl:template>
1454
1455  <xsl:template name="cutIntervals">
1456    <xsl:param name="length"/>
1457    <xsl:param name="angle"/>
1458
1459    <xsl:variable name="vsign">
1460      <xsl:choose>
1461        <xsl:when test="$angle >= 0">1</xsl:when>
1462        <xsl:otherwise>-1</xsl:otherwise>
1463      </xsl:choose>
1464    </xsl:variable>
1465    <xsl:variable name="vdiff" select="$length*floor($angle div $length) -$angle"/> 
1466    <xsl:choose>
1467      <xsl:when test="$vdiff*$angle > 0">
1468        <xsl:value-of select="$vsign*$vdiff"/>
1469      </xsl:when>
1470      <xsl:otherwise>
1471        <xsl:value-of select="-$vsign*$vdiff"/>
1472      </xsl:otherwise>
1473    </xsl:choose>
1474  </xsl:template>
1475
1476  <xsl:template name="cos">
1477    <xsl:param name="angle" />
1478    <xsl:param name="precision" select="0.00000001"/>
1479
1480    <xsl:call-template name="sin">
1481      <xsl:with-param name="angle" select="$halfPi - $angle" />
1482      <xsl:with-param name="precision" select="$precision" />
1483    </xsl:call-template>
1484  </xsl:template>
1485
1486  <!-- Find the nearest intersection into the polygon along the line ($x,$y)-$linepoint.
1487       Can also be used for ray-casting point-in-polygon checking -->
1488  <xsl:template name="areacenterNearestIntersectionInside">
1489    <xsl:param name="x" />
1490    <xsl:param name="y" />
1491    <xsl:param name="edgestart" />
1492    <xsl:param name="linepoint_x" />
1493    <xsl:param name="linepoint_y" />
1494    <xsl:param name="holerelation" />
1495    <xsl:param name="intersectioncount_on" select="0" /><!-- Number of intersections. Only counts those on segment (x,y)-linepoint -->
1496    <xsl:param name="nearest_on_x" />
1497    <xsl:param name="nearest_on_y" />
1498    <xsl:param name="nearest_on_dist" select="'NaN'" />
1499    <xsl:param name="nearest_off_x" />
1500    <xsl:param name="nearest_off_y" />
1501    <xsl:param name="nearest_off_dist" select="'NaN'" />
1502
1503    <xsl:choose>
1504      <!-- If there are no more vertices we don't have a second point for the edge, and are finished -->
1505      <xsl:when test="$edgestart/following-sibling::nd[1]">
1506        <xsl:variable name="edgeend" select="$edgestart/following-sibling::nd[1]" />
1507        <!-- Get the intersection point between the line ($x,$y)-$linepoint and $edgestart-$edgeend -->
1508        <xsl:variable name="intersection">
1509          <xsl:choose>
1510            <xsl:when test="( $x = key('nodeById', $edgestart/@ref)/@lon and $y = key('nodeById', $edgestart/@ref)/@lat ) or
1511                            ( $x = key('nodeById', $edgeend/@ref)/@lon and $y = key('nodeById', $edgeend/@ref)/@lat )">
1512              <!-- (x,y) is one of the points in edge, skip -->
1513              NoIntersection
1514            </xsl:when>
1515            <xsl:otherwise>     
1516              <xsl:call-template name="areacenterLinesIntersection">
1517                <xsl:with-param name="x1" select="$x" />
1518                <xsl:with-param name="y1" select="$y" />
1519                <xsl:with-param name="x2" select="$linepoint_x" />
1520                <xsl:with-param name="y2" select="$linepoint_y" />
1521                <xsl:with-param name="x3" select="key('nodeById', $edgestart/@ref)/@lon" />
1522                <xsl:with-param name="y3" select="key('nodeById', $edgestart/@ref)/@lat" />
1523                <xsl:with-param name="x4" select="key('nodeById', $edgeend/@ref)/@lon" />
1524                <xsl:with-param name="y4" select="key('nodeById', $edgeend/@ref)/@lat" />
1525              </xsl:call-template>
1526            </xsl:otherwise>
1527          </xsl:choose>
1528        </xsl:variable>
1529
1530        <!-- Haul ix, iy, ua and ub out of the csv -->
1531        <xsl:variable name="ix" select="substring-before($intersection, ',')" />
1532        <xsl:variable name="iy" select="substring-before(substring-after($intersection, ','), ',')" />
1533        <xsl:variable name="ua" select="substring-before(substring-after(substring-after($intersection, ','), ','), ',')" />
1534        <xsl:variable name="ub" select="substring-after(substring-after(substring-after($intersection, ','), ','), ',')" />
1535
1536        <!-- A) Is there actually an intersection? B) Is it on edge? -->
1537        <xsl:choose>
1538          <xsl:when test="$intersection != 'NoIntersection' and $ub &gt; 0 and $ub &lt;= 1">
1539            <xsl:variable name="distance">
1540              <xsl:call-template name="areacenterPointDistance">
1541                <xsl:with-param name="x1" select="$x" />
1542                <xsl:with-param name="y1" select="$y" />
1543                <xsl:with-param name="x2" select="$ix" />
1544                <xsl:with-param name="y2" select="$iy" />
1545              </xsl:call-template>
1546            </xsl:variable>
1547
1548            <!-- Is intersection on the segment ($x,$y)-$linepoint, or on the other side of ($x,$y)? -->
1549            <xsl:variable name="isOnSegment">
1550              <xsl:if test="$ua &gt;= 0">Yes</xsl:if>
1551            </xsl:variable>
1552           
1553            <xsl:variable name="isNewNearestOn">
1554              <xsl:if test="$isOnSegment = 'Yes' and ( $nearest_on_dist = 'NaN' or $distance &lt; $nearest_on_dist )">Yes</xsl:if>
1555            </xsl:variable>
1556           
1557            <xsl:variable name="isNewNearestOff">
1558              <xsl:if test="$isOnSegment != 'Yes' and ( $nearest_off_dist = 'NaN' or $distance &lt; $nearest_off_dist )">Yes</xsl:if>
1559            </xsl:variable>
1560
1561            <xsl:call-template name="areacenterNearestIntersectionInside">
1562              <xsl:with-param name="x" select="$x" />
1563              <xsl:with-param name="y" select="$y" />
1564              <xsl:with-param name="linepoint_x" select="$linepoint_x" />
1565              <xsl:with-param name="linepoint_y" select="$linepoint_y" />
1566              <xsl:with-param name="edgestart" select="$edgeend" />
1567              <xsl:with-param name="holerelation" select="$holerelation" />
1568              <xsl:with-param name="intersectioncount_on" select="$intersectioncount_on + number(boolean($isOnSegment = 'Yes'))" />
1569              <xsl:with-param name="nearest_on_dist"> <xsl:choose>
1570                <xsl:when test="$isNewNearestOn = 'Yes'"> <xsl:value-of select="$distance" /> </xsl:when>
1571                <xsl:otherwise> <xsl:value-of select="$nearest_on_dist" /> </xsl:otherwise>
1572              </xsl:choose> </xsl:with-param>
1573              <xsl:with-param name="nearest_on_x"> <xsl:choose>
1574                <xsl:when test="$isNewNearestOn = 'Yes'"> <xsl:value-of select="$ix" /> </xsl:when>
1575                <xsl:otherwise> <xsl:value-of select="$nearest_on_x" /> </xsl:otherwise>
1576              </xsl:choose> </xsl:with-param>
1577              <xsl:with-param name="nearest_on_y"> <xsl:choose>
1578                <xsl:when test="$isNewNearestOn = 'Yes'"> <xsl:value-of select="$iy" /> </xsl:when>
1579                <xsl:otherwise> <xsl:value-of select="$nearest_on_y" /> </xsl:otherwise>
1580              </xsl:choose> </xsl:with-param>
1581              <xsl:with-param name="nearest_off_dist"> <xsl:choose>
1582                <xsl:when test="$isNewNearestOff = 'Yes'"> <xsl:value-of select="$distance" /> </xsl:when>
1583                <xsl:otherwise> <xsl:value-of select="$nearest_off_dist" /> </xsl:otherwise>
1584              </xsl:choose> </xsl:with-param>
1585              <xsl:with-param name="nearest_off_x"> <xsl:choose>
1586                <xsl:when test="$isNewNearestOff = 'Yes'"> <xsl:value-of select="$ix" /> </xsl:when>
1587                <xsl:otherwise> <xsl:value-of select="$nearest_off_x" /> </xsl:otherwise>
1588              </xsl:choose> </xsl:with-param>
1589              <xsl:with-param name="nearest_off_y"> <xsl:choose>
1590                <xsl:when test="$isNewNearestOff = 'Yes'"> <xsl:value-of select="$iy" /> </xsl:when>
1591                <xsl:otherwise> <xsl:value-of select="$nearest_off_y" /> </xsl:otherwise>
1592              </xsl:choose> </xsl:with-param>
1593            </xsl:call-template>
1594          </xsl:when>
1595          <!-- No intersection, just go on to next edge -->
1596          <xsl:otherwise>
1597            <xsl:call-template name="areacenterNearestIntersectionInside">
1598              <xsl:with-param name="x" select="$x" />
1599              <xsl:with-param name="y" select="$y" />
1600              <xsl:with-param name="linepoint_x" select="$linepoint_x" />
1601              <xsl:with-param name="linepoint_y" select="$linepoint_y" />
1602              <xsl:with-param name="edgestart" select="$edgeend" />
1603              <xsl:with-param name="holerelation" select="$holerelation" />
1604              <xsl:with-param name="intersectioncount_on" select="$intersectioncount_on" />
1605              <xsl:with-param name="nearest_on_dist" select="$nearest_on_dist" />
1606              <xsl:with-param name="nearest_on_x" select="$nearest_on_x" />
1607              <xsl:with-param name="nearest_on_y" select="$nearest_on_y" />
1608              <xsl:with-param name="nearest_off_dist" select="$nearest_off_dist" />
1609              <xsl:with-param name="nearest_off_x" select="$nearest_off_x" />
1610              <xsl:with-param name="nearest_off_y" select="$nearest_off_y" />
1611            </xsl:call-template>
1612          </xsl:otherwise>
1613        </xsl:choose>
1614      </xsl:when>
1615      <!-- Is there a hole in the polygon, and were we working on the outer one? Then we start edge detection against the hole. -->
1616      <xsl:when test="$holerelation and
1617                      $holerelation/member[@ref = $edgestart/../@id][@role='outer']">
1618        <xsl:variable name="nextnode" select="key('wayById', $holerelation/member[@type='way'][@role='inner'][1]/@ref)/nd[1]"/>
1619        <xsl:call-template name="areacenterNearestIntersectionInside">
1620          <xsl:with-param name="x" select="$x" />
1621          <xsl:with-param name="y" select="$y" />
1622          <xsl:with-param name="linepoint_x" select="$linepoint_x" />
1623          <xsl:with-param name="linepoint_y" select="$linepoint_y" />
1624          <xsl:with-param name="edgestart" select="$nextnode" />
1625          <xsl:with-param name="holerelation" select="$holerelation" />
1626          <xsl:with-param name="intersectioncount_on" select="$intersectioncount_on" />
1627          <xsl:with-param name="nearest_on_dist" select="$nearest_on_dist" />
1628          <xsl:with-param name="nearest_on_x" select="$nearest_on_x" />
1629          <xsl:with-param name="nearest_on_y" select="$nearest_on_y" />
1630          <xsl:with-param name="nearest_off_dist" select="$nearest_off_dist" />
1631          <xsl:with-param name="nearest_off_x" select="$nearest_off_x" />
1632          <xsl:with-param name="nearest_off_y" select="$nearest_off_y" />
1633        </xsl:call-template>
1634      </xsl:when>
1635      <!-- Is there a hole in the polygon, and were we working working on one of the inner ones? Then go to the next hole, if there is one -->
1636      <xsl:when test="$holerelation and
1637                      $holerelation/member[@ref = $edgestart/../@id][@type='way'][@role='inner']/following-sibling::member[@role='inner']">
1638        <xsl:variable name="nextnode" select="key('wayById', $holerelation/member[@ref = $edgestart/../@id][@type='way'][@role='inner']/following-sibling::member[@role='inner']/@ref)/nd[1]"/>
1639        <xsl:call-template name="areacenterNearestIntersectionInside">
1640          <xsl:with-param name="x" select="$x" />
1641          <xsl:with-param name="y" select="$y" />
1642          <xsl:with-param name="linepoint_x" select="$linepoint_x" />
1643          <xsl:with-param name="linepoint_y" select="$linepoint_y" />
1644          <xsl:with-param name="edgestart" select="$nextnode" />
1645          <xsl:with-param name="holerelation" select="$holerelation" />
1646          <xsl:with-param name="intersectioncount_on" select="$intersectioncount_on" />
1647          <xsl:with-param name="nearest_on_dist" select="$nearest_on_dist" />
1648          <xsl:with-param name="nearest_on_x" select="$nearest_on_x" />
1649          <xsl:with-param name="nearest_on_y" select="$nearest_on_y" />
1650          <xsl:with-param name="nearest_off_dist" select="$nearest_off_dist" />
1651          <xsl:with-param name="nearest_off_x" select="$nearest_off_x" />
1652          <xsl:with-param name="nearest_off_y" select="$nearest_off_y" />
1653        </xsl:call-template>
1654      </xsl:when>
1655      <xsl:otherwise>
1656        <!-- No more edges, return data -->
1657        <xsl:value-of select="$intersectioncount_on" />;
1658        <xsl:value-of select="$nearest_on_x"/>,<xsl:value-of select="$nearest_on_y"/>,<xsl:value-of select="$nearest_on_dist"/>;
1659        <xsl:value-of select="$nearest_off_x"/>,<xsl:value-of select="$nearest_off_y"/>,<xsl:value-of select="$nearest_off_dist"/>;
1660      </xsl:otherwise>
1661    </xsl:choose>
1662  </xsl:template>
1663
1664  <!-- Find the distance to the edge nearest (x,y) -->
1665  <xsl:template name="areacenterNearestEdge">
1666    <xsl:param name="x" />
1667    <xsl:param name="y" />
1668    <xsl:param name="edgestart" />
1669    <xsl:param name="holerelation" />
1670    <xsl:param name="nearest_dist" select="'NaN'" />
1671
1672    <xsl:choose>
1673      <!-- If there are no more vertices we don't have a second point for the edge, and are finished -->
1674      <xsl:when test="$edgestart/following-sibling::nd[1]">
1675        <xsl:variable name="edgeend" select="$edgestart/following-sibling::nd[1]" />
1676
1677        <xsl:variable name="distance">
1678          <xsl:call-template name="areacenterDistancePointSegment">
1679            <xsl:with-param name="x" select="$x" />
1680            <xsl:with-param name="y" select="$y" />
1681            <xsl:with-param name="x1" select="key('nodeById', $edgestart/@ref)/@lon" />
1682            <xsl:with-param name="y1" select="key('nodeById', $edgestart/@ref)/@lat" />
1683            <xsl:with-param name="x2" select="key('nodeById', $edgeend/@ref)/@lon" />
1684            <xsl:with-param name="y2" select="key('nodeById', $edgeend/@ref)/@lat" />
1685          </xsl:call-template>
1686        </xsl:variable>
1687
1688        <!-- Did we get a valid distance?
1689             There is some code in DistancePointSegment that can return NaN in some cases -->
1690        <xsl:choose>
1691          <xsl:when test="string(number($distance)) != 'NaN'">
1692            <xsl:call-template name="areacenterNearestEdge">
1693              <xsl:with-param name="x" select="$x" />
1694              <xsl:with-param name="y" select="$y" />
1695              <xsl:with-param name="edgestart" select="$edgeend" />
1696              <xsl:with-param name="holerelation" select="$holerelation" />
1697              <xsl:with-param name="nearest_dist"> <xsl:choose>
1698                <xsl:when test="$nearest_dist = 'NaN' or $distance &lt; $nearest_dist"> <xsl:value-of select="$distance" /> </xsl:when>
1699                <xsl:otherwise> <xsl:value-of select="$nearest_dist" /> </xsl:otherwise>
1700              </xsl:choose> </xsl:with-param>
1701            </xsl:call-template>
1702          </xsl:when>
1703
1704          <xsl:otherwise>
1705            <xsl:call-template name="areacenterNearestEdge">
1706              <xsl:with-param name="x" select="$x" />
1707              <xsl:with-param name="y" select="$y" />
1708              <xsl:with-param name="edgestart" select="$edgeend" />
1709              <xsl:with-param name="holerelation" select="$holerelation" />
1710              <xsl:with-param name="nearest_dist" select="$nearest_dist" />
1711            </xsl:call-template>
1712          </xsl:otherwise>
1713        </xsl:choose>
1714      </xsl:when>
1715      <!-- Is there a hole in the polygon, and were we working on the outer one? Then we start edge detection against the hole. -->
1716      <xsl:when test="$holerelation and
1717                      $holerelation/member[@ref = $edgestart/../@id][@role='outer']">
1718        <xsl:variable name="nextnode" select="key('wayById', $holerelation/member[@type='way'][@role='inner'][1]/@ref)/nd[1]"/>
1719        <xsl:call-template name="areacenterNearestEdge">
1720          <xsl:with-param name="x" select="$x" />
1721          <xsl:with-param name="y" select="$y" />
1722          <xsl:with-param name="edgestart" select="$nextnode" />
1723          <xsl:with-param name="holerelation" select="$holerelation" />
1724          <xsl:with-param name="nearest_dist" select="$nearest_dist" />
1725        </xsl:call-template>
1726      </xsl:when>
1727      <!-- Is there a hole in the polygon, and were we working working on one of the inner ones? Then go to the next hole, if there is one -->
1728      <xsl:when test="$holerelation and
1729                      $holerelation/member[@ref = $edgestart/../@id][@type='way'][@role='inner']/following-sibling::member[@role='inner']">
1730        <xsl:variable name="nextnode" select="key('wayById', $holerelation/member[@ref = $edgestart/../@id][@type='way'][@role='inner']/following-sibling::member[@role='inner']/@ref)/nd[1]"/>
1731        <xsl:call-template name="areacenterNearestEdge">
1732          <xsl:with-param name="x" select="$x" />
1733          <xsl:with-param name="y" select="$y" />
1734          <xsl:with-param name="edgestart" select="$nextnode" />
1735          <xsl:with-param name="holerelation" select="$holerelation" />
1736          <xsl:with-param name="nearest_dist" select="$nearest_dist" />
1737        </xsl:call-template>
1738      </xsl:when>
1739      <xsl:otherwise>
1740        <!-- No more edges, return data -->
1741        <xsl:value-of select="$nearest_dist" />
1742      </xsl:otherwise>
1743    </xsl:choose>
1744  </xsl:template>
1745
1746  <!-- Find the distance between the point (x,y) and the segment x1,y1 -> x2,y2 -->
1747  <!-- Based on http://local.wasp.uwa.edu.au/~pbourke/geometry/pointline/ and the
1748       Delphi example by Graham O'Brien -->
1749  <xsl:template name="areacenterDistancePointSegment">
1750    <xsl:param name="x" />
1751    <xsl:param name="y" />
1752    <xsl:param name="x1" />
1753    <xsl:param name="y1" />
1754    <xsl:param name="x2" />
1755    <xsl:param name="y2" />
1756
1757    <!-- Constants -->
1758    <xsl:variable name="EPS" select="0.000001" />
1759    <xsl:variable name="EPSEPS" select="$EPS * $EPS" />
1760
1761    <!-- The line magnitude, squared -->
1762    <xsl:variable name="sqLineMagnitude" select="($x2 - $x1) * ($x2 - $x1) + ($y2 - $y1) * ($y2 - $y1)" />
1763
1764    <xsl:choose>
1765      <xsl:when test="sqLineMagnitude &lt; $EPSEPS">
1766        NaN
1767      </xsl:when>
1768      <xsl:otherwise>
1769        <xsl:variable name="u" select="( ($x - $x1)*($x2 - $x1) + ($y - $y1)*($y2 - $y1) ) div sqLineMagnitude" />
1770
1771        <xsl:variable name="result">
1772          <xsl:choose>
1773            <xsl:when test="u &lt; $EPS or u &gt; 1">
1774              <!-- Closest point in not on segment, return shortest distance to an endpoint -->
1775              <xsl:variable name="dist1" select="($x1 - $x) * ($x1 - $x) + ($y1 - $y) * ($y1 - $y)" />
1776              <xsl:variable name="dist2" select="($x2 - $x) * ($x2 - $x) + ($y2 - $y) * ($y2 - $y)" />
1777             
1778              <!-- min($dist1, $dist2) -->
1779              <xsl:choose>
1780                <xsl:when test="$dist1 &lt; $dist2">
1781                  <xsl:value-of select="$dist1" />
1782                </xsl:when>
1783                <xsl:otherwise>
1784                  <xsl:value-of select="$dist2" />
1785                </xsl:otherwise>
1786              </xsl:choose>
1787             
1788            </xsl:when>
1789            <xsl:otherwise>
1790              <xsl:variable name="ix" select="$x1 + $u * ($x2 - $x1)" />
1791              <xsl:variable name="iy" select="$y1 + $u * ($y2 - $y1)" />
1792              <xsl:value-of select="($ix - $x) * ($ix - $x) + ($iy - $y) * ($iy - $y)" />
1793            </xsl:otherwise>
1794          </xsl:choose>
1795        </xsl:variable>
1796
1797        <!-- Finally return the square root of the result, as we were working with squared distances -->
1798        <xsl:call-template name="sqrt">
1799          <xsl:with-param name="num" select="$result" />
1800        </xsl:call-template>
1801      </xsl:otherwise>
1802    </xsl:choose>
1803
1804  </xsl:template>
1805
1806  <!--
1807      Finds intersection point between lines x1,y1 -> x2,y2 and x3,y3 -> x4,y4.
1808      Returns a comma-separated list of x,y,ua,ub or NoIntersection if the lines do not intersect
1809  -->
1810  <xsl:template name="areacenterLinesIntersection">
1811    <xsl:param name="x1" />
1812    <xsl:param name="y1" />
1813    <xsl:param name="x2" />
1814    <xsl:param name="y2" />
1815    <xsl:param name="x3" />
1816    <xsl:param name="y3" />
1817    <xsl:param name="x4" />
1818    <xsl:param name="y4" />
1819
1820    <xsl:variable name="denom" select="(( $y4 - $y3 ) * ( $x2 - $x1 )) -
1821                                       (( $x4 - $x3 ) * ( $y2 - $y1 ))" />
1822    <xsl:variable name="nume_a" select="(( $x4 - $x3 ) * ( $y1 - $y3 )) -
1823                                        (( $y4 - $y3 ) * ( $x1 - $x3 ))" />
1824    <xsl:variable name="nume_b" select="(( $x2 - $x1 ) * ( $y1 - $y3 )) -
1825                                        (( $y2 - $y1 ) * ( $x1 - $x3 ))" />
1826
1827    <xsl:choose>
1828      <xsl:when test="$denom = 0">
1829        NoIntersection
1830      </xsl:when>
1831      <xsl:otherwise>
1832        <xsl:variable name="ua" select="$nume_a div $denom" />
1833        <xsl:variable name="ub" select="$nume_b div $denom" />
1834
1835        <!-- x,y,ua,ub -->
1836        <xsl:value-of select="$x1 + $ua * ($x2 - $x1)" />,<xsl:value-of select="$y1 + $ua * ($y2 - $y1)" />,<xsl:value-of select="$ua" />,<xsl:value-of select="$ub" />
1837      </xsl:otherwise>
1838    </xsl:choose>
1839  </xsl:template>
1840
1841  <!-- Distance between two points -->
1842  <xsl:template name="areacenterPointDistance">
1843    <xsl:param name="x1" />
1844    <xsl:param name="y1" />
1845    <xsl:param name="x2" />
1846    <xsl:param name="y2" />
1847
1848    <!-- sqrt( ($x2 - $x1)**2 + ($y2 - $y1)**2 ) -->
1849    <xsl:call-template name="sqrt">
1850      <xsl:with-param name="num" select="($x2*$x2 - $x2*$x1 - $x1*$x2 + $x1*$x1) + ($y2*$y2 - $y2*$y1 - $y1*$y2 + $y1*$y1)" />
1851    </xsl:call-template>
1852  </xsl:template>
1853
1854  <xsl:template name="sqrt">
1855    <xsl:param name="num" select="0"/>  <!-- The number you want to find the
1856                                             square root of -->
1857    <xsl:param name="try" select="1"/>  <!-- The current 'try'.  This is used
1858                                             internally. -->
1859    <xsl:param name="iter" select="1"/> <!-- The current iteration, checked
1860                                             against maxiter to limit loop count -->
1861    <xsl:param name="maxiter" select="10"/>  <!-- Set this up to insure
1862against infinite loops -->
1863   
1864    <!-- This template was written by Nate Austin using Sir Isaac Newton's
1865         method of finding roots -->
1866   
1867    <xsl:choose>
1868      <xsl:when test="$try * $try = $num or $iter &gt; $maxiter">
1869        <xsl:value-of select="$try"/>
1870      </xsl:when>
1871      <xsl:otherwise>
1872        <xsl:call-template name="sqrt">
1873          <xsl:with-param name="num" select="$num"/>
1874          <xsl:with-param name="try" select="$try - (($try * $try - $num) div
1875                                             (2 * $try))"/>
1876          <xsl:with-param name="iter" select="$iter + 1"/>
1877          <xsl:with-param name="maxiter" select="$maxiter"/>
1878        </xsl:call-template>
1879      </xsl:otherwise>
1880    </xsl:choose>
1881  </xsl:template>
1882
1883  <!-- Returns the medium value of all the points -->
1884  <xsl:template name="areacenterMediumOfPoints">
1885    <xsl:param name="points" />
1886    <xsl:param name="total_x" select="0" />
1887    <xsl:param name="total_y" select="0" />
1888    <xsl:param name="total_dist" select="0" />
1889    <xsl:param name="count" select="0" />
1890
1891    <xsl:variable name="point" select="substring-before($points, ';')" />
1892
1893    <xsl:choose>
1894      <xsl:when test="string-length($point) &gt; 0">
1895        <xsl:variable name="x" select="substring-before($point, ',')" />
1896        <xsl:variable name="y" select="substring-before(substring-after($point, ','), ',')" />
1897        <xsl:variable name="dist" select="substring-after(substring-after($point, ','), ',')" />
1898
1899        <xsl:call-template name="areacenterMediumOfPoints">
1900          <xsl:with-param name="points" select="substring-after($points, ';')" />
1901          <xsl:with-param name="total_x" select="$total_x + $x" />
1902          <xsl:with-param name="total_y" select="$total_y + $y" />
1903          <xsl:with-param name="total_dist" select="$total_dist + $dist" />
1904          <xsl:with-param name="count" select="$count + 1" />
1905        </xsl:call-template>
1906      </xsl:when>
1907      <xsl:otherwise>
1908        <xsl:value-of select="$total_x div $count" />,<xsl:value-of select="$total_y div $count" />,<xsl:value-of select="$total_dist div $count" />
1909      </xsl:otherwise>
1910    </xsl:choose>
1911  </xsl:template>
1912
1913  <!-- Returns the coordinates of the point that scores highest.
1914       The score is based on the distance to (x,y),
1915       the distance between the point and it's vertex,
1916       and the medium of that distance in all the points -->
1917  <xsl:template name="areacenterBestPoint">
1918    <xsl:param name="points" />
1919    <xsl:param name="x" />
1920    <xsl:param name="y" />
1921    <xsl:param name="nearest_x" />
1922    <xsl:param name="nearest_y" />
1923    <xsl:param name="medium_dist" />
1924    <xsl:param name="nearest_score" />
1925    <xsl:param name="nearest_dist" select="'NaN'" />
1926
1927    <xsl:variable name="point" select="substring-before($points, ';')" />
1928
1929    <xsl:choose>
1930      <xsl:when test="string-length($point) &gt; 0"> 
1931        <xsl:variable name="point_x" select="substring-before($point, ',')" />
1932        <xsl:variable name="point_y" select="substring-before(substring-after($point, ','), ',')" />
1933        <xsl:variable name="point_dist" select="substring-after(substring-after($point, ','), ',')" />
1934       
1935        <xsl:variable name="distance">
1936          <xsl:call-template name="areacenterPointDistance">
1937            <xsl:with-param name="x1" select="$x" />
1938            <xsl:with-param name="y1" select="$y" />
1939            <xsl:with-param name="x2" select="$point_x" />
1940            <xsl:with-param name="y2" select="$point_y" />
1941          </xsl:call-template>
1942        </xsl:variable>
1943
1944        <xsl:variable name="score" select="0 - $distance + $point_dist + $point_dist - $medium_dist"/>
1945        <xsl:variable name="isNewNearest" select="$nearest_dist = 'NaN' or $score &gt; $nearest_score" />
1946
1947        <xsl:call-template name="areacenterBestPoint">
1948          <xsl:with-param name="points" select="substring-after($points, ';')" />
1949          <xsl:with-param name="x" select="$x" />
1950          <xsl:with-param name="y" select="$y" />
1951          <xsl:with-param name="medium_dist" select="$medium_dist" />
1952          <xsl:with-param name="nearest_dist"><xsl:choose>
1953            <xsl:when test="$isNewNearest"><xsl:value-of select="$distance" /></xsl:when>
1954            <xsl:otherwise><xsl:value-of select="$nearest_dist" /></xsl:otherwise>
1955          </xsl:choose></xsl:with-param>
1956          <xsl:with-param name="nearest_x"><xsl:choose>
1957            <xsl:when test="$isNewNearest"><xsl:value-of select="$point_x" /></xsl:when>
1958            <xsl:otherwise><xsl:value-of select="$nearest_x" /></xsl:otherwise>
1959          </xsl:choose></xsl:with-param>
1960          <xsl:with-param name="nearest_y"><xsl:choose>
1961            <xsl:when test="$isNewNearest"><xsl:value-of select="$point_y" /></xsl:when>
1962            <xsl:otherwise><xsl:value-of select="$nearest_y" /></xsl:otherwise>
1963          </xsl:choose></xsl:with-param>
1964          <xsl:with-param name="nearest_score"><xsl:choose>
1965            <xsl:when test="$isNewNearest"><xsl:value-of select="$score" /></xsl:when>
1966            <xsl:otherwise><xsl:value-of select="$nearest_score" /></xsl:otherwise>
1967          </xsl:choose></xsl:with-param>
1968        </xsl:call-template>
1969      </xsl:when>
1970      <xsl:otherwise>
1971        <xsl:value-of select="$nearest_x" />, <xsl:value-of select="$nearest_y" />
1972      </xsl:otherwise>
1973    </xsl:choose>
1974  </xsl:template>
1975
1976  <!-- Process a <text> instruction -->
1977  <xsl:template match="text">
1978    <xsl:param name="elements"/>
1979
1980    <!-- This is the instruction that is currently being processed -->
1981    <xsl:variable name="instruction" select="."/>
1982
1983    <!-- Select all <node> elements that have a key that matches the k attribute of the text instruction -->
1984    <xsl:for-each select="$elements[name()='node'][tag[@k=$instruction/@k]]">
1985      <xsl:call-template name="renderText">
1986        <xsl:with-param name="instruction" select="$instruction"/>
1987      </xsl:call-template>
1988    </xsl:for-each>
1989
1990    <!-- Select all <way> elements -->
1991    <xsl:apply-templates select="$elements[name()='way']" mode="textPath">
1992      <xsl:with-param name="instruction" select="$instruction"/>
1993    </xsl:apply-templates>
1994  </xsl:template>
1995
1996
1997  <!-- Suppress output of any unhandled elements -->
1998  <xsl:template match="*" mode="textPath"/>
1999
2000
2001  <!-- Render textPaths for a way -->
2002  <xsl:template match="way" mode="textPath">
2003    <xsl:param name="instruction"/>
2004
2005    <!-- The current <way> element -->
2006    <xsl:variable name="way" select="."/>
2007
2008    <!-- DODI: !!!WORKAROUND!!! no text for one node ways-->
2009    <xsl:if test="count($way/nd) &gt; 1">
2010      <xsl:variable name='text'>
2011        <xsl:choose>
2012          <xsl:when test='$instruction/@k'>
2013            <xsl:value-of select='tag[@k=$instruction/@k]/@v'/>
2014          </xsl:when>
2015          <xsl:otherwise>
2016            <xsl:apply-templates select='$instruction' mode='textFormat'>
2017              <xsl:with-param name='way' select='$way'/>
2018            </xsl:apply-templates>
2019          </xsl:otherwise>
2020        </xsl:choose>
2021      </xsl:variable>
2022
2023      <xsl:if test='string($text)'>
2024
2025        <xsl:variable name="pathDirection">
2026          <xsl:choose>
2027            <!-- Manual override, reverse direction -->
2028            <xsl:when test="tag[@k='name_direction']/@v='-1' or tag[@k='osmarender:nameDirection']/@v='-1'">reverse</xsl:when>
2029            <!-- Manual override, normal direction -->
2030            <xsl:when test="tag[@k='name_direction']/@v='1' or tag[@k='osmarender:nameDirection']/@v='1'">normal</xsl:when>
2031            <!-- Automatic, reverse direction -->
2032            <xsl:when test="(key('nodeById',$way/nd[1]/@ref)/@lon &gt; key('nodeById',$way/nd[last()]/@ref)/@lon)">reverse</xsl:when>
2033            <!-- Automatic, normal direction -->
2034            <xsl:otherwise>normal</xsl:otherwise>
2035          </xsl:choose>
2036        </xsl:variable>
2037
2038        <xsl:variable name="wayPath">
2039          <xsl:choose>
2040            <!-- Normal -->
2041            <xsl:when test='$pathDirection="normal"'>
2042              <xsl:value-of select="concat('way_normal_',@id)"/>
2043            </xsl:when>
2044            <!-- Reverse -->
2045            <xsl:otherwise>
2046              <xsl:value-of select="concat('way_reverse_',@id)"/>
2047            </xsl:otherwise>
2048          </xsl:choose>
2049        </xsl:variable>
2050
2051        <xsl:call-template name="renderTextPath">
2052          <xsl:with-param name="instruction" select="$instruction"/>
2053          <xsl:with-param name="pathId" select="$wayPath"/>
2054          <xsl:with-param name="pathDirection" select="$pathDirection"/>
2055          <xsl:with-param name="text" select="$text"/>
2056        </xsl:call-template>
2057      </xsl:if>
2058    </xsl:if>
2059  </xsl:template>
2060
2061  <!-- Process extended form of text instruction -->
2062  <xsl:template match='text' mode='textFormat'>
2063    <xsl:param name='way'/>
2064
2065    <xsl:apply-templates mode='textFormat'>
2066      <xsl:with-param name='way' select='$way'/>
2067    </xsl:apply-templates>
2068  </xsl:template>
2069
2070
2071  <!-- Substitute a tag in a text instruction -->
2072  <xsl:template match='text/tag' mode='textFormat'>
2073    <xsl:param name='way'/>
2074
2075    <xsl:variable name='key' select='@k'/>
2076    <xsl:variable name='value'>
2077      <xsl:choose>
2078        <xsl:when test='$key="osm:user"'>
2079          <xsl:value-of select='$way/@user'/>
2080        </xsl:when>
2081        <xsl:when test='$key="osm:timestamp"'>
2082          <xsl:value-of select='$way/@timestamp'/>
2083        </xsl:when>
2084        <xsl:when test='$key="osm:id"'>
2085          <xsl:value-of select='$way/@id'/>
2086        </xsl:when>
2087        <xsl:otherwise>
2088          <xsl:value-of select='$way/tag[@k=$key]/@v'/>
2089        </xsl:otherwise>
2090      </xsl:choose>
2091    </xsl:variable>
2092    <xsl:choose>
2093      <xsl:when test='string($value)'>
2094        <xsl:value-of select='$value'/>
2095      </xsl:when>
2096      <xsl:otherwise>
2097        <xsl:value-of select='@default'/>
2098      </xsl:otherwise>
2099    </xsl:choose>
2100  </xsl:template>
2101
2102
2103
2104  <!-- Generate a way path for the current way element -->
2105  <xsl:template name="generateWayPaths">
2106    <!-- DODI: !!!WORKAROUND!!! skip one node ways -->
2107    <xsl:if test="count(nd) &gt; 1">
2108
2109      <!-- Generate a normal way path -->
2110      <xsl:variable name="pathWayNormal">
2111        <xsl:call-template name="generateWayPathNormal"/>
2112      </xsl:variable>
2113      <xsl:if test="$pathWayNormal!=''">
2114        <path id="way_normal_{@id}" d="{$pathWayNormal}"/>
2115      </xsl:if>
2116
2117      <!-- Generate a normal way path as area -->
2118      <!-- DODI: !!!WORKAROUND!!! added to generate "area for all ways, yes it is very dirty... but -->
2119      <!-- DODI: removed because of line2curves.pl duplicate node detection problem -->
2120      <!-- <xsl:variable name="pathArea">
2121      <xsl:call-template name="generateAreaPath"/>
2122    </xsl:variable>
2123    <path id="area_{@id}" d="{$pathArea}"/> -->
2124      <!-- Generate a reverse way path (if needed) -->
2125      <xsl:variable name="pathWayReverse">
2126        <xsl:choose>
2127          <!-- Manual override, reverse direction -->
2128          <xsl:when test="tag[@k='name_direction']/@v='-1' or tag[@k='osmarender:nameDirection']/@v='-1'">
2129            <xsl:call-template name="generateWayPathReverse"/>
2130          </xsl:when>
2131          <!-- Manual override, normal direction -->
2132          <xsl:when test="tag[@k='name_direction']/@v='1' or tag[@k='osmarender:nameDirection']/@v='1'">
2133            <!-- Generate nothing -->
2134          </xsl:when>
2135          <!-- Automatic, reverse direction -->
2136          <xsl:when test="(key('nodeById',nd[1]/@ref)/@lon &gt; key('nodeById',nd[last()]/@ref)/@lon)">
2137            <xsl:call-template name="generateWayPathReverse"/>
2138          </xsl:when>
2139        </xsl:choose>
2140      </xsl:variable>
2141      <xsl:if test="$pathWayReverse!=''">
2142        <path id="way_reverse_{@id}" d="{$pathWayReverse}"/>
2143      </xsl:if>
2144
2145      <!-- Generate the start, middle and end paths needed for smart-linecaps (TM). -->
2146      <xsl:variable name="pathWayStart">
2147        <xsl:call-template name="generatePathWayStart"/>
2148      </xsl:variable>
2149      <path id="way_start_{@id}" d="{$pathWayStart}"/>
2150
2151      <xsl:if test="count(nd) &gt; 1">
2152        <xsl:variable name="pathWayMid">
2153          <xsl:call-template name="generatePathWayMid"/>
2154        </xsl:variable>
2155        <path id="way_mid_{@id}" d="{$pathWayMid}"/>
2156      </xsl:if>
2157
2158      <xsl:variable name="pathWayEnd">
2159        <xsl:call-template name="generatePathWayEnd"/>
2160      </xsl:variable>
2161      <path id="way_end_{@id}" d="{$pathWayEnd}"/>
2162    </xsl:if >
2163  </xsl:template>
2164
2165
2166  <!-- Generate a normal way path -->
2167  <xsl:template name="generateWayPathNormal">
2168    <xsl:for-each select="nd[key('nodeById',@ref) ]">
2169      <xsl:choose>
2170        <xsl:when test="position()=1">
2171          <xsl:call-template name="moveToNode">
2172            <xsl:with-param name="node" select="key('nodeById',@ref)"/>
2173          </xsl:call-template>
2174        </xsl:when>
2175        <xsl:otherwise>
2176          <xsl:call-template name="lineToNode">
2177            <xsl:with-param name="node" select="key('nodeById',@ref)"/>
2178          </xsl:call-template>
2179        </xsl:otherwise>
2180      </xsl:choose>
2181    </xsl:for-each>
2182  </xsl:template>
2183
2184
2185  <!-- Generate a reverse way path -->
2186  <xsl:template name="generateWayPathReverse">
2187    <xsl:for-each select="nd[key('nodeById',@ref)]">
2188      <xsl:sort select="position()" data-type="number" order="descending"/>
2189      <xsl:choose>
2190        <xsl:when test="position()=1">
2191          <xsl:call-template name="moveToNode">
2192            <xsl:with-param name="node" select="key('nodeById',@ref)"/>
2193          </xsl:call-template>
2194        </xsl:when>
2195        <xsl:otherwise>
2196          <xsl:call-template name="lineToNode">
2197            <xsl:with-param name="node" select="key('nodeById',@ref)"/>
2198          </xsl:call-template>
2199        </xsl:otherwise>
2200      </xsl:choose>
2201    </xsl:for-each>
2202  </xsl:template>
2203
2204
2205  <!-- These template generates two paths, one for each end of a way.  The line to the first node is cut in two so that the join
2206         between the two paths is not at an angle.  -->
2207  <xsl:template name="generatePathWayStart">
2208    <xsl:call-template name="moveToNode">
2209      <xsl:with-param name="node" select="key('nodeById',nd[1]/@ref)"/>
2210    </xsl:call-template>
2211    <xsl:call-template name="lineToMidpointPlus">
2212      <xsl:with-param name="fromNode" select="key('nodeById',nd[1]/@ref)"/>
2213      <xsl:with-param name="toNode" select="key('nodeById',nd[2]/@ref)"/>
2214    </xsl:call-template>
2215  </xsl:template>
2216
2217  <xsl:template name="generatePathWayEnd">
2218    <xsl:call-template name="moveToMidpointPlus">
2219      <xsl:with-param name="fromNode" select="key('nodeById',nd[position()=(last())]/@ref)"/>
2220      <xsl:with-param name="toNode" select="key('nodeById',nd[position()=last()-1]/@ref)"/>
2221    </xsl:call-template>
2222    <xsl:call-template name="lineToNode">
2223      <xsl:with-param name="node" select="key('nodeById',nd[position()=last()]/@ref)"/>
2224    </xsl:call-template>
2225  </xsl:template>
2226
2227  <xsl:template name="generatePathWayMid">
2228    <xsl:for-each select="nd[key('nodeById',@ref)]">
2229      <xsl:choose>
2230        <xsl:when test="position()=1">
2231          <xsl:call-template name="moveToMidpointPlus">
2232            <xsl:with-param name="fromNode" select="key('nodeById',@ref)"/>
2233            <xsl:with-param name="toNode" select="key('nodeById',following-sibling::nd[1]/@ref)"/>
2234          </xsl:call-template>
2235        </xsl:when>
2236        <xsl:when test="position()=last()">
2237          <xsl:call-template name="lineToMidpointMinus">
2238            <xsl:with-param name="fromNode" select="key('nodeById',preceding-sibling::nd[1]/@ref)"/>
2239            <xsl:with-param name="toNode" select="key('nodeById',@ref)"/>
2240          </xsl:call-template>
2241        </xsl:when>
2242        <xsl:otherwise>
2243          <xsl:call-template name="lineToNode">
2244            <xsl:with-param name="node" select="key('nodeById',@ref)"/>
2245          </xsl:call-template>
2246        </xsl:otherwise>
2247      </xsl:choose>
2248    </xsl:for-each>
2249  </xsl:template>
2250
2251  <!-- Generate an area path for the current way or area element -->
2252  <xsl:template name="generateAreaPath">
2253    <xsl:variable name='relation' select="key('relationByWay',@id)[tag[@k='type' and @v='multipolygon']]"/>
2254    <xsl:choose>
2255      <xsl:when test='$relation'>
2256        <!-- Handle multipolygons.
2257             Draw area only once, draw the outer one first if we know which is it, else just draw the first one -->
2258        <xsl:variable name='outerway' select="$relation/member[@type='way'][@role='outer']/@ref"/>
2259        <xsl:variable name='firsrelationmember' select="$relation/member[@type='way'][key('wayById', @ref)][1]/@ref"/> 
2260        <xsl:if test='( $outerway and $outerway=@id ) or ( not($outerway) and $firsrelationmember=@id )'>
2261          <xsl:message>
2262            <xsl:value-of select='$relation/@id'/>
2263          </xsl:message>
2264          <xsl:for-each select="$relation/member[@type='way'][key('wayById', @ref)]">
2265            <xsl:call-template name='generateAreaSubPath'>
2266              <xsl:with-param name='way' select="key('wayById',@ref)"/>
2267              <xsl:with-param name='position' select="position()"/>
2268            </xsl:call-template>
2269          </xsl:for-each>
2270          <xsl:text>Z</xsl:text>
2271        </xsl:if>
2272
2273      </xsl:when>
2274      <xsl:otherwise>
2275        <xsl:call-template name='generateAreaSubPath'>
2276          <xsl:with-param name='way' select='.'/>
2277          <xsl:with-param name='position' select="'1'"/>
2278        </xsl:call-template>
2279        <xsl:text>Z</xsl:text>
2280      </xsl:otherwise>
2281    </xsl:choose>
2282  </xsl:template>
2283
2284
2285  <xsl:template name='generateAreaSubPath'>
2286    <xsl:param name='way'/>
2287    <xsl:param name='position'/>
2288
2289    <xsl:variable name='loop' select='$way/nd[1]/@ref=$way/nd[last()]/@ref'/>
2290    <xsl:message>
2291      WayId: <xsl:value-of select='$way/@id'/>
2292      Loop: <xsl:value-of select='$loop'/>
2293      Loop: <xsl:value-of select='$way/nd[1]/@ref'/>
2294      Loop: <xsl:value-of select='$way/nd[last()]/@ref'/>
2295    </xsl:message>
2296    <xsl:for-each select="$way/nd[key('nodeById',@ref)]">
2297      <xsl:choose>
2298        <xsl:when test="position()=1 and $loop">
2299          <xsl:if test='not($position=1)'>
2300            <xsl:text>Z</xsl:text>
2301          </xsl:if>
2302          <xsl:call-template name="moveToNode">
2303            <xsl:with-param name="node" select="key('nodeById',@ref)"/>
2304          </xsl:call-template>
2305        </xsl:when>
2306        <xsl:when test="$position=1 and position()=1 and not($loop=1)">
2307          <xsl:call-template name="moveToNode">
2308            <xsl:with-param name="node" select="key('nodeById',@ref)"/>
2309          </xsl:call-template>
2310        </xsl:when>
2311        <xsl:otherwise>
2312          <xsl:call-template name="lineToNode">
2313            <xsl:with-param name="node" select="key('nodeById',@ref)"/>
2314          </xsl:call-template>
2315        </xsl:otherwise>
2316      </xsl:choose>
2317    </xsl:for-each>
2318
2319
2320  </xsl:template>
2321
2322  <!-- Generate a MoveTo command for a node -->
2323  <xsl:template name="moveToNode">
2324    <xsl:param name='node' />
2325    <xsl:variable name="x1" select="($width)-((($topRightLongitude)-($node/@lon))*10000*$scale)"/>
2326    <xsl:variable name="y1" select="($height)+((($bottomLeftLatitude)-($node/@lat))*10000*$scale*$projection)"/>
2327    <xsl:text>M</xsl:text>
2328    <xsl:value-of select="$x1"/>
2329    <xsl:text> </xsl:text>
2330    <xsl:value-of select="$y1"/>
2331  </xsl:template>
2332
2333  <!-- Generate a LineTo command for a nd -->
2334  <xsl:template name="lineToNode">
2335    <xsl:param name='node'/>
2336
2337    <xsl:variable name="x1" select="($width)-((($topRightLongitude)-($node/@lon))*10000*$scale)"/>
2338    <xsl:variable name="y1" select="($height)+((($bottomLeftLatitude)-($node/@lat))*10000*$scale*$projection)"/>
2339    <xsl:text>L</xsl:text>
2340    <xsl:value-of select="$x1"/>
2341    <xsl:text> </xsl:text>
2342    <xsl:value-of select="$y1"/>
2343  </xsl:template>
2344
2345  <xsl:template name="lineToMidpointPlus">
2346    <xsl:param name='fromNode'/>
2347    <xsl:param name='toNode'/>
2348
2349    <xsl:variable name="x1" select="($width)-((($topRightLongitude)-($fromNode/@lon))*10000*$scale)"/>
2350    <xsl:variable name="y1" select="($height)+((($bottomLeftLatitude)-($fromNode/@lat))*10000*$scale*$projection)"/>
2351
2352    <xsl:variable name="x2" select="($width)-((($topRightLongitude)-($toNode/@lon))*10000*$scale)"/>
2353    <xsl:variable name="y2" select="($height)+((($bottomLeftLatitude)-($toNode/@lat))*10000*$scale*$projection)"/>
2354
2355    <xsl:text>L</xsl:text>
2356    <xsl:value-of select="$x1+(($x2 - $x1) div 1.9)"/>
2357    <xsl:text> </xsl:text>
2358    <xsl:value-of select="$y1+(($y2 - $y1) div 1.9)"/>
2359  </xsl:template>
2360
2361  <xsl:template name="lineToMidpointMinus">
2362    <xsl:param name='fromNode'/>
2363    <xsl:param name='toNode'/>
2364
2365    <xsl:variable name="x1" select="($width)-((($topRightLongitude)-($fromNode/@lon))*10000*$scale)"/>
2366    <xsl:variable name="y1" select="($height)+((($bottomLeftLatitude)-($fromNode/@lat))*10000*$scale*$projection)"/>
2367
2368    <xsl:variable name="x2" select="($width)-((($topRightLongitude)-($toNode/@lon))*10000*$scale)"/>
2369    <xsl:variable name="y2" select="($height)+((($bottomLeftLatitude)-($toNode/@lat))*10000*$scale*$projection)"/>
2370    <xsl:text>L</xsl:text>
2371    <xsl:value-of select="$x1+(($x2 - $x1) div 2.1)"/>
2372    <xsl:text> </xsl:text>
2373    <xsl:value-of select="$y1+(($y2 - $y1) div 2.1)"/>
2374  </xsl:template>
2375
2376
2377  <xsl:template name="moveToMidpointPlus">
2378    <xsl:param name='fromNode'/>
2379    <xsl:param name='toNode'/>
2380
2381    <xsl:variable name="x1" select="($width)-((($topRightLongitude)-($fromNode/@lon))*10000*$scale)"/>
2382    <xsl:variable name="y1" select="($height)+((($bottomLeftLatitude)-($fromNode/@lat))*10000*$scale*$projection)"/>
2383
2384    <xsl:variable name="x2" select="($width)-((($topRightLongitude)-($toNode/@lon))*10000*$scale)"/>
2385    <xsl:variable name="y2" select="($height)+((($bottomLeftLatitude)-($toNode/@lat))*10000*$scale*$projection)"/>
2386    <xsl:text>M</xsl:text>
2387    <xsl:value-of select="$x1+(($x2 - $x1) div 1.9)"/>
2388    <xsl:text> </xsl:text>
2389    <xsl:value-of select="$y1+(($y2 - $y1) div 1.9)"/>
2390  </xsl:template>
2391
2392  <!-- Some attribute shouldn't be copied -->
2393  <xsl:template match="@type|@ref|@scale|@smart-linecap" mode="copyAttributes" />
2394
2395  <!-- Copy all other attributes  -->
2396  <xsl:template match="@*" mode="copyAttributes">
2397    <xsl:copy/>
2398  </xsl:template>
2399
2400
2401  <!-- Rule processing engine -->
2402
2403  <!--
2404
2405                Calls all templates inside <rule> tags (including itself, if there are nested rules).
2406
2407                If the global var withOSMLayers is 'no', we don't care about layers and draw everything
2408                in one go. This is faster and is sometimes useful. For normal maps you want withOSMLayers
2409                to be 'yes', which is the default.
2410
2411        -->
2412  <xsl:template name="processRules">
2413
2414    <!-- First select all elements - exclude those marked as deleted by JOSM -->
2415    <xsl:variable name='elements' select="$data/osm/*[not(@action) or not(@action='delete')]" />
2416
2417    <xsl:choose>
2418
2419      <!-- Process all the rules, one layer at a time -->
2420      <xsl:when test="$withOSMLayers='yes'">
2421        <xsl:call-template name="processLayer">
2422          <xsl:with-param name="layer" select="'-5'"/>
2423          <xsl:with-param name="elements" select="$elements"/>
2424        </xsl:call-template>
2425        <xsl:call-template name="processLayer">
2426          <xsl:with-param name="layer" select="'-4'"/>
2427          <xsl:with-param name="elements" select="$elements"/>
2428        </xsl:call-template>
2429        <xsl:call-template name="processLayer">
2430          <xsl:with-param name="layer" select="'-3'"/>
2431          <xsl:with-param name="elements" select="$elements"/>
2432        </xsl:call-template>
2433        <xsl:call-template name="processLayer">
2434          <xsl:with-param name="layer" select="'-2'"/>
2435          <xsl:with-param name="elements" select="$elements"/>
2436        </xsl:call-template>
2437        <xsl:call-template name="processLayer">
2438          <xsl:with-param name="layer" select="'-1'"/>
2439          <xsl:with-param name="elements" select="$elements"/>
2440        </xsl:call-template>
2441        <xsl:call-template name="processLayer">
2442          <xsl:with-param name="layer" select="'0'"/>
2443          <xsl:with-param name="elements" select="$elements"/>
2444        </xsl:call-template>
2445        <xsl:call-template name="processLayer">
2446          <xsl:with-param name="layer" select="'1'"/>
2447          <xsl:with-param name="elements" select="$elements"/>
2448        </xsl:call-template>
2449        <xsl:call-template name="processLayer">
2450          <xsl:with-param name="layer" select="'2'"/>
2451          <xsl:with-param name="elements" select="$elements"/>
2452        </xsl:call-template>
2453        <xsl:call-template name="processLayer">
2454          <xsl:with-param name="layer" select="'3'"/>
2455          <xsl:with-param name="elements" select="$elements"/>
2456        </xsl:call-template>
2457        <xsl:call-template name="processLayer">
2458          <xsl:with-param name="layer" select="'4'"/>
2459          <xsl:with-param name="elements" select="$elements"/>
2460        </xsl:call-template>
2461        <xsl:call-template name="processLayer">
2462          <xsl:with-param name="layer" select="'5'"/>
2463          <xsl:with-param name="elements" select="$elements"/>
2464        </xsl:call-template>
2465      </xsl:when>
2466
2467      <!-- Process all the rules, without looking at the layers -->
2468      <xsl:otherwise>
2469        <xsl:apply-templates select="/rules/rule">
2470          <xsl:with-param name="elements" select="$elements"/>
2471          <xsl:with-param name="layer" select="'0'"/>
2472        </xsl:apply-templates>
2473      </xsl:otherwise>
2474
2475    </xsl:choose>
2476  </xsl:template>
2477
2478
2479  <xsl:template name="processLayer">
2480    <xsl:param name="layer"/>
2481    <xsl:param name="elements"/>
2482
2483    <g inkscape:groupmode="layer" id="layer{$layer}" inkscape:label="Layer {$layer}">
2484      <xsl:apply-templates select="/rules/rule">
2485        <xsl:with-param name="elements" select="$elements"/>
2486        <xsl:with-param name="layer" select="$layer"/>
2487      </xsl:apply-templates>
2488    </g>
2489  </xsl:template>
2490
2491
2492  <!-- Process a rule at a specific level -->
2493  <xsl:template match='rule'>
2494    <xsl:param name="elements"/>
2495    <xsl:param name="layer"/>
2496
2497    <!-- If the rule is for a specific layer and we are processing that layer then pass *all* elements
2498                     to the rule, otherwise just select the matching elements for this layer. -->
2499    <xsl:choose>
2500      <xsl:when test='$layer=@layer'>
2501        <xsl:call-template name="rule">
2502          <xsl:with-param name="elements" select="$elements"/>
2503          <xsl:with-param name="layer" select="$layer"/>
2504        </xsl:call-template>
2505      </xsl:when>
2506      <xsl:otherwise>
2507        <xsl:if test='not(@layer)'>
2508          <xsl:call-template name="rule">
2509            <xsl:with-param name="elements" select="$elements[
2510                                                        tag[@k='layer' and @v=$layer]
2511                                                        or ($layer='0' and count(tag[@k='layer'])=0)
2512                                                ]"/>
2513            <xsl:with-param name="layer" select="$layer"/>
2514          </xsl:call-template>
2515        </xsl:if>
2516      </xsl:otherwise>
2517    </xsl:choose>
2518  </xsl:template>
2519
2520
2521  <xsl:template name='rule'>
2522    <xsl:param name="elements"/>
2523    <xsl:param name="layer"/>
2524
2525    <!-- This is the rule currently being processed -->
2526    <xsl:variable name="rule" select="."/>
2527
2528    <!-- Make list of elements that this rule should be applied to -->
2529    <xsl:variable name="eBare">
2530      <xsl:choose>
2531        <xsl:when test="$rule/@e='*'">node|way</xsl:when>
2532        <xsl:when test="$rule/@e">
2533          <xsl:value-of select="$rule/@e"/>
2534        </xsl:when>
2535        <xsl:otherwise>node|way</xsl:otherwise>
2536      </xsl:choose>
2537    </xsl:variable>
2538
2539    <!-- List of keys that this rule should be applied to -->
2540    <xsl:variable name="kBare" select="$rule/@k"/>
2541
2542    <!-- List of values that this rule should be applied to -->
2543    <xsl:variable name="vBare" select="$rule/@v"/>
2544    <xsl:variable name="sBare" select="$rule/@s"/>
2545
2546    <!-- Top'n'tail selectors with | for contains usage -->
2547    <xsl:variable name="e">
2548      |<xsl:value-of select="$eBare"/>|
2549    </xsl:variable>
2550    <xsl:variable name="k">
2551      |<xsl:value-of select="$kBare"/>|
2552    </xsl:variable>
2553    <xsl:variable name="v">
2554      |<xsl:value-of select="$vBare"/>|
2555    </xsl:variable>
2556    <xsl:variable name="s">
2557      |<xsl:value-of select="$sBare"/>|
2558    </xsl:variable>
2559
2560    <xsl:variable
2561      name="selectedElements"
2562      select="$elements[contains($e,concat('|',name(),'|'))
2563            or
2564            (contains($e,'|node|') and name()='way' and key('wayByNode',@id))
2565            ]"/>
2566
2567
2568    <!-- Patch $s -->
2569    <xsl:choose>
2570      <!-- way selector -->
2571      <xsl:when test="contains($s,'|way|')">
2572        <xsl:choose>
2573          <!-- every key -->
2574          <xsl:when test="contains($k,'|*|')">
2575            <xsl:choose>
2576              <!-- every key ,no value defined -->
2577              <xsl:when test="contains($v,'|~|')">
2578                <xsl:variable name="elementsWithNoTags" select="$selectedElements[count(key('wayByNode',@id)/tag)=0]"/>
2579                <xsl:call-template name="processElements">
2580                  <xsl:with-param name="eBare" select="$eBare"/>
2581                  <xsl:with-param name="kBare" select="$kBare"/>
2582                  <xsl:with-param name="vBare" select="$vBare"/>
2583                  <xsl:with-param name="layer" select="$layer"/>
2584                  <xsl:with-param name="elements" select="$elementsWithNoTags"/>
2585                  <xsl:with-param name="rule" select="$rule"/>
2586                </xsl:call-template>
2587              </xsl:when>
2588              <!-- every key ,every value -->
2589              <xsl:when test="contains($v,'|*|')">
2590                <xsl:variable name="allElements" select="$selectedElements"/>
2591                <xsl:call-template name="processElements">
2592                  <xsl:with-param name="eBare" select="$eBare"/>
2593                  <xsl:with-param name="kBare" select="$kBare"/>
2594                  <xsl:with-param name="vBare" select="$vBare"/>
2595                  <xsl:with-param name="layer" select="$layer"/>
2596                  <xsl:with-param name="elements" select="$allElements"/>
2597                  <xsl:with-param name="rule" select="$rule"/>
2598                </xsl:call-template>
2599              </xsl:when>
2600              <!-- every key , selected values -->
2601              <xsl:otherwise>
2602                <xsl:variable name="allElementsWithValue" select="$selectedElements[key('wayByNode',@id)/tag[contains($v,concat('|',@v,'|'))]]"/>
2603                <xsl:call-template name="processElements">
2604                  <xsl:with-param name="eBare" select="$eBare"/>
2605                  <xsl:with-param name="kBare" select="$kBare"/>
2606                  <xsl:with-param name="vBare" select="$vBare"/>
2607                  <xsl:with-param name="layer" select="$layer"/>
2608                  <xsl:with-param name="elements" select="$allElementsWithValue"/>
2609                  <xsl:with-param name="rule" select="$rule"/>
2610                </xsl:call-template>
2611              </xsl:otherwise>
2612            </xsl:choose>
2613          </xsl:when>
2614          <!-- no value  -->
2615          <xsl:when test="contains($v,'|~|')">
2616            <xsl:variable name="elementsWithoutKey" select="$selectedElements[count(key('wayByNode',@id)/tag[contains($k,concat('|',@k,'|'))])=0]"/>
2617            <xsl:call-template name="processElements">
2618              <xsl:with-param name="eBare" select="$eBare"/>
2619              <xsl:with-param name="kBare" select="$kBare"/>
2620              <xsl:with-param name="vBare" select="$vBare"/>
2621              <xsl:with-param name="layer" select="$layer"/>
2622              <xsl:with-param name="elements" select="$elementsWithoutKey"/>
2623              <xsl:with-param name="rule" select="$rule"/>
2624            </xsl:call-template>
2625          </xsl:when>
2626          <!-- every value  -->
2627          <xsl:when test="contains($v,'|*|')">
2628            <xsl:variable name="allElementsWithKey" select="$selectedElements[key('wayByNode',@id)/tag[contains($k,concat('|',@k,'|'))]]"/>
2629            <xsl:call-template name="processElements">
2630              <xsl:with-param name="eBare" select="$eBare"/>
2631              <xsl:with-param name="kBare" select="$kBare"/>
2632              <xsl:with-param name="vBare" select="$vBare"/>
2633              <xsl:with-param name="layer" select="$layer"/>
2634              <xsl:with-param name="elements" select="$allElementsWithKey"/>
2635              <xsl:with-param name="rule" select="$rule"/>
2636            </xsl:call-template>
2637          </xsl:when>
2638
2639          <!-- defined key and defined value -->
2640          <xsl:otherwise>
2641            <xsl:variable name="elementsWithKey" select="$selectedElements[
2642                                                        key('wayByNode',@id)/tag[
2643                                                                contains($k,concat('|',@k,'|')) and contains($v,concat('|',@v,'|'))
2644                                                                ]
2645                                                        ]"/>
2646            <xsl:call-template name="processElements">
2647              <xsl:with-param name="eBare" select="$eBare"/>
2648              <xsl:with-param name="kBare" select="$kBare"/>
2649              <xsl:with-param name="vBare" select="$vBare"/>
2650              <xsl:with-param name="layer" select="$layer"/>
2651              <xsl:with-param name="elements" select="$elementsWithKey"/>
2652              <xsl:with-param name="rule" select="$rule"/>
2653            </xsl:call-template>
2654          </xsl:otherwise>
2655        </xsl:choose>
2656      </xsl:when>
2657
2658      <!-- other selector -->
2659      <xsl:otherwise>
2660        <xsl:choose>
2661          <xsl:when test="contains($k,'|*|')">
2662            <xsl:choose>
2663              <xsl:when test="contains($v,'|~|')">
2664                <xsl:variable name="elementsWithNoTags" select="$selectedElements[count(tag)=0]"/>
2665                <xsl:call-template name="processElements">
2666                  <xsl:with-param name="eBare" select="$eBare"/>
2667                  <xsl:with-param name="kBare" select="$kBare"/>
2668                  <xsl:with-param name="vBare" select="$vBare"/>
2669                  <xsl:with-param name="layer" select="$layer"/>
2670                  <xsl:with-param name="elements" select="$elementsWithNoTags"/>
2671                  <xsl:with-param name="rule" select="$rule"/>
2672                </xsl:call-template>
2673              </xsl:when>
2674              <xsl:when test="contains($v,'|*|')">
2675                <xsl:variable name="allElements" select="$selectedElements"/>
2676                <xsl:call-template name="processElements">
2677                  <xsl:with-param name="eBare" select="$eBare"/>
2678                  <xsl:with-param name="kBare" select="$kBare"/>
2679                  <xsl:with-param name="vBare" select="$vBare"/>
2680                  <xsl:with-param name="layer" select="$layer"/>
2681                  <xsl:with-param name="elements" select="$allElements"/>
2682                  <xsl:with-param name="rule" select="$rule"/>
2683                </xsl:call-template>
2684              </xsl:when>
2685              <xsl:otherwise>
2686                <xsl:variable name="allElementsWithValue" select="$selectedElements[tag[contains($v,concat('|',@v,'|'))]]"/>
2687                <xsl:call-template name="processElements">
2688                  <xsl:with-param name="eBare" select="$eBare"/>
2689                  <xsl:with-param name="kBare" select="$kBare"/>
2690                  <xsl:with-param name="vBare" select="$vBare"/>
2691                  <xsl:with-param name="layer" select="$layer"/>
2692                  <xsl:with-param name="elements" select="$allElementsWithValue"/>
2693                  <xsl:with-param name="rule" select="$rule"/>
2694                </xsl:call-template>
2695              </xsl:otherwise>
2696            </xsl:choose>
2697          </xsl:when>
2698          <xsl:when test="contains($v,'|~|')">
2699            <xsl:variable name="elementsWithoutKey" select="$selectedElements[count(tag[contains($k,concat('|',@k,'|'))])=0]"/>
2700            <xsl:call-template name="processElements">
2701              <xsl:with-param name="eBare" select="$eBare"/>
2702              <xsl:with-param name="kBare" select="$kBare"/>
2703              <xsl:with-param name="vBare" select="$vBare"/>
2704              <xsl:with-param name="layer" select="$layer"/>
2705              <xsl:with-param name="elements" select="$elementsWithoutKey"/>
2706              <xsl:with-param name="rule" select="$rule"/>
2707            </xsl:call-template>
2708          </xsl:when>
2709          <xsl:when test="contains($v,'|*|')">
2710            <xsl:variable name="allElementsWithKey" select="$selectedElements[tag[contains($k,concat('|',@k,'|'))]]"/>
2711            <xsl:call-template name="processElements">
2712              <xsl:with-param name="eBare" select="$eBare"/>
2713              <xsl:with-param name="kBare" select="$kBare"/>
2714              <xsl:with-param name="vBare" select="$vBare"/>
2715              <xsl:with-param name="layer" select="$layer"/>
2716              <xsl:with-param name="elements" select="$allElementsWithKey"/>
2717              <xsl:with-param name="rule" select="$rule"/>
2718            </xsl:call-template>
2719          </xsl:when>
2720          <xsl:otherwise>
2721            <xsl:variable name="elementsWithKey" select="$selectedElements[tag[contains($k,concat('|',@k,'|')) and contains($v,concat('|',@v,'|'))]]"/>
2722            <xsl:call-template name="processElements">
2723              <xsl:with-param name="eBare" select="$eBare"/>
2724              <xsl:with-param name="kBare" select="$kBare"/>
2725              <xsl:with-param name="vBare" select="$vBare"/>
2726              <xsl:with-param name="layer" select="$layer"/>
2727              <xsl:with-param name="elements" select="$elementsWithKey"/>
2728              <xsl:with-param name="rule" select="$rule"/>
2729            </xsl:call-template>
2730          </xsl:otherwise>
2731        </xsl:choose>
2732      </xsl:otherwise>
2733    </xsl:choose>
2734  </xsl:template>
2735
2736
2737  <xsl:template match="else">
2738    <xsl:param name="elements"/>
2739    <xsl:param name="layer"/>
2740
2741    <!-- This is the previous rule that is being negated -->
2742    <!-- TODO: abort if no preceding rule element -->
2743    <xsl:variable name="rule" select="preceding-sibling::rule[1]"/>
2744
2745    <!-- Make list of elements that this rule should be applied to -->
2746    <xsl:variable name="eBare">
2747      <xsl:choose>
2748        <xsl:when test="$rule/@e='*'">node|way</xsl:when>
2749        <xsl:when test="$rule/@e">
2750          <xsl:value-of select="$rule/@e"/>
2751        </xsl:when>
2752        <xsl:otherwise>node|way</xsl:otherwise>
2753      </xsl:choose>
2754    </xsl:variable>
2755
2756    <!-- List of keys that this rule should be applied to -->
2757    <xsl:variable name="kBare" select="$rule/@k"/>
2758
2759    <!-- List of values that this rule should be applied to -->
2760    <xsl:variable name="vBare" select="$rule/@v"/>
2761    <xsl:variable name="sBare" select="$rule/@s"/>
2762
2763
2764    <!-- Top'n'tail selectors with | for contains usage -->
2765    <xsl:variable name="e">
2766      |<xsl:value-of select="$eBare"/>|
2767    </xsl:variable>
2768    <xsl:variable name="k">
2769      |<xsl:value-of select="$kBare"/>|
2770    </xsl:variable>
2771    <xsl:variable name="v">
2772      |<xsl:value-of select="$vBare"/>|
2773    </xsl:variable>
2774    <xsl:variable name="s">
2775      |<xsl:value-of select="$sBare"/>|
2776    </xsl:variable>
2777
2778    <xsl:variable
2779      name="selectedElements"
2780      select="$elements[contains($e,concat('|',name(),'|'))
2781              or
2782              (contains($e,'|node|') and name()='way'and key('wayByNode',@id))
2783              ]"/>
2784
2785    <!-- Patch $s -->
2786    <xsl:choose>
2787      <xsl:when test="contains($s,'|way|')">
2788        <xsl:choose>
2789          <xsl:when test="contains($k,'|*|')">
2790            <xsl:choose>
2791              <xsl:when test="contains($v,'|~|')">
2792                <xsl:variable name="elementsWithNoTags" select="$selectedElements[count(key('wayByNode',@id)/tag)!=0]"/>
2793                <xsl:call-template name="processElements">
2794                  <xsl:with-param name="eBare" select="$eBare"/>
2795                  <xsl:with-param name="kBare" select="$kBare"/>
2796                  <xsl:with-param name="vBare" select="$vBare"/>
2797                  <xsl:with-param name="layer" select="$layer"/>
2798                  <xsl:with-param name="elements" select="$elementsWithNoTags"/>
2799                  <xsl:with-param name="rule" select="$rule"/>
2800                </xsl:call-template>
2801              </xsl:when>
2802              <xsl:when test="contains($v,'|*|')">
2803                <!-- no-op! -->
2804              </xsl:when>
2805              <xsl:otherwise>
2806                <xsl:variable name="allElementsWithValue" select="$selectedElements[not(key('wayByNode',@id)/tag[contains($v,concat('|',@v,'|'))])]"/>
2807                <xsl:call-template name="processElements">
2808                  <xsl:with-param name="eBare" select="$eBare"/>
2809                  <xsl:with-param name="kBare" select="$kBare"/>
2810                  <xsl:with-param name="vBare" select="$vBare"/>
2811                  <xsl:with-param name="layer" select="$layer"/>
2812                  <xsl:with-param name="elements" select="$allElementsWithValue"/>
2813                  <xsl:with-param name="rule" select="$rule"/>
2814                </xsl:call-template>
2815              </xsl:otherwise>
2816            </xsl:choose>
2817          </xsl:when>
2818          <xsl:when test="contains($v,'|~|')">
2819            <xsl:variable name="elementsWithoutKey" select="$selectedElements[count(key('wayByNode',@id)/tag[contains($k,concat('|',@k,'|'))])!=0]"/>
2820            <xsl:call-template name="processElements">
2821              <xsl:with-param name="eBare" select="$eBare"/>
2822              <xsl:with-param name="kBare" select="$kBare"/>
2823              <xsl:with-param name="vBare" select="$vBare"/>
2824              <xsl:with-param name="layer" select="$layer"/>
2825              <xsl:with-param name="elements" select="$elementsWithoutKey"/>
2826              <xsl:with-param name="rule" select="$rule"/>
2827            </xsl:call-template>
2828          </xsl:when>
2829          <xsl:when test="contains($v,'|*|')">
2830            <xsl:variable name="allElementsWithKey" select="$selectedElements[not(key('wayByNode',@id)/tag[contains($k,concat('|',@k,'|'))])]"/>
2831            <xsl:call-template name="processElements">
2832              <xsl:with-param name="eBare" select="$eBare"/>
2833              <xsl:with-param name="kBare" select="$kBare"/>
2834              <xsl:with-param name="vBare" select="$vBare"/>
2835              <xsl:with-param name="layer" select="$layer"/>
2836              <xsl:with-param name="elements" select="$allElementsWithKey"/>
2837              <xsl:with-param name="rule" select="$rule"/>
2838            </xsl:call-template>
2839          </xsl:when>
2840          <xsl:otherwise>
2841            <xsl:variable name="elementsWithKey" select="$selectedElements[not(
2842                         key('wayByNode',@id)/tag[
2843                            contains($k,concat('|',@k,'|')) and contains($v,concat('|',@v,'|'))
2844                            ]
2845                         )]"/>
2846            <xsl:call-template name="processElements">
2847              <xsl:with-param name="eBare" select="$eBare"/>
2848              <xsl:with-param name="kBare" select="$kBare"/>
2849              <xsl:with-param name="vBare" select="$vBare"/>
2850              <xsl:with-param name="layer" select="$layer"/>
2851              <xsl:with-param name="elements" select="$elementsWithKey"/>
2852              <xsl:with-param name="rule" select="$rule"/>
2853            </xsl:call-template>
2854          </xsl:otherwise>
2855        </xsl:choose>
2856      </xsl:when>
2857
2858      <xsl:otherwise>
2859        <!-- not contains $s -->
2860        <xsl:choose>
2861          <xsl:when test="contains($k,'|*|')">
2862            <xsl:choose>
2863              <xsl:when test="contains($v,'|~|')">
2864                <xsl:variable name="elementsWithNoTags" select="$selectedElements[count(tag)!=0]"/>
2865                <xsl:call-template name="processElements">
2866                  <xsl:with-param name="eBare" select="$eBare"/>
2867                  <xsl:with-param name="kBare" select="$kBare"/>
2868                  <xsl:with-param name="vBare" select="$vBare"/>
2869                  <xsl:with-param name="layer" select="$layer"/>
2870                  <xsl:with-param name="elements" select="$elementsWithNoTags"/>
2871                  <xsl:with-param name="rule" select="$rule"/>
2872                </xsl:call-template>
2873              </xsl:when>
2874              <xsl:when test="contains($v,'|*|')">
2875                <!-- no-op! -->
2876              </xsl:when>
2877              <xsl:otherwise>
2878                <xsl:variable name="allElementsWithValue" select="$selectedElements[not(tag[contains($v,concat('|',@v,'|'))])]"/>
2879                <xsl:call-template name="processElements">
2880                  <xsl:with-param name="eBare" select="$eBare"/>
2881                  <xsl:with-param name="kBare" select="$kBare"/>
2882                  <xsl:with-param name="vBare" select="$vBare"/>
2883                  <xsl:with-param name="layer" select="$layer"/>
2884                  <xsl:with-param name="elements" select="$allElementsWithValue"/>
2885                  <xsl:with-param name="rule" select="$rule"/>
2886                </xsl:call-template>
2887              </xsl:otherwise>
2888            </xsl:choose>
2889          </xsl:when>
2890          <xsl:when test="contains($v,'|~|')">
2891            <xsl:variable name="elementsWithoutKey" select="$selectedElements[count(tag[contains($k,concat('|',@k,'|'))])!=0]"/>
2892            <xsl:call-template name="processElements">
2893              <xsl:with-param name="eBare" select="$eBare"/>
2894              <xsl:with-param name="kBare" select="$kBare"/>
2895              <xsl:with-param name="vBare" select="$vBare"/>
2896              <xsl:with-param name="layer" select="$layer"/>
2897              <xsl:with-param name="elements" select="$elementsWithoutKey"/>
2898              <xsl:with-param name="rule" select="$rule"/>
2899            </xsl:call-template>
2900          </xsl:when>
2901          <xsl:when test="contains($v,'|*|')">
2902            <xsl:variable name="allElementsWithKey" select="$selectedElements[not(tag[contains($k,concat('|',@k,'|'))])]"/>
2903            <xsl:call-template name="processElements">
2904              <xsl:with-param name="eBare" select="$eBare"/>
2905              <xsl:with-param name="kBare" select="$kBare"/>
2906              <xsl:with-param name="vBare" select="$vBare"/>
2907              <xsl:with-param name="layer" select="$layer"/>
2908              <xsl:with-param name="elements" select="$allElementsWithKey"/>
2909              <xsl:with-param name="rule" select="$rule"/>
2910            </xsl:call-template>
2911          </xsl:when>
2912          <xsl:otherwise>
2913            <xsl:variable name="elementsWithKey" select="$selectedElements[not(tag[contains($k,concat('|',@k,'|')) and contains($v,concat('|',@v,'|'))])]"/>
2914            <xsl:call-template name="processElements">
2915              <xsl:with-param name="eBare" select="$eBare"/>
2916              <xsl:with-param name="kBare" select="$kBare"/>
2917              <xsl:with-param name="vBare" select="$vBare"/>
2918              <xsl:with-param name="layer" select="$layer"/>
2919              <xsl:with-param name="elements" select="$elementsWithKey"/>
2920              <xsl:with-param name="rule" select="$rule"/>
2921            </xsl:call-template>
2922          </xsl:otherwise>
2923        </xsl:choose>
2924      </xsl:otherwise>
2925    </xsl:choose>
2926  </xsl:template>
2927
2928
2929  <xsl:template name="processElements">
2930    <xsl:param name="eBare"/>
2931    <xsl:param name="kBare"/>
2932    <xsl:param name="vBare"/>
2933    <xsl:param name="layer"/>
2934    <xsl:param name="elements"/>
2935    <xsl:param name="rule"/>
2936
2937
2938    <xsl:if test="$elements">
2939 
2940      <!-- elementCount is the number of elements we started with (just used for the progress message) -->
2941      <xsl:variable name="elementCount" select="count($elements)"/>
2942      <!-- If there's a proximity attribute on the rule then filter elements based on proximity -->
2943      <xsl:choose>
2944        <xsl:when test='$rule/@verticalProximity'>
2945          <xsl:variable name='nearbyElements1'>
2946            <xsl:call-template name="proximityFilter">
2947              <xsl:with-param name="elements" select="$elements"/>
2948              <xsl:with-param name="horizontalProximity" select="$rule/@horizontalProximity div 32"/>
2949              <xsl:with-param name="verticalProximity" select="$rule/@verticalProximity div 32"/>
2950            </xsl:call-template>
2951          </xsl:variable>
2952          <xsl:variable name='nearbyElements2'>
2953            <xsl:call-template name="proximityFilter">
2954              <xsl:with-param name="elements" select="exslt:node-set($nearbyElements1)/*"/>
2955              <xsl:with-param name="horizontalProximity" select="$rule/@horizontalProximity div 16"/>
2956              <xsl:with-param name="verticalProximity" select="$rule/@verticalProximity div 16"/>
2957            </xsl:call-template>
2958          </xsl:variable>
2959          <xsl:variable name='nearbyElements3'>
2960            <xsl:call-template name="proximityFilter">
2961              <xsl:with-param name="elements" select="exslt:node-set($nearbyElements2)/*"/>
2962              <xsl:with-param name="horizontalProximity" select="$rule/@horizontalProximity div 8"/>
2963              <xsl:with-param name="verticalProximity" select="$rule/@verticalProximity div 8"/>
2964            </xsl:call-template>
2965          </xsl:variable>
2966          <xsl:variable name='nearbyElements4'>
2967            <xsl:call-template name="proximityFilter">
2968              <xsl:with-param name="elements" select="exslt:node-set($nearbyElements3)/*"/>
2969              <xsl:with-param name="horizontalProximity" select="$rule/@horizontalProximity div 4"/>
2970              <xsl:with-param name="verticalProximity" select="$rule/@verticalProximity div 4"/>
2971            </xsl:call-template>
2972          </xsl:variable>
2973          <xsl:variable name='nearbyElements5'>
2974            <xsl:call-template name="proximityFilter">
2975              <xsl:with-param name="elements" select="exslt:node-set($nearbyElements4)/*"/>
2976              <xsl:with-param name="horizontalProximity" select="$rule/@horizontalProximity div 2"/>
2977              <xsl:with-param name="verticalProximity" select="$rule/@verticalProximity div 2"/>
2978            </xsl:call-template>
2979          </xsl:variable>
2980          <xsl:variable name='nearbyElementsRtf'>
2981            <xsl:call-template name="proximityFilter">
2982              <xsl:with-param name="elements" select="exslt:node-set($nearbyElements5)/*"/>
2983              <xsl:with-param name="horizontalProximity" select="$rule/@horizontalProximity"/>
2984              <xsl:with-param name="verticalProximity" select="$rule/@verticalProximity"/>
2985            </xsl:call-template>
2986          </xsl:variable>
2987
2988          <!-- Convert nearbyElements rtf to a node-set -->
2989          <xsl:variable name="nearbyElements" select="exslt:node-set($nearbyElementsRtf)/*"/>
2990
2991          <xsl:message>
2992            Processing &lt;rule e="<xsl:value-of select="$eBare"/>" k="<xsl:value-of select="$kBare"/>" v="<xsl:value-of select="$vBare"/>"
2993                        horizontalProximity="<xsl:value-of select="$rule/@horizontalProximity"/>" verticalProximity="<xsl:value-of select="$rule/@verticalProximity"/>" &gt;
2994            Matched by <xsl:value-of select="count($nearbyElements)"/> out of <xsl:value-of select="count($elements)"/> elements for layer <xsl:value-of select="$layer"/>.
2995          </xsl:message>
2996
2997          <xsl:apply-templates select="*">
2998            <xsl:with-param name="layer" select="$layer"/>
2999            <xsl:with-param name="elements" select="$nearbyElements"/>
3000            <xsl:with-param name="rule" select="$rule"/>
3001          </xsl:apply-templates>
3002        </xsl:when>
3003        <xsl:otherwise>
3004
3005          <xsl:message>
3006            Processing &lt;rule e="<xsl:value-of select="$eBare"/>" k="<xsl:value-of select="$kBare"/>" v="<xsl:value-of select="$vBare"/>" &gt;
3007            Matched by <xsl:value-of select="count($elements)"/> elements for layer <xsl:value-of select="$layer"/>.
3008          </xsl:message>
3009
3010          <xsl:apply-templates select="*">
3011            <xsl:with-param name="layer" select="$layer"/>
3012            <xsl:with-param name="elements" select="$elements"/>
3013            <xsl:with-param name="rule" select="$rule"/>
3014          </xsl:apply-templates>
3015        </xsl:otherwise>
3016      </xsl:choose>
3017    </xsl:if>
3018  </xsl:template>
3019
3020
3021  <!-- Select elements that are not within the specified distance from any other element -->
3022  <xsl:template name="proximityFilter">
3023    <xsl:param name="elements"/>
3024    <xsl:param name="horizontalProximity"/>
3025    <xsl:param name="verticalProximity"/>
3026   
3027    <!-- Offsetting the rectangle to the right gives better results when there are a solitary pair of adjacent elements. 
3028         One will get selected but the other won't.  Without the offset neither will get selected.  -->
3029    <xsl:variable name="topOffset" select="90  + $verticalProximity"/>
3030    <xsl:variable name="bottomOffset" select="90  - $verticalProximity"/>
3031    <xsl:variable name="leftOffset" select="180 - ($horizontalProximity * 0.5)"/>
3032    <xsl:variable name="rightOffset" select="180 + ($horizontalProximity * 1.5)"/>
3033
3034    <!-- Test each element to see if it is near any other element -->
3035    <xsl:for-each select="$elements">
3036      <xsl:variable name="id" select="@id"/>
3037      <xsl:variable name="top"    select="@lat + $topOffset"/>
3038      <xsl:variable name="bottom" select="@lat + $bottomOffset"/>
3039      <xsl:variable name="left"   select="@lon + $leftOffset"/>
3040      <xsl:variable name="right"  select="@lon + $rightOffset"/>
3041      <!-- Iterate through all of the elements currently selected and if there are no elements other
3042           than the current element in the rectangle then select this element -->
3043      <xsl:if test="not($elements[not(@id=$id)
3044                                  and (@lon+180) &lt; $right
3045                                  and (@lon+180) &gt; $left
3046                                  and (@lat+90)  &lt; $top
3047                                  and (@lat+90)  &gt; $bottom
3048                                  ]
3049                        )">
3050        <xsl:copy-of select="."/>
3051      </xsl:if>
3052    </xsl:for-each>
3053  </xsl:template>
3054
3055
3056  <!-- Draw SVG layers -->
3057  <xsl:template match="layer">
3058    <xsl:param name="elements"/>
3059    <xsl:param name="layer"/>
3060    <xsl:param name="rule"/>
3061
3062    <xsl:message>
3063      Processing SVG layer: <xsl:value-of select="@name"/> (at OSM layer <xsl:value-of select="$layer"/>)
3064    </xsl:message>
3065
3066    <xsl:variable name="opacity">
3067      <xsl:if test="@opacity">
3068        <xsl:value-of select="concat('opacity:',@opacity,';')"/>
3069      </xsl:if>
3070    </xsl:variable>
3071
3072    <xsl:variable name="display">
3073      <xsl:if test="(@display='none') or (@display='off')">
3074        <xsl:text>display:none;</xsl:text>
3075      </xsl:if>
3076    </xsl:variable>
3077
3078    <g inkscape:groupmode="layer" id="{@name}-{$layer}" inkscape:label="{@name}">
3079      <xsl:if test="concat($opacity,$display)!=''">
3080        <xsl:attribute name="style">
3081          <xsl:value-of select="concat($opacity,$display)"/>
3082        </xsl:attribute>
3083      </xsl:if>
3084      <xsl:apply-templates select="*">
3085        <xsl:with-param name="layer" select="$layer"/>
3086        <xsl:with-param name="elements" select="$elements"/>
3087      </xsl:apply-templates>
3088    </g>
3089
3090  </xsl:template>
3091
3092
3093  <!-- Draw map border -->
3094  <xsl:template name="drawBorder">
3095    <!-- dasharray definitions here can be overridden in stylesheet -->
3096    <g id="border" inkscape:groupmode="layer" inkscape:label="Map Border">
3097      <line id="border-left-casing" x1="0" y1="0" x2="0" y2="{$documentHeight}" class="map-border-casing" stroke-dasharray="{($km div 10) - 1},1"/>
3098      <line id="border-top-casing" x1="0" y1="0" x2="{$documentWidth}" y2="0" class="map-border-casing" stroke-dasharray="{($km div 10) - 1},1"/>
3099      <line id="border-bottom-casing" x1="0" y1="{$documentHeight}" x2="{$documentWidth}" y2="{$documentHeight}" class="map-border-casing" stroke-dasharray="{($km div 10) - 1},1"/>
3100      <line id="border-right-casing" x1="{$documentWidth}" y1="0" x2="{$documentWidth}" y2="{$documentHeight}" class="map-border-casing" stroke-dasharray="{($km div 10) - 1},1"/>
3101
3102      <line id="border-left-core" x1="0" y1="0" x2="0" y2="{$documentHeight}" class="map-border-core" stroke-dasharray="{($km div 10) - 1},1"/>
3103      <line id="border-top-core" x1="0" y1="0" x2="{$documentWidth}" y2="0" class="map-border-core" stroke-dasharray="{($km div 10) - 1},1"/>
3104      <line id="border-bottom-core" x1="0" y1="{$documentHeight}" x2="{$documentWidth}" y2="{$documentHeight}" class="map-border-core" stroke-dasharray="{($km div 10) - 1},1"/>
3105      <line id="border-right-core" x1="{$documentWidth}" y1="0" x2="{$documentWidth}" y2="{$documentHeight}" class="map-border-core" stroke-dasharray="{($km div 10) - 1},1"/>
3106    </g>
3107  </xsl:template>
3108
3109
3110  <!-- Draw a grid over the map in 1km increments -->
3111  <xsl:template name="drawGrid">
3112    <g id="grid" inkscape:groupmode="layer" inkscape:label="Grid">
3113      <xsl:call-template name="drawGridHorizontals">
3114        <xsl:with-param name="line" select="'1'"/>
3115      </xsl:call-template>
3116      <xsl:call-template name="drawGridVerticals">
3117        <xsl:with-param name="line" select="'1'"/>
3118      </xsl:call-template>
3119    </g>
3120  </xsl:template>
3121
3122
3123  <xsl:template name="drawGridHorizontals">
3124    <xsl:param name="line"/>
3125    <xsl:if test="($line*$km) &lt; $documentHeight">
3126      <line id="grid-hori-{$line}" x1="0px" y1="{$line*$km}px" x2="{$documentWidth}px" y2="{$line*$km}px" class="map-grid-line"/>
3127      <xsl:call-template name="drawGridHorizontals">
3128        <xsl:with-param name="line" select="$line+1"/>
3129      </xsl:call-template>
3130    </xsl:if>
3131  </xsl:template>
3132
3133
3134  <xsl:template name="drawGridVerticals">
3135    <xsl:param name="line"/>
3136    <xsl:if test="($line*$km) &lt; $documentWidth">
3137      <line id="grid-vert-{$line}" x1="{$line*$km}px" y1="0px" x2="{$line*$km}px" y2="{$documentHeight}px" class="map-grid-line"/>
3138      <xsl:call-template name="drawGridVerticals">
3139        <xsl:with-param name="line" select="$line+1"/>
3140      </xsl:call-template>
3141    </xsl:if>
3142  </xsl:template>
3143
3144
3145  <!-- Draw map title -->
3146  <xsl:template name="drawTitle">
3147    <xsl:param name="title"/>
3148
3149    <xsl:variable name="x" select="$documentWidth div 2"/>
3150    <xsl:variable name="y" select="30"/>
3151
3152    <g id="marginalia-title" inkscape:groupmode="layer" inkscape:label="Title">
3153      <rect id="marginalia-title-background" x="0px" y="0px" height="{$marginaliaTopHeight - 5}px" width="{$documentWidth}px" class="map-title-background"/>
3154      <text id="marginalia-title-text" class="map-title" x="{$x}" y="{$y}">
3155        <xsl:value-of select="$title"/>
3156      </text>
3157    </g>
3158  </xsl:template>
3159
3160
3161  <!-- Draw an approximate scale in the bottom left corner of the map -->
3162  <xsl:template name="drawScale">
3163    <xsl:variable name="x1" select="14"/>
3164    <xsl:variable name="y1" select="round(($documentHeight)+((($bottomLeftLatitude)-(number($bottomLeftLatitude)))*10000*$scale*$projection))+28"/>
3165    <xsl:variable name="x2" select="$x1+$km"/>
3166    <xsl:variable name="y2" select="$y1"/>
3167
3168    <g id="marginalia-scale" inkscape:groupmode="layer" inkscape:label="Scale">
3169      <line id="marginalia-scale-casing" class="map-scale-casing" x1="{$x1}" y1="{$y1}" x2="{$x2}" y2="{$y2}"/>
3170
3171      <line id="marginalia-scale-core" class="map-scale-core" stroke-dasharray="{($km div 10)}" x1="{$x1}" y1="{$y1}" x2="{$x2}" y2="{$y2}"/>
3172
3173      <line id="marginalia-scale-bookend-from" class="map-scale-bookend" x1="{$x1}" y1="{$y1 + 2}" x2="{$x1}" y2="{$y1 - 10}"/>
3174
3175      <line id="marginalia-scale-bookend-to" class="map-scale-bookend" x1="{$x2}" y1="{$y2 + 2}" x2="{$x2}" y2="{$y2 - 10}"/>
3176
3177      <text id="marginalia-scale-text-from" class="map-scale-caption" x="{$x1}" y="{$y1 - 10}">0</text>
3178
3179      <text id="marginalia-scale-text-to" class="map-scale-caption" x="{$x2}" y="{$y2 - 10}">1km</text>
3180    </g>
3181  </xsl:template>
3182
3183
3184  <!-- Create a comment in SVG source code and RDF description of license -->
3185  <xsl:template name="metadata">
3186
3187    <xsl:comment>
3188
3189      Copyright (c) <xsl:value-of select="$year"/> OpenStreetMap
3190      www.openstreetmap.org
3191      This work is licensed under the
3192      Creative Commons Attribution-ShareAlike 2.0 License.
3193      http://creativecommons.org/licenses/by-sa/2.0/
3194
3195    </xsl:comment>
3196    <metadata id="metadata">
3197      <rdf:RDF xmlns="http://web.resource.org/cc/">
3198        <cc:Work rdf:about="">
3199          <cc:license rdf:resource="http://creativecommons.org/licenses/by-sa/2.0/"/>
3200          <dc:format>image/svg+xml</dc:format>
3201          <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
3202          <dc:title>
3203            <xsl:value-of select="$title"/>
3204          </dc:title>
3205          <dc:date>
3206            <xsl:value-of select="$date"/>
3207          </dc:date>
3208          <dc:source>http://www.openstreetmap.org/</dc:source>
3209        </cc:Work>
3210        <cc:License rdf:about="http://creativecommons.org/licenses/by-sa/2.0/">
3211          <cc:permits rdf:resource="http://web.resource.org/cc/Reproduction"/>
3212          <cc:permits rdf:resource="http://web.resource.org/cc/Distribution"/>
3213          <cc:permits rdf:resource="http://web.resource.org/cc/DerivativeWorks"/>
3214          <cc:requires rdf:resource="http://web.resource.org/cc/Notice"/>
3215          <cc:requires rdf:resource="http://web.resource.org/cc/Attribution"/>
3216          <cc:requires rdf:resource="http://web.resource.org/cc/ShareAlike"/>
3217        </cc:License>
3218      </rdf:RDF>
3219    </metadata>
3220  </xsl:template>
3221
3222  <!-- Create a license logo and description in the image -->
3223  <xsl:template name="in-image-license">
3224    <xsl:param name="dx"/>
3225    <xsl:param name="dy"/>
3226
3227    <g id="license" inkscape:groupmode="layer" inkscape:label="Copyright" transform="translate({$dx},{$dy})">
3228      <style type="text/css">
3229        <![CDATA[
3230                .license-text {
3231                    text-anchor: start;
3232                    font-family: "DejaVu Sans",sans-serif;
3233                    font-size: 6px;
3234                    fill: black;
3235                }
3236            ]]>
3237      </style>
3238      <a id="license-cc-logo-link" xlink:href="http://creativecommons.org/licenses/by-sa/2.0/">
3239        <g id="license-cc-logo" transform="scale(0.5,0.5) translate(-604,-49)">
3240          <path id="path3817_2_" nodetypes="ccccccc" d="M
3241                    182.23532,75.39014 L 296.29928,75.59326 C
3242                    297.89303,75.59326 299.31686,75.35644 299.31686,78.77344 L
3243                    299.17721,116.34033 L 179.3569,116.34033 L
3244                    179.3569,78.63379 C 179.3569,76.94922 179.51999,75.39014
3245                    182.23532,75.39014 z " style="fill:#aab2ab"/>
3246          <g id="g5908_2_" transform="matrix(0.872921,0,0,0.872921,50.12536,143.2144)">
3247            <path id="path5906_2_" type="arc" cx="296.35416"
3248            cy="264.3577" ry="22.939548" rx="22.939548" d="M
3249                        187.20944,-55.6792 C 187.21502,-46.99896
3250                        180.18158,-39.95825 171.50134,-39.95212 C
3251                        162.82113,-39.94708 155.77929,-46.97998
3252                        155.77426,-55.66016 C 155.77426,-55.66687
3253                        155.77426,-55.67249 155.77426,-55.6792 C
3254                        155.76922,-64.36054 162.80209,-71.40125
3255                        171.48233,-71.40631 C 180.16367,-71.41193
3256                        187.20441,-64.37842 187.20944,-55.69824 C
3257                        187.20944,-55.69263 187.20944,-55.68591
3258                        187.20944,-55.6792 z " style="fill:white"/>
3259            <g id="g5706_2_" transform="translate(-289.6157,99.0653)">
3260              <path id="path5708_2_" d="M 473.88455,-167.54724 C
3261                            477.36996,-164.06128 479.11294,-159.79333
3262                            479.11294,-154.74451 C 479.11294,-149.69513
3263                            477.40014,-145.47303 473.9746,-142.07715 C
3264                            470.33929,-138.50055 466.04281,-136.71283
3265                            461.08513,-136.71283 C 456.18736,-136.71283
3266                            451.96526,-138.48544 448.42003,-142.03238 C
3267                            444.87419,-145.57819 443.10158,-149.81537
3268                            443.10158,-154.74451 C 443.10158,-159.6731
3269                            444.87419,-163.94049 448.42003,-167.54724 C
3270                            451.87523,-171.03375 456.09728,-172.77618
3271                            461.08513,-172.77618 C 466.13342,-172.77618
3272                            470.39914,-171.03375 473.88455,-167.54724 z M
3273                            450.76657,-165.20239 C 447.81982,-162.22601
3274                            446.34701,-158.7395 446.34701,-154.74005 C
3275                            446.34701,-150.7417 447.80529,-147.28485
3276                            450.72125,-144.36938 C 453.63778,-141.45288
3277                            457.10974,-139.99462 461.1383,-139.99462 C
3278                            465.16683,-139.99462 468.66848,-141.46743
3279                            471.64486,-144.41363 C 474.47076,-147.14947
3280                            475.88427,-150.59069 475.88427,-154.74005 C
3281                            475.88427,-158.85809 474.44781,-162.35297
3282                            471.57659,-165.22479 C 468.70595,-168.09546
3283                            465.22671,-169.53131 461.1383,-169.53131 C
3284                            457.04993,-169.53131 453.59192,-168.08813
3285                            450.76657,-165.20239 z M 458.52106,-156.49927 C
3286                            458.07074,-157.4809 457.39673,-157.9715
3287                            456.49781,-157.9715 C 454.90867,-157.9715
3288                            454.11439,-156.90198 454.11439,-154.763 C
3289                            454.11439,-152.62341 454.90867,-151.55389
3290                            456.49781,-151.55389 C 457.54719,-151.55389
3291                            458.29676,-152.07519 458.74647,-153.11901 L
3292                            460.94923,-151.94598 C 459.8993,-150.0805
3293                            458.32417,-149.14697 456.22374,-149.14697 C
3294                            454.60384,-149.14697 453.30611,-149.64367
3295                            452.33168,-150.63653 C 451.35561,-151.62994
3296                            450.86894,-152.99926 450.86894,-154.7445 C
3297                            450.86894,-156.46008 451.37123,-157.82159
3298                            452.37642,-158.83013 C 453.38161,-159.83806
3299                            454.63347,-160.34264 456.13423,-160.34264 C
3300                            458.35435,-160.34264 459.94407,-159.46776
3301                            460.90504,-157.71978 L 458.52106,-156.49927 z M
3302                            468.8844,-156.49927 C 468.43353,-157.4809
3303                            467.77292,-157.9715 466.90201,-157.9715 C
3304                            465.28095,-157.9715 464.46988,-156.90198
3305                            464.46988,-154.763 C 464.46988,-152.62341
3306                            465.28095,-151.55389 466.90201,-151.55389 C
3307                            467.95304,-151.55389 468.68918,-152.07519
3308                            469.10925,-153.11901 L 471.36126,-151.94598 C
3309                            470.31301,-150.0805 468.74007,-149.14697
3310                            466.64358,-149.14697 C 465.02587,-149.14697
3311                            463.73095,-149.64367 462.75711,-150.63653 C
3312                            461.78494,-151.62994 461.29773,-152.99926
3313                            461.29773,-154.7445 C 461.29773,-156.46008
3314                            461.79221,-157.82159 462.78061,-158.83013 C
3315                            463.76843,-159.83806 465.02588,-160.34264
3316                            466.55408,-160.34264 C 468.77027,-160.34264
3317                            470.35776,-159.46776 471.3154,-157.71978 L
3318                            468.8844,-156.49927 z "/>
3319            </g>
3320          </g>
3321          <path d="M 297.29639,74.91064 L 181.06688,74.91064 C
3322                    179.8203,74.91064 178.80614,75.92529 178.80614,77.17187 L
3323                    178.80614,116.66748 C 178.80614,116.94922
3324                    179.03466,117.17822 179.31639,117.17822 L
3325                    299.04639,117.17822 C 299.32813,117.17822
3326                    299.55713,116.94922 299.55713,116.66748 L
3327                    299.55713,77.17188 C 299.55713,75.92529 298.54297,74.91064
3328                    297.29639,74.91064 z M 181.06688,75.93213 L
3329                    297.29639,75.93213 C 297.97998,75.93213 298.53565,76.48828
3330                    298.53565,77.17188 C 298.53565,77.17188 298.53565,93.09131
3331                    298.53565,104.59034 L 215.4619,104.59034 C
3332                    212.41698,110.09571 206.55077,113.83399 199.81835,113.83399
3333                    C 193.083,113.83399 187.21825,110.09913 184.1748,104.59034
3334                    L 179.82666,104.59034 C 179.82666,93.09132
3335                    179.82666,77.17188 179.82666,77.17188 C 179.82664,76.48828
3336                    180.38329,75.93213 181.06688,75.93213 z " id="frame"/>
3337          <g enable-background="new" id="g2821">
3338            <path d="M 265.60986,112.8833 C 265.68994,113.03906
3339                        265.79736,113.16504 265.93115,113.26172 C
3340                        266.06494,113.35791 266.22119,113.42969
3341                        266.40088,113.47608 C 266.58154,113.52296
3342                        266.76807,113.54639 266.96045,113.54639 C
3343                        267.09033,113.54639 267.22998,113.53565
3344                        267.3794,113.51368 C 267.52784,113.4922
3345                        267.66749,113.44972 267.79835,113.3877 C
3346                        267.92823,113.32569 268.03761,113.23975
3347                        268.12355,113.13086 C 268.21144,113.02197
3348                        268.25441,112.88379 268.25441,112.71533 C
3349                        268.25441,112.53515 268.19679,112.38916
3350                        268.08156,112.27685 C 267.9673,112.16455
3351                        267.81594,112.07177 267.62941,111.99658 C
3352                        267.44386,111.92236 267.23195,111.85693
3353                        266.9966,111.80078 C 266.76027,111.74463
3354                        266.52101,111.68262 266.27883,111.61377 C
3355                        266.02981,111.55176 265.78762,111.47559
3356                        265.55129,111.38525 C 265.31594,111.29541
3357                        265.10402,111.17822 264.9175,111.03515 C
3358                        264.73098,110.89208 264.58059,110.71337
3359                        264.46535,110.49853 C 264.35109,110.28369
3360                        264.29347,110.02392 264.29347,109.71923 C
3361                        264.29347,109.37646 264.36671,109.07958
3362                        264.51222,108.82763 C 264.6587,108.57568
3363                        264.85011,108.36572 265.08644,108.19726 C
3364                        265.32179,108.02929 265.58937,107.90478
3365                        265.8882,107.82372 C 266.18605,107.74315
3366                        266.48488,107.70263 266.78273,107.70263 C
3367                        267.13136,107.70263 267.46535,107.74169
3368                        267.78566,107.81982 C 268.105,107.89746
3369                        268.39015,108.02392 268.6382,108.19824 C
3370                        268.88722,108.37256 269.08449,108.59521
3371                        269.23097,108.86621 C 269.37648,109.13721
3372                        269.44972,109.46582 269.44972,109.85156 L
3373                        268.02784,109.85156 C 268.01514,109.65234
3374                        267.97315,109.4873 267.90284,109.35693 C
3375                        267.83155,109.22607 267.73682,109.12353
3376                        267.61964,109.04834 C 267.50148,108.97412
3377                        267.36671,108.9209 267.21534,108.89014 C
3378                        267.063,108.85889 266.89796,108.84326
3379                        266.71827,108.84326 C 266.60108,108.84326
3380                        266.48292,108.85596 266.36573,108.88037 C
3381                        266.24757,108.90576 266.14112,108.94922
3382                        266.04542,109.01123 C 265.94874,109.07373
3383                        265.86964,109.15137 265.80812,109.24463 C
3384                        265.7466,109.33838 265.71535,109.45654
3385                        265.71535,109.59961 C 265.71535,109.73047
3386                        265.73976,109.83643 265.78957,109.91699 C
3387                        265.83937,109.99804 265.93801,110.07275
3388                        266.08352,110.14111 C 266.22903,110.20947
3389                        266.43118,110.27832 266.68899,110.34668 C
3390                        266.9468,110.41504 267.28372,110.50244
3391                        267.70071,110.60791 C 267.82473,110.63281
3392                        267.99661,110.67822 268.21731,110.74365 C
3393                        268.43801,110.80908 268.65676,110.91308
3394                        268.87454,111.05615 C 269.09231,111.1997
3395                        269.27981,111.39111 269.43899,111.63037 C
3396                        269.59719,111.87012 269.67629,112.17676
3397                        269.67629,112.55029 C 269.67629,112.85547
3398                        269.61672,113.13867 269.49856,113.3999 C
3399                        269.3804,113.66162 269.20461,113.8872
3400                        268.97122,114.07666 C 268.73782,114.26709
3401                        268.44876,114.41455 268.10403,114.52051 C
3402                        267.75833,114.62647 267.35794,114.6792
3403                        266.90481,114.6792 C 266.53762,114.6792
3404                        266.18118,114.63379 265.83547,114.54346 C
3405                        265.49074,114.45313 265.18508,114.31104
3406                        264.92043,114.11768 C 264.65676,113.92432
3407                        264.4468,113.67774 264.29055,113.37891 C
3408                        264.13528,113.07959 264.06106,112.7251
3409                        264.06692,112.31397 L 265.4888,112.31397 C
3410                        265.48877,112.53809 265.52881,112.72803
3411                        265.60986,112.8833 z " id="path2823"
3412            style="fill:white"/>
3413            <path d="M 273.8667,107.8667 L
3414                        276.35986,114.53076 L 274.8374,114.53076 L
3415                        274.33349,113.04638 L 271.84033,113.04638 L
3416                        271.31787,114.53076 L 269.84326,114.53076 L
3417                        272.36377,107.8667 L 273.8667,107.8667 z M
3418                        273.95068,111.95264 L 273.11084,109.50928 L
3419                        273.09229,109.50928 L 272.22315,111.95264 L
3420                        273.95068,111.95264 z " id="path2825"
3421            style="fill:white"/>
3422          </g>
3423          <g enable-background="new" id="g2827">
3424            <path d="M 239.17821,107.8667 C 239.49559,107.8667
3425                        239.78563,107.89502 240.04735,107.95068 C
3426                        240.30907,108.00683 240.53368,108.09863
3427                        240.72118,108.22607 C 240.9077,108.35351
3428                        241.05321,108.52295 241.15575,108.73437 C
3429                        241.25829,108.94579 241.31005,109.20703
3430                        241.31005,109.51806 C 241.31005,109.854
3431                        241.23388,110.13329 241.08056,110.35742 C
3432                        240.92822,110.58154 240.70165,110.76465
3433                        240.40283,110.90771 C 240.81494,111.02587
3434                        241.12256,111.23291 241.32568,111.5288 C
3435                        241.5288,111.82469 241.63037,112.18114
3436                        241.63037,112.59814 C 241.63037,112.93408
3437                        241.56494,113.22509 241.43408,113.47119 C
3438                        241.30322,113.7168 241.12646,113.91748
3439                        240.90576,114.07324 C 240.68408,114.229
3440                        240.43115,114.34424 240.14795,114.41845 C
3441                        239.86377,114.49365 239.57275,114.53075
3442                        239.27295,114.53075 L 236.03662,114.53075 L
3443                        236.03662,107.86669 L 239.17821,107.86669 L
3444                        239.17821,107.8667 z M 238.99071,110.56201 C
3445                        239.25243,110.56201 239.46727,110.5 239.63622,110.37597
3446                        C 239.80419,110.25146 239.88817,110.05029
3447                        239.88817,109.77099 C 239.88817,109.61572
3448                        239.85985,109.48828 239.80419,109.38915 C
3449                        239.74755,109.28954 239.67333,109.21239
3450                        239.57958,109.15624 C 239.48583,109.10058
3451                        239.37841,109.06151 239.25731,109.04003 C
3452                        239.13524,109.01806 239.00926,109.00732
3453                        238.8784,109.00732 L 237.50535,109.00732 L
3454                        237.50535,110.56201 L 238.99071,110.56201 z M
3455                        239.07664,113.39014 C 239.22019,113.39014
3456                        239.35691,113.37647 239.48777,113.34815 C
3457                        239.61863,113.32032 239.73484,113.27344
3458                        239.83445,113.2085 C 239.93406,113.14307
3459                        240.01316,113.0542 240.07273,112.94239 C
3460                        240.1323,112.83058 240.1616,112.68751
3461                        240.1616,112.51319 C 240.1616,112.17139
3462                        240.06492,111.92725 239.87156,111.78126 C
3463                        239.6782,111.63527 239.42234,111.56202
3464                        239.10496,111.56202 L 237.50535,111.56202 L
3465                        237.50535,113.39014 L 239.07664,113.39014 z "
3466            id="path2829" style="fill:white"/>
3467            <path d="M 241.88914,107.8667 L 243.53269,107.8667 L
3468                        245.09324,110.49854 L 246.64402,107.8667 L
3469                        248.27781,107.8667 L 245.80418,111.97315 L
3470                        245.80418,114.53077 L 244.33543,114.53077 L
3471                        244.33543,111.93604 L 241.88914,107.8667 z "
3472            id="path2831" style="fill:white"/>
3473          </g>
3474          <g id="g6316_1_" transform="matrix(0.624995,0,0,0.624995,391.2294,176.9332)">
3475            <path id="path6318_1_" type="arc" cx="475.97119"
3476            cy="252.08646" ry="29.209877" rx="29.209877" d="M
3477                        -175.0083,-139.1153 C -175.00204,-129.7035
3478                        -182.62555,-122.06751 -192.03812,-122.06049 C
3479                        -201.44913,-122.05341 -209.08512,-129.67774
3480                        -209.09293,-139.09028 C -209.09293,-139.09809
3481                        -209.09293,-139.10749 -209.09293,-139.1153 C
3482                        -209.09919,-148.52784 -201.47413,-156.1623
3483                        -192.06311,-156.17011 C -182.65054,-156.17713
3484                        -175.01456,-148.55207 -175.0083,-139.14026 C
3485                        -175.0083,-139.13092 -175.0083,-139.1239
3486                        -175.0083,-139.1153 z " style="fill:white"/>
3487            <g id="g6320_1_" transform="translate(-23.9521,-89.72962)">
3488              <path id="path6322_1_" d="M -168.2204,-68.05536 C
3489                            -173.39234,-68.05536 -177.76892,-66.25067
3490                            -181.35175,-62.64203 C -185.02836,-58.90759
3491                            -186.86588,-54.48883 -186.86588,-49.38568 C
3492                            -186.86588,-44.28253 -185.02836,-39.89416
3493                            -181.35175,-36.22308 C -177.67673,-32.55114
3494                            -173.29859,-30.71521 -168.2204,-30.71521 C
3495                            -163.07974,-30.71521 -158.62503,-32.56677
3496                            -154.85312,-36.26996 C -151.30307,-39.78558
3497                            -149.52652,-44.15827 -149.52652,-49.38568 C
3498                            -149.52652,-54.6123 -151.33432,-59.03265
3499                            -154.94843,-62.64203 C -158.5625,-66.25067
3500                            -162.98599,-68.05536 -168.2204,-68.05536 z M
3501                            -168.17352,-64.69519 C -163.936,-64.69519
3502                            -160.33752,-63.20221 -157.37655,-60.21466 C
3503                            -154.38748,-57.25836 -152.89214,-53.64899
3504                            -152.89214,-49.38568 C -152.89214,-45.09186
3505                            -154.35466,-41.52856 -157.28438,-38.69653 C
3506                            -160.36876,-35.64727 -163.99849,-34.12304
3507                            -168.17351,-34.12304 C -172.34856,-34.12304
3508                            -175.94701,-35.63244 -178.96892,-38.64965 C
3509                            -181.9908,-41.66918 -183.50176,-45.24657
3510                            -183.50176,-49.38567 C -183.50176,-53.52398
3511                            -181.97518,-57.13414 -178.92205,-60.21465 C
3512                            -175.9939,-63.20221 -172.41107,-64.69519
3513                            -168.17352,-64.69519 z "/>
3514              <path id="path6324_1_" d="M -176.49548,-52.02087 C
3515                            -175.75171,-56.71856 -172.44387,-59.22949
3516                            -168.30008,-59.22949 C -162.33911,-59.22949
3517                            -158.70783,-54.90448 -158.70783,-49.1372 C
3518                            -158.70783,-43.50982 -162.57194,-39.13793
3519                            -168.39383,-39.13793 C -172.39856,-39.13793
3520                            -175.98297,-41.60277 -176.63611,-46.43877 L
3521                            -171.93292,-46.43877 C -171.7923,-43.92778
3522                            -170.1626,-43.04418 -167.83447,-43.04418 C
3523                            -165.1813,-43.04418 -163.4563,-45.50908
3524                            -163.4563,-49.27709 C -163.4563,-53.22942
3525                            -164.94693,-55.32244 -167.74228,-55.32244 C
3526                            -169.79074,-55.32244 -171.55948,-54.57787
3527                            -171.93292,-52.02087 L -170.56418,-52.02789 L
3528                            -174.26734,-48.32629 L -177.96894,-52.02789 L
3529                            -176.49548,-52.02087 z "/>
3530            </g>
3531          </g>
3532          <g id="g2838">
3533            <circle cx="242.56226" cy="90.224609" r="10.8064" id="circle2840" style="fill:white"/>
3534            <g id="g2842">
3535              <path d="M 245.68994,87.09766 C 245.68994,86.68116
3536                            245.35205,86.34424 244.93603,86.34424 L
3537                            240.16357,86.34424 C 239.74755,86.34424
3538                            239.40966,86.68115 239.40966,87.09766 L
3539                            239.40966,91.87061 L 240.74071,91.87061 L
3540                            240.74071,97.52295 L 244.3579,97.52295 L
3541                            244.3579,91.87061 L 245.68993,91.87061 L
3542                            245.68993,87.09766 L 245.68994,87.09766 z "
3543              id="path2844"/>
3544              <circle cx="242.5498" cy="84.083008" r="1.63232" id="circle2846"/>
3545            </g>
3546            <path clip-rule="evenodd" d="M 242.53467,78.31836 C
3547                        239.30322,78.31836 236.56641,79.4458 234.32715,81.70215
3548                        C 232.0293,84.03516 230.88086,86.79736
3549                        230.88086,89.98633 C 230.88086,93.1753
3550                        232.0293,95.91846 234.32715,98.21338 C
3551                        236.625,100.50781 239.36133,101.65527
3552                        242.53467,101.65527 C 245.74756,101.65527
3553                        248.53272,100.49853 250.88819,98.18359 C
3554                        253.10889,95.98681 254.21827,93.2539 254.21827,89.98632
3555                        C 254.21827,86.71874 253.08936,83.95751
3556                        250.83057,81.70214 C 248.57178,79.4458
3557                        245.80615,78.31836 242.53467,78.31836 z M
3558                        242.56396,80.41797 C 245.2124,80.41797
3559                        247.46142,81.35156 249.31103,83.21875 C
3560                        251.18115,85.06592 252.11572,87.32227
3561                        252.11572,89.98633 C 252.11572,92.66992
3562                        251.20068,94.89746 249.36963,96.66699 C
3563                        247.4419,98.57275 245.17334,99.52539 242.56397,99.52539
3564                        C 239.9546,99.52539 237.70557,98.58252
3565                        235.81739,96.6958 C 233.92774,94.80957
3566                        232.98389,92.57324 232.98389,89.98633 C
3567                        232.98389,87.3999 233.93799,85.14404 235.84619,83.21875
3568                        C 237.67676,81.35156 239.9165,80.41797
3569                        242.56396,80.41797 z " id="path2848"
3570            style="fill-rule:evenodd"/>
3571          </g>
3572        </g>
3573      </a>
3574      <a id="license-osm-link" xlink:href="http://www.openstreetmap.org/">
3575        <g transform="translate(-210,10)" id="license-osm-text">
3576          <text class="license-text" dx="0" dy="0">
3577            Copyright © <xsl:value-of select="$year"/> OpenStreetMap (openstreetmap.org)
3578          </text>
3579        </g>
3580      </a>
3581      <a id="license-cc-text-link" xlink:href="http://creativecommons.org/licenses/by-sa/2.0/">
3582        <g transform="translate(-150,18)" id="license-cc-text">
3583          <text class="license-text" dx="0" dy="0">This work is licensed under the Creative</text>
3584          <text class="license-text" dx="0" dy="8">Commons Attribution-ShareAlike 2.0 License.</text>
3585          <text class="license-text" dx="0" dy="16">http://creativecommons.org/licenses/by-sa/2.0/</text>
3586        </g>
3587      </a>
3588    </g>
3589  </xsl:template>
3590
3591
3592  <!-- Draw zoom controls -->
3593  <xsl:template name="zoomControl">
3594    <defs>
3595
3596      <style type="text/css">
3597        .fancyButton {
3598        stroke: #8080ff;
3599        stroke-width: 2px;
3600        fill: #fefefe;
3601        }
3602        .fancyButton:hover {
3603        stroke: red;
3604        }
3605      </style>
3606
3607      <filter id="fancyButton" filterUnits="userSpaceOnUse" x="0" y="0" width="200" height="350">
3608        <feGaussianBlur in="SourceAlpha" stdDeviation="4" result="blur"/>
3609        <feOffset in="blur" dx="2" dy="2" result="offsetBlur"/>
3610        <feSpecularLighting in="blur" surfaceScale="5" specularConstant=".75" specularExponent="20" lighting-color="white" result="specOut">
3611          <fePointLight x="-5000" y="-10000" z="7000"/>
3612        </feSpecularLighting>
3613        <feComposite in="specOut" in2="SourceAlpha" operator="in" result="specOut"/>
3614        <feComposite in="SourceGraphic" in2="specOut" operator="arithmetic" k1="0" k2="1" k3="1" k4="0" result="litPaint"/>
3615        <feMerge>
3616          <feMergeNode in="offsetBlur"/>
3617          <feMergeNode in="litPaint"/>
3618        </feMerge>
3619      </filter>
3620      <symbol id="panDown" viewBox="0 0 19 19" class="fancyButton">
3621        <path d="M 17 9.5 A 7 7 0 1 1 2,9.5 A 7 7 0 1 1 17 9.5 z"/>
3622        <path d="M 9.5,5 L 9.5,14"/>
3623      </symbol>
3624      <symbol id="panUp" viewBox="0 0 19 19" class="fancyButton">
3625        <path d="M 17 9.5 A 7 7 0 1 1 2,9.5 A 7 7 0 1 1 17 9.5 z"/>
3626        <path d="M 9.5,5 L 9.5,14"/>
3627      </symbol>
3628      <symbol id="panLeft" viewBox="0 0 19 19" class="fancyButton">
3629        <path d="M 17 9.5 A 7 7 0 1 1 2,9.5 A 7 7 0 1 1 17 9.5 z"/>
3630        <path d="M 5,9.5 L 14,9.5"/>
3631      </symbol>
3632      <symbol id="panRight" viewBox="0 0 19 19" class="fancyButton">
3633        <path d="M 17 9.5 A 7 7 0 1 1 2,9.5 A 7 7 0 1 1 17 9.5 z"/>
3634        <path d="M 5,9.5 L 14,9.5"/>
3635      </symbol>
3636      <symbol id="zoomIn" viewBox="0 0 19 19" class="fancyButton">
3637        <path d="M 17 9.5 A 7 7 0 1 1 2,9.5 A 7 7 0 1 1 17 9.5 z"/>
3638        <path d="M 5,9.5 L 14,9.5 M 9.5,5 L 9.5,14"/>
3639      </symbol>
3640      <symbol id="zoomOut" viewBox="0 0 19 19" class="fancyButton">
3641        <path d="M 17 9.5 A 7 7 0 1 1 2,9.5 A 7 7 0 1 1 17 9.5 z"/>
3642        <path d="M 5,9.5 L 14,9.5"/>
3643      </symbol>
3644
3645    </defs>
3646
3647    <g id="gPanDown" filter="url(#fancyButton)" onclick="fnPan('down')">
3648      <use x="18px" y="60px" xlink:href="#panDown" width="14px" height="14px"/>
3649    </g>
3650    <g id="gPanRight" filter="url(#fancyButton)" onclick="fnPan('right')">
3651      <use x="8px" y="70px" xlink:href="#panRight" width="14px" height="14px"/>
3652    </g>
3653    <g id="gPanLeft" filter="url(#fancyButton)" onclick="fnPan('left')">
3654      <use x="28px" y="70px" xlink:href="#panLeft" width="14px" height="14px"/>
3655    </g>
3656    <g id="gPanUp" filter="url(#fancyButton)" onclick="fnPan('up')">
3657      <use x="18px" y="80px" xlink:href="#panUp" width="14px" height="14px"/>
3658    </g>
3659
3660    <xsl:variable name="x1" select="25"/>
3661    <xsl:variable name="y1" select="105"/>
3662    <xsl:variable name="x2" select="25"/>
3663    <xsl:variable name="y2" select="300"/>
3664
3665    <line style="stroke-width: 10; stroke-linecap: butt; stroke: #8080ff;">
3666      <xsl:attribute name="x1">
3667        <xsl:value-of select="$x1"/>
3668      </xsl:attribute>
3669      <xsl:attribute name="y1">
3670        <xsl:value-of select="$y1"/>
3671      </xsl:attribute>
3672      <xsl:attribute name="x2">
3673        <xsl:value-of select="$x2"/>
3674      </xsl:attribute>
3675      <xsl:attribute name="y2">
3676        <xsl:value-of select="$y2"/>
3677      </xsl:attribute>
3678    </line>
3679
3680    <line style="stroke-width: 8; stroke-linecap: butt; stroke: white; stroke-dasharray: 10,1;">
3681      <xsl:attribute name="x1">
3682        <xsl:value-of select="$x1"/>
3683      </xsl:attribute>
3684      <xsl:attribute name="y1">
3685        <xsl:value-of select="$y1"/>
3686      </xsl:attribute>
3687      <xsl:attribute name="x2">
3688        <xsl:value-of select="$x2"/>
3689      </xsl:attribute>
3690      <xsl:attribute name="y2">
3691        <xsl:value-of select="$y2"/>
3692      </xsl:attribute>
3693    </line>
3694
3695    <!-- Need to use onmousedown because onclick is interfered with by the onmousedown handler for panning -->
3696    <g id="gZoomIn" filter="url(#fancyButton)" onmousedown="fnZoom('in')">
3697      <use x="15.5px" y="100px" xlink:href="#zoomIn" width="19px" height="19px"/>
3698    </g>
3699
3700    <!-- Need to use onmousedown because onclick is interfered with by the onmousedown handler for panning -->
3701    <g id="gZoomOut" filter="url(#fancyButton)" onmousedown="fnZoom('out')">
3702      <use x="15.5px" y="288px" xlink:href="#zoomOut" width="19px" height="19px"/>
3703    </g>
3704  </xsl:template>
3705
3706  <xsl:template name="javaScript">
3707    <script>
3708      /*
3709
3710      Osmarender
3711
3712      interactive.js
3713
3714      */
3715
3716      function fnResize() {
3717      fnResizeElement("gAttribution")
3718      fnResizeElement("gLicense")
3719      fnResizeElement("gZoomIn")
3720      fnResizeElement("gZoomOut")
3721      }
3722
3723
3724      function fnResizeElement(e) {
3725      //
3726      var oSVG,scale,currentTranslateX,currentTranslateY,oe
3727      //
3728      oSVG=document.rootElement
3729      scale=1/oSVG.currentScale
3730      currentTranslateX=oSVG.currentTranslate.x
3731      currentTranslateY=oSVG.currentTranslate.y
3732      oe=document.getElementById(e)
3733      if (oe) oe.setAttributeNS(null,"transform","scale("+scale+","+scale+") translate("+(-currentTranslateX)+","+(-currentTranslateY)+")")
3734      }
3735
3736
3737      function fnToggleImage(osmImage) {
3738      var xlink = 'http://www.w3.org/1999/xlink';
3739      ogThumbnail=document.getElementById('gThumbnail')
3740      if (ogThumbnail.getAttributeNS(null,"visibility")=="visible") fnHideImage()
3741      else {
3742      ogThumbnail.setAttributeNS(null,"visibility","visible")
3743      oThumbnail=document.getElementById('thumbnail')
3744      oThumbnail.setAttributeNS(xlink,"href",osmImage)
3745      }
3746      }
3747
3748      function fnHideImage() {
3749      ogThumbnail=document.getElementById('gThumbnail')
3750      ogThumbnail.setAttributeNS(null,"visibility","hidden")
3751      }
3752
3753
3754      /* The following code originally written by Jonathan Watt (http://jwatt.org/), Aug. 2005 */
3755
3756      if (!window)
3757      window = this;
3758
3759
3760      function fnOnLoad(evt) {
3761      if (!document) window.document = evt.target.ownerDocument
3762      }
3763
3764
3765      /**
3766      * Event handlers to change the current user space for the zoom and pan
3767      * controls to make them appear to be scale invariant.
3768      */
3769
3770      function fnOnZoom(evt) {
3771      try {
3772      if (evt.newScale == undefined) throw 'bad interface'
3773      // update the transform list that adjusts for zoom and pan
3774      var tlist = document.getElementById('staticElements').transform.baseVal
3775      tlist.getItem(0).setScale(1/evt.newScale, 1/evt.newScale)
3776      tlist.getItem(1).setTranslate(-evt.newTranslate.x, -evt.newTranslate.y)
3777      }
3778      catch (e) {
3779      // work around difficiencies in non-moz implementations (some don't
3780      // implement the SVGZoomEvent or SVGAnimatedTransform interfaces)
3781      var de = document.documentElement
3782      var tform = 'scale(' + 1/de.currentScale + ') ' + 'translate(' + (-de.currentTranslate.x) + ', ' + (-de.currentTranslate.y) + ')'
3783      document.getElementById('staticElements').setAttributeNS(null, 'transform', tform)
3784      }
3785      }
3786
3787
3788      function fnOnScroll(evt) {
3789      var ct = document.documentElement.currentTranslate
3790      try {
3791      // update the transform list that adjusts for zoom and pan
3792      var tlist = document.getElementById('staticElements').transform.baseVal
3793      tlist.getItem(1).setTranslate(-ct.x, -ct.y)
3794      }
3795      catch (e) {
3796      // work around difficiencies in non-moz implementations (some don't
3797      // implement the SVGAnimatedTransform interface)
3798      var tform = 'scale(' + 1/document.documentElement.currentScale + ') ' + 'translate(' + (-ct.x) + ', ' + (-ct.y) + ')';
3799      document.getElementById('staticElements').setAttributeNS(null, 'transform', tform)
3800      }
3801      }
3802
3803
3804      function fnZoom(type) {
3805      var de = document.documentElement;
3806      var oldScale = de.currentScale;
3807      var oldTranslate = { x: de.currentTranslate.x, y: de.currentTranslate.y };
3808      var s = 2;
3809      if (type == 'in') {de.currentScale *= 1.5;}
3810      if (type == 'out') {de.currentScale /= 1.4;}
3811      // correct currentTranslate so zooming is to the center of the viewport:
3812
3813      var vp_width, vp_height;
3814      try {
3815      vp_width = de.viewport.width;
3816      vp_height = de.viewport.height;
3817      }
3818      catch (e) {
3819      // work around difficiency in moz ('viewport' property not implemented)
3820      vp_width = window.innerWidth;
3821      vp_height = window.innerHeight;
3822      }
3823      de.currentTranslate.x = vp_width/2 - ((de.currentScale/oldScale) * (vp_width/2 - oldTranslate.x));
3824      de.currentTranslate.y = vp_height/2 - ((de.currentScale/oldScale) * (vp_height/2 - oldTranslate.y));
3825
3826      }
3827
3828
3829      function fnPan(type) {
3830      var de = document.documentElement;
3831      var ct = de.currentTranslate;
3832      var t = 150;
3833      if (type == 'right') ct.x += t;
3834      if (type == 'down') ct.y += t;
3835      if (type == 'left') ct.x -= t;
3836      if (type == 'up') ct.y -= t;
3837      }
3838
3839
3840      var gCurrentX,gCurrentY
3841      var gDeltaX,gDeltaY
3842      var gMouseDown=false
3843      var gCurrentTranslate=document.documentElement.currentTranslate
3844
3845      function fnOnMouseDown(evt) {
3846      gCurrentX=gCurrentTranslate.x
3847      gCurrentY=gCurrentTranslate.y
3848      gDeltaX=evt.clientX
3849      gDeltaY=evt.clientY
3850      gMouseDown=true
3851      evt.target.ownerDocument.rootElement.setAttributeNS(null,"cursor","move")
3852      }
3853
3854
3855      function fnOnMouseUp(evt) {
3856      gMouseDown=false
3857      evt.target.ownerDocument.rootElement.setAttribute("cursor","default")
3858      }
3859
3860
3861      function fnOnMouseMove(evt) {
3862      var id
3863      if (gMouseDown) {
3864      gCurrentTranslate.x=gCurrentX+evt.clientX-gDeltaX
3865      gCurrentTranslate.y=gCurrentY+evt.clientY-gDeltaY
3866      }
3867      }
3868
3869
3870    </script>
3871  </xsl:template>
3872
3873</xsl:stylesheet>
Note: See TracBrowser for help on using the repository browser.