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

Last change on this file since 6402 was 6402, checked in by bobkare, 12 years ago

Bugfix: When making sure multipolygons are only drawn once, draw when we have the role=outer instead of finding first member, which failed in some cases

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