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

Last change on this file since 7428 was 7205, checked in by jochen, 12 years ago

fixed wrong SVG CSS: "text-anchor: start" instead of "left"

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