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

Last change on this file since 8256 was 8256, checked in by andrew, 11 years ago

Typo fixes within comments only.

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