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

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

Implemented a fancy algorithm for finding the center of polygons. See http://bob.cakebox.net/poly-center.php for human-readable explanation of algorithm.

File size: 155.1 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      <!-- Find the nearest intersection between the line vertex-linepoint and the nearest edge inwards into the polygon -->
1117      <xsl:variable name="intersection">
1118        <xsl:call-template name="areacenterFindPointForVertex">
1119          <xsl:with-param name="vertex" select="key('nodeById', $vertex/@ref)" />
1120          <xsl:with-param name="edgestart" select="../nd[1]" />
1121          <xsl:with-param name="linepoint_x" select="$linepoint_x" />
1122          <xsl:with-param name="linepoint_y" select="$linepoint_y" />
1123        </xsl:call-template>
1124      </xsl:variable>
1125      <xsl:variable name="intersection_x" select="substring-before($intersection, ',')" />
1126      <xsl:variable name="intersection_y" select="substring-after($intersection, ',')" />
1127
1128      <xsl:variable name="point_x" select="key('nodeById', $vertex/@ref)/@lon + ( $intersection_x - key('nodeById', $vertex/@ref)/@lon ) div 2" />
1129      <xsl:variable name="point_y" select="key('nodeById', $vertex/@ref)/@lat + ( $intersection_y - key('nodeById', $vertex/@ref)/@lat ) div 2" />
1130     
1131      <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 -->
1132        <!-- Note: this will produce trailing semicolon, which is nice as it simplifies looping over this later -->
1133        <xsl:value-of select="$point_x" />,<xsl:value-of select="$point_y" />;
1134      </xsl:if>
1135    </xsl:for-each>
1136  </xsl:template>
1137
1138  <!-- Calculate the angle between $from and $to in $through. Returns answer in radians -->
1139  <xsl:template name="angleThroughPoints">
1140    <xsl:param name="from" />
1141    <xsl:param name="through" />
1142    <xsl:param name="to" />
1143
1144    <xsl:variable name="from_x" select="($from/@lon) - ($through/@lon)" />
1145    <xsl:variable name="from_y" select="$from/@lat - $through/@lat" />
1146    <xsl:variable name="to_x" select="$to/@lon - $through/@lon" />
1147    <xsl:variable name="to_y" select="$to/@lat - $through/@lat" />
1148
1149    <xsl:variable name="from_angle_">
1150      <xsl:call-template name="atan2">
1151        <xsl:with-param name="x" select="$from_x" />
1152        <xsl:with-param name="y" select="$from_y" />
1153      </xsl:call-template>
1154    </xsl:variable>
1155    <xsl:variable name="from_angle" select="$from_angle_ + $pi" />
1156    <xsl:variable name="to_angle_">
1157      <xsl:call-template name="atan2">
1158        <xsl:with-param name="x" select="$to_x" />
1159        <xsl:with-param name="y" select="$to_y" />
1160      </xsl:call-template>
1161    </xsl:variable>
1162    <xsl:variable name="to_angle" select="$to_angle_ + $pi" />
1163
1164    <xsl:variable name="min_angle">
1165      <xsl:choose>
1166        <xsl:when test="$from_angle &gt; $to_angle">
1167          <xsl:value-of select="$to_angle" />
1168        </xsl:when>
1169        <xsl:otherwise>
1170          <xsl:value-of select="$from_angle" />
1171        </xsl:otherwise>
1172      </xsl:choose>
1173    </xsl:variable>
1174    <xsl:variable name="max_angle">
1175      <xsl:choose>
1176        <xsl:when test="$from_angle &gt; $to_angle">
1177          <xsl:value-of select="$from_angle" />
1178        </xsl:when>
1179        <xsl:otherwise>
1180          <xsl:value-of select="$to_angle" />
1181        </xsl:otherwise>
1182      </xsl:choose>
1183    </xsl:variable>
1184
1185    <xsl:value-of select="$min_angle + ($max_angle - $min_angle) div 2" />
1186  </xsl:template>
1187
1188  <!-- atan2 implementation from http://lists.fourthought.com/pipermail/exslt/2007-March/001540.html -->
1189  <xsl:template name="atan2">
1190    <xsl:param name="y"/>
1191    <xsl:param name="x"/>
1192    <!-- http://lists.apple.com/archives/PerfOptimization-dev/2005/Jan/msg00051.html -->
1193    <xsl:variable name="PI"    select="number(3.1415926535897)"/>
1194    <xsl:variable name="PIBY2" select="$PI div 2.0"/>
1195    <xsl:choose>
1196      <xsl:when test="$x = 0.0">
1197        <xsl:choose>
1198          <xsl:when test="($y &gt; 0.0)">
1199            <xsl:value-of select="$PIBY2"/>
1200          </xsl:when>
1201          <xsl:when test="($y &lt; 0.0)">
1202            <xsl:value-of select="-$PIBY2"/>
1203          </xsl:when>
1204          <xsl:otherwise>
1205            <!-- Error: Degenerate x == y == 0.0 -->
1206            <xsl:value-of select="number(NaN)"/>
1207          </xsl:otherwise>
1208        </xsl:choose>
1209      </xsl:when>
1210      <xsl:otherwise>
1211        <xsl:variable name="z" select="$y div $x"/>
1212        <xsl:variable name="absZ">
1213          <!-- inline abs function -->
1214          <xsl:choose>
1215            <xsl:when test="$z &lt; 0.0">
1216              <xsl:value-of select="- number($z)"/>
1217            </xsl:when>
1218            <xsl:otherwise>
1219              <xsl:value-of select="number($z)"/>
1220            </xsl:otherwise>
1221          </xsl:choose>
1222        </xsl:variable>
1223        <xsl:choose>
1224          <xsl:when test="($absZ &lt; 1.0)">
1225            <xsl:variable name="f1Z" select="$z div (1.0 + 0.28*$z*$z)"/>
1226            <xsl:choose>
1227              <xsl:when test="($x &lt; 0.0) and ($y &lt; 0.0)">
1228                <xsl:value-of select="$f1Z - $PI"/>
1229              </xsl:when>
1230              <xsl:when test="($x &lt; 0.0)">
1231                <xsl:value-of select="$f1Z + $PI"/>
1232              </xsl:when>
1233              <xsl:otherwise>
1234                <xsl:value-of select="$f1Z"/>
1235              </xsl:otherwise>
1236            </xsl:choose>
1237          </xsl:when>
1238          <xsl:otherwise>
1239            <xsl:variable name="f2Z" select="$PIBY2 - ($z div ($z*$z +
12400.28))"/>
1241            <xsl:choose>
1242              <xsl:when test="($y &lt; 0.0)">
1243                <xsl:value-of select="$f2Z - $PI"/>
1244              </xsl:when>
1245              <xsl:otherwise>
1246                <xsl:value-of select="$f2Z"/>
1247              </xsl:otherwise>
1248            </xsl:choose>
1249          </xsl:otherwise>
1250        </xsl:choose>
1251      </xsl:otherwise>
1252    </xsl:choose>
1253  </xsl:template>
1254
1255  <!-- Find a point on the line going through $point at $angle that's guaranteed to be outside the polygon -->
1256  <xsl:template name="areacenterLinepoint">
1257    <xsl:param name="point" />
1258    <xsl:param name="angle" />
1259
1260    <xsl:variable name="cos_angle">
1261      <xsl:call-template name="cos">
1262        <xsl:with-param name="angle" select="$angle"/>
1263      </xsl:call-template>
1264    </xsl:variable>
1265   
1266    <xsl:variable name="sin_angle">
1267      <xsl:call-template name="sin">
1268        <xsl:with-param name="angle" select="$angle"/>
1269      </xsl:call-template>
1270    </xsl:variable>
1271   
1272    <xsl:value-of select="$point/@lon + $cos_angle"/>, <xsl:value-of select="$point/@lat + $sin_angle"/>
1273  </xsl:template>
1274 
1275  <!-- Constants for trig templates -->
1276  <xsl:variable name="pi" select="3.1415926535897"/>
1277  <xsl:variable name="halfPi" select="$pi div 2"/>
1278  <xsl:variable name="twicePi" select="$pi*2"/>
1279
1280  <xsl:template name="sin">
1281    <xsl:param name="angle" />
1282    <xsl:param name="precision" select="0.00000001"/>
1283
1284    <xsl:variable name="y">
1285      <xsl:choose>
1286        <xsl:when test="not(0 &lt;= $angle and $twicePi > $angle)">
1287          <xsl:call-template name="cutIntervals">
1288            <xsl:with-param name="length" select="$twicePi"/>
1289            <xsl:with-param name="angle" select="$angle"/>
1290          </xsl:call-template>
1291        </xsl:when>
1292        <xsl:otherwise>
1293          <xsl:value-of select="$angle"/>
1294        </xsl:otherwise>
1295      </xsl:choose>
1296    </xsl:variable>
1297
1298    <xsl:call-template name="sineIter">
1299      <xsl:with-param name="angle2" select="$y*$y"/>
1300      <xsl:with-param name="res" select="$y"/>
1301      <xsl:with-param name="elem" select="$y"/>
1302      <xsl:with-param name="n" select="1"/>
1303      <xsl:with-param name="precision" select="$precision" />
1304    </xsl:call-template>
1305  </xsl:template>
1306
1307  <xsl:template name="sineIter">
1308    <xsl:param name="angle2" />
1309    <xsl:param name="res" />
1310    <xsl:param name="elem" />
1311    <xsl:param name="n" />
1312    <xsl:param name="precision"/>
1313
1314    <xsl:variable name="nextN" select="$n+2" />
1315    <xsl:variable name="newElem" select="-$elem*$angle2 div ($nextN*($nextN - 1))" />
1316    <xsl:variable name="newResult" select="$res + $newElem" />
1317    <xsl:variable name="diffResult" select="$newResult - $res" />
1318
1319    <xsl:choose>
1320      <xsl:when test="$diffResult > $precision or $diffResult &lt; -$precision">
1321        <xsl:call-template name="sineIter">
1322          <xsl:with-param name="angle2" select="$angle2" />
1323          <xsl:with-param name="res" select="$newResult" />
1324          <xsl:with-param name="elem" select="$newElem" />
1325          <xsl:with-param name="n" select="$nextN" />
1326          <xsl:with-param name="precision" select="$precision" />
1327        </xsl:call-template>
1328      </xsl:when>
1329      <xsl:otherwise>
1330        <xsl:value-of select="$newResult"/>
1331      </xsl:otherwise>
1332    </xsl:choose>
1333  </xsl:template>
1334
1335  <xsl:template name="cutIntervals">
1336    <xsl:param name="length"/>
1337    <xsl:param name="angle"/>
1338
1339    <xsl:variable name="vsign">
1340      <xsl:choose>
1341        <xsl:when test="$angle >= 0">1</xsl:when>
1342        <xsl:otherwise>-1</xsl:otherwise>
1343      </xsl:choose>
1344    </xsl:variable>
1345    <xsl:variable name="vdiff" select="$length*floor($angle div $length) -$angle"/> 
1346    <xsl:choose>
1347      <xsl:when test="$vdiff*$angle > 0">
1348        <xsl:value-of select="$vsign*$vdiff"/>
1349      </xsl:when>
1350      <xsl:otherwise>
1351        <xsl:value-of select="-$vsign*$vdiff"/>
1352      </xsl:otherwise>
1353    </xsl:choose>
1354  </xsl:template>
1355
1356  <xsl:template name="cos">
1357    <xsl:param name="angle" />
1358    <xsl:param name="precision" select="0.00000001"/>
1359
1360    <xsl:call-template name="sin">
1361      <xsl:with-param name="angle" select="$halfPi - $angle" />
1362      <xsl:with-param name="precision" select="$precision" />
1363    </xsl:call-template>
1364  </xsl:template>
1365
1366  <!-- Find the point halfway into the polygon along the line $vertex-$linepoint -->
1367  <xsl:template name="areacenterFindPointForVertex">
1368    <xsl:param name="vertex" />
1369    <xsl:param name="edgestart" />
1370    <xsl:param name="linepoint_x" />
1371    <xsl:param name="linepoint_y" />
1372    <xsl:param name="intersectioncount_on" select="0" /><!-- Number of intersections. Only counts those on segment vertex-linepoint -->
1373    <xsl:param name="nearest_on_x" />
1374    <xsl:param name="nearest_on_y" />
1375    <xsl:param name="nearest_on_dist" select="'NaN'" />
1376    <xsl:param name="nearest_off_x" />
1377    <xsl:param name="nearest_off_y" />
1378    <xsl:param name="nearest_off_dist" select="'NaN'" />
1379
1380    <xsl:choose>
1381      <!-- If there are no more vertices we don't have a second point for the edge, and are finished -->
1382      <xsl:when test="$edgestart/following-sibling::nd[1]">
1383        <xsl:variable name="edgeend" select="$edgestart/following-sibling::nd[1]" />
1384
1385        <!-- Get the intersection point between the line $vertex-$linepoint and $edgestart-$edgeend -->
1386        <xsl:variable name="intersection">
1387          <xsl:choose>
1388            <xsl:when test="$vertex/@id = $edgestart/@ref or $vertex/@id = $edgeend/@ref">
1389              <!-- Vertex is one of the points in edge, skip -->
1390              NoIntersection
1391            </xsl:when>
1392            <xsl:otherwise>     
1393              <xsl:call-template name="areacenterLinesIntersection">
1394                <xsl:with-param name="x1" select="$vertex/@lon" />
1395                <xsl:with-param name="y1" select="$vertex/@lat" />
1396                <xsl:with-param name="x2" select="$linepoint_x" />
1397                <xsl:with-param name="y2" select="$linepoint_y" />
1398                <xsl:with-param name="x3" select="key('nodeById', $edgestart/@ref)/@lon" />
1399                <xsl:with-param name="y3" select="key('nodeById', $edgestart/@ref)/@lat" />
1400                <xsl:with-param name="x4" select="key('nodeById', $edgeend/@ref)/@lon" />
1401                <xsl:with-param name="y4" select="key('nodeById', $edgeend/@ref)/@lat" />
1402              </xsl:call-template>
1403            </xsl:otherwise>
1404          </xsl:choose>
1405        </xsl:variable>
1406
1407        <!-- Haul ix, iy, ua and ub out of the csv -->
1408        <xsl:variable name="ix" select="substring-before($intersection, ',')" />
1409        <xsl:variable name="iy" select="substring-before(substring-after($intersection, ','), ',')" />
1410        <xsl:variable name="ua" select="substring-before(substring-after(substring-after($intersection, ','), ','), ',')" />
1411        <xsl:variable name="ub" select="substring-after(substring-after(substring-after($intersection, ','), ','), ',')" />
1412
1413        <!-- A) Is there actually an intersection? B) Is it on edge? -->
1414        <xsl:choose>
1415          <xsl:when test="$intersection != 'NoIntersection' and $ub &gt; 0 and $ub &lt;= 1">
1416            <xsl:variable name="distance">
1417              <xsl:call-template name="areacenterPointDistance">
1418                <xsl:with-param name="x1" select="$vertex/@lon" />
1419                <xsl:with-param name="y1" select="$vertex/@lat" />
1420                <xsl:with-param name="x2" select="$ix" />
1421                <xsl:with-param name="y2" select="$iy" />
1422              </xsl:call-template>
1423            </xsl:variable>
1424
1425            <!-- Is intersection on the segment $vertex-$linepoint, or on the other side of $vertex? -->
1426            <xsl:variable name="isOnSegment">
1427              <xsl:if test="$ua &gt;= 0">Yes</xsl:if>
1428            </xsl:variable>
1429           
1430            <xsl:variable name="isNewNearestOn">
1431              <xsl:if test="$isOnSegment = 'Yes' and ( $nearest_on_dist = 'NaN' or $distance &lt; $nearest_on_dist )">Yes</xsl:if>
1432            </xsl:variable>
1433           
1434            <xsl:variable name="isNewNearestOff">
1435              <xsl:if test="$isOnSegment != 'Yes' and ( $nearest_off_dist = 'NaN' or $distance &lt; $nearest_off_dist )">Yes</xsl:if>
1436            </xsl:variable>
1437
1438            <xsl:call-template name="areacenterFindPointForVertex">
1439              <xsl:with-param name="vertex" select="$vertex" />
1440              <xsl:with-param name="linepoint_x" select="$linepoint_x" />
1441              <xsl:with-param name="linepoint_y" select="$linepoint_y" />
1442              <xsl:with-param name="edgestart" select="$edgeend" />
1443              <xsl:with-param name="intersectioncount_on" select="$intersectioncount_on + number(boolean($isOnSegment = 'Yes'))" />
1444              <xsl:with-param name="nearest_on_dist"> <xsl:choose>
1445                <xsl:when test="$isNewNearestOn = 'Yes'"> <xsl:value-of select="$distance" /> </xsl:when>
1446                <xsl:otherwise> <xsl:value-of select="$nearest_on_dist" /> </xsl:otherwise>
1447              </xsl:choose> </xsl:with-param>
1448              <xsl:with-param name="nearest_on_x"> <xsl:choose>
1449                <xsl:when test="$isNewNearestOn = 'Yes'"> <xsl:value-of select="$ix" /> </xsl:when>
1450                <xsl:otherwise> <xsl:value-of select="$nearest_on_x" /> </xsl:otherwise>
1451              </xsl:choose> </xsl:with-param>
1452              <xsl:with-param name="nearest_on_y"> <xsl:choose>
1453                <xsl:when test="$isNewNearestOn = 'Yes'"> <xsl:value-of select="$iy" /> </xsl:when>
1454                <xsl:otherwise> <xsl:value-of select="$nearest_on_y" /> </xsl:otherwise>
1455              </xsl:choose> </xsl:with-param>
1456              <xsl:with-param name="nearest_off_dist"> <xsl:choose>
1457                <xsl:when test="$isNewNearestOff = 'Yes'"> <xsl:value-of select="$distance" /> </xsl:when>
1458                <xsl:otherwise> <xsl:value-of select="$nearest_off_dist" /> </xsl:otherwise>
1459              </xsl:choose> </xsl:with-param>
1460              <xsl:with-param name="nearest_off_x"> <xsl:choose>
1461                <xsl:when test="$isNewNearestOff = 'Yes'"> <xsl:value-of select="$ix" /> </xsl:when>
1462                <xsl:otherwise> <xsl:value-of select="$nearest_off_x" /> </xsl:otherwise>
1463              </xsl:choose> </xsl:with-param>
1464              <xsl:with-param name="nearest_off_y"> <xsl:choose>
1465                <xsl:when test="$isNewNearestOff = 'Yes'"> <xsl:value-of select="$iy" /> </xsl:when>
1466                <xsl:otherwise> <xsl:value-of select="$nearest_off_y" /> </xsl:otherwise>
1467              </xsl:choose> </xsl:with-param>
1468            </xsl:call-template>
1469           
1470          </xsl:when>
1471          <!-- No intersection, just go on to next edge -->       
1472          <xsl:otherwise>
1473            <xsl:call-template name="areacenterFindPointForVertex">
1474              <xsl:with-param name="vertex" select="$vertex" />
1475              <xsl:with-param name="linepoint_x" select="$linepoint_x" />
1476              <xsl:with-param name="linepoint_y" select="$linepoint_y" />
1477              <xsl:with-param name="edgestart" select="$edgeend" />
1478              <xsl:with-param name="intersectioncount_on" select="$intersectioncount_on" />
1479              <xsl:with-param name="nearest_on_dist" select="$nearest_on_dist" />
1480              <xsl:with-param name="nearest_on_x" select="$nearest_on_x" />
1481              <xsl:with-param name="nearest_on_y" select="$nearest_on_y" />
1482              <xsl:with-param name="nearest_off_dist" select="$nearest_off_dist" />
1483              <xsl:with-param name="nearest_off_x" select="$nearest_off_x" />
1484              <xsl:with-param name="nearest_off_y" select="$nearest_off_y" />
1485            </xsl:call-template>
1486          </xsl:otherwise>
1487        </xsl:choose>
1488      </xsl:when>
1489      <xsl:otherwise>
1490        <!-- No more edges, return point -->
1491        <xsl:choose>
1492          <xsl:when test="$intersectioncount_on mod 2 = 0">
1493            <xsl:value-of select="$nearest_off_x"/>,<xsl:value-of select="$nearest_off_y"/>
1494          </xsl:when>
1495          <xsl:otherwise>
1496            <xsl:value-of select="$nearest_on_x"/>,<xsl:value-of select="$nearest_on_y"/>
1497          </xsl:otherwise>
1498        </xsl:choose>
1499      </xsl:otherwise>
1500    </xsl:choose>
1501  </xsl:template>
1502
1503  <!--
1504      Finds intersection point between lines x1,y1 -> x2,y2 and x3,y3 -> x4,y4.
1505      Returns a comma-separated list of x,y,ua,ub or NoIntersection if the lines do not intersect
1506  -->
1507  <xsl:template name="areacenterLinesIntersection">
1508    <xsl:param name="x1" />
1509    <xsl:param name="y1" />
1510    <xsl:param name="x2" />
1511    <xsl:param name="y2" />
1512    <xsl:param name="x3" />
1513    <xsl:param name="y3" />
1514    <xsl:param name="x4" />
1515    <xsl:param name="y4" />
1516
1517    <xsl:variable name="denom" select="(( $y4 - $y3 ) * ( $x2 - $x1 )) -
1518                                       (( $x4 - $x3 ) * ( $y2 - $y1 ))" />
1519    <xsl:variable name="nume_a" select="(( $x4 - $x3 ) * ( $y1 - $y3 )) -
1520                                        (( $y4 - $y3 ) * ( $x1 - $x3 ))" />
1521    <xsl:variable name="nume_b" select="(( $x2 - $x1 ) * ( $y1 - $y3 )) -
1522                                        (( $y2 - $y1 ) * ( $x1 - $x3 ))" />
1523
1524    <xsl:choose>
1525      <xsl:when test="$denom = 0">
1526        NoIntersection
1527      </xsl:when>
1528      <xsl:otherwise>
1529        <xsl:variable name="ua" select="$nume_a div $denom" />
1530        <xsl:variable name="ub" select="$nume_b div $denom" />
1531
1532        <!-- x,y,ua,ub -->
1533        <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" />
1534      </xsl:otherwise>
1535    </xsl:choose>
1536  </xsl:template>
1537
1538  <!-- Distance between two points -->
1539  <xsl:template name="areacenterPointDistance">
1540    <xsl:param name="x1" />
1541    <xsl:param name="y1" />
1542    <xsl:param name="x2" />
1543    <xsl:param name="y2" />
1544
1545    <!-- sqrt( ($x2 - $x1)**2 + ($y2 - $y1)**2 ) -->
1546    <xsl:call-template name="sqrt">
1547      <xsl:with-param name="num" select="($x2*$x2 - $x2*$x1 - $x1*$x2 + $x1*$x1) + ($y2*$y2 - $y2*$y1 - $y1*$y2 + $y1*$y1)" />
1548    </xsl:call-template>
1549  </xsl:template>
1550
1551  <xsl:template name="sqrt">
1552    <xsl:param name="num" select="0"/>  <!-- The number you want to find the
1553                                             square root of -->
1554    <xsl:param name="try" select="1"/>  <!-- The current 'try'.  This is used
1555                                             internally. -->
1556    <xsl:param name="iter" select="1"/> <!-- The current iteration, checked
1557                                             against maxiter to limit loop count -->
1558    <xsl:param name="maxiter" select="10"/>  <!-- Set this up to insure
1559against infinite loops -->
1560   
1561    <!-- This template was written by Nate Austin using Sir Isaac Newton's
1562         method of finding roots -->
1563   
1564    <xsl:choose>
1565      <xsl:when test="$try * $try = $num or $iter &gt; $maxiter">
1566        <xsl:value-of select="$try"/>
1567      </xsl:when>
1568      <xsl:otherwise>
1569        <xsl:call-template name="sqrt">
1570          <xsl:with-param name="num" select="$num"/>
1571          <xsl:with-param name="try" select="$try - (($try * $try - $num) div
1572                                             (2 * $try))"/>
1573          <xsl:with-param name="iter" select="$iter + 1"/>
1574          <xsl:with-param name="maxiter" select="$maxiter"/>
1575        </xsl:call-template>
1576      </xsl:otherwise>
1577    </xsl:choose>
1578  </xsl:template>
1579
1580  <!-- Returns the medium value of all the points -->
1581  <xsl:template name="areacenterMediumOfPoints">
1582    <xsl:param name="points" />
1583    <xsl:param name="total_x" select="0" />
1584    <xsl:param name="total_y" select="0" />
1585    <xsl:param name="count" select="0" />
1586
1587    <xsl:variable name="point" select="substring-before($points, ';')" />
1588
1589    <xsl:choose>
1590      <xsl:when test="string-length($point) &gt; 0">
1591        <xsl:variable name="x" select="substring-before($point, ',')" />
1592        <xsl:variable name="y" select="substring-after($point, ',')" />
1593
1594        <xsl:call-template name="areacenterMediumOfPoints">
1595          <xsl:with-param name="points" select="substring-after($points, ';')" />
1596          <xsl:with-param name="total_x" select="$total_x + $x" />
1597          <xsl:with-param name="total_y" select="$total_y + $y" />
1598          <xsl:with-param name="count" select="$count + 1" />
1599        </xsl:call-template>
1600      </xsl:when>
1601      <xsl:otherwise>
1602        <xsl:value-of select="$total_x div $count" />, <xsl:value-of select="$total_y div $count" />
1603      </xsl:otherwise>
1604    </xsl:choose>
1605  </xsl:template>
1606
1607  <!-- Returns the coordinates of the point in points that's nearest x,y -->
1608  <xsl:template name="areacenterNearestPoint">
1609    <xsl:param name="points" />
1610    <xsl:param name="x" />
1611    <xsl:param name="y" />
1612    <xsl:param name="nearest_x" />
1613    <xsl:param name="nearest_y" />
1614    <xsl:param name="nearest_dist" select="'NaN'" />
1615
1616    <xsl:variable name="point" select="substring-before($points, ';')" />
1617
1618    <xsl:choose>
1619      <xsl:when test="string-length($point) &gt; 0"> 
1620        <xsl:variable name="point_x" select="substring-before($point, ',')" />
1621        <xsl:variable name="point_y" select="substring-after($point, ',')" />
1622       
1623        <xsl:variable name="distance">
1624          <xsl:call-template name="areacenterPointDistance">
1625            <xsl:with-param name="x1" select="$x" />
1626            <xsl:with-param name="y1" select="$y" />
1627            <xsl:with-param name="x2" select="$point_x" />
1628            <xsl:with-param name="y2" select="$point_y" />
1629          </xsl:call-template>
1630        </xsl:variable>
1631
1632        <xsl:variable name="isNewNearest" select="$nearest_dist = 'NaN' or $distance &lt; $nearest_dist" />
1633
1634        <xsl:call-template name="areacenterNearestPoint">
1635          <xsl:with-param name="points" select="substring-after($points, ';')" />
1636          <xsl:with-param name="x" select="$x" />
1637          <xsl:with-param name="y" select="$y" />
1638          <xsl:with-param name="nearest_dist"><xsl:choose>
1639            <xsl:when test="$isNewNearest"><xsl:value-of select="$distance" /></xsl:when>
1640            <xsl:otherwise><xsl:value-of select="$nearest_dist" /></xsl:otherwise>
1641          </xsl:choose></xsl:with-param>
1642          <xsl:with-param name="nearest_x"><xsl:choose>
1643            <xsl:when test="$isNewNearest"><xsl:value-of select="$point_x" /></xsl:when>
1644            <xsl:otherwise><xsl:value-of select="$nearest_x" /></xsl:otherwise>
1645          </xsl:choose></xsl:with-param>
1646          <xsl:with-param name="nearest_y"><xsl:choose>
1647            <xsl:when test="$isNewNearest"><xsl:value-of select="$point_y" /></xsl:when>
1648            <xsl:otherwise><xsl:value-of select="$nearest_y" /></xsl:otherwise>
1649          </xsl:choose></xsl:with-param>
1650        </xsl:call-template>
1651      </xsl:when>
1652      <xsl:otherwise>
1653        <xsl:value-of select="$nearest_x" />, <xsl:value-of select="$nearest_y" />
1654      </xsl:otherwise>
1655    </xsl:choose>
1656  </xsl:template>
1657
1658  <!-- Process a <text> instruction -->
1659  <xsl:template match="text">
1660    <xsl:param name="elements"/>
1661
1662    <!-- This is the instruction that is currently being processed -->
1663    <xsl:variable name="instruction" select="."/>
1664
1665    <!-- Select all <node> elements that have a key that matches the k attribute of the text instruction -->
1666    <xsl:for-each select="$elements[name()='node'][tag[@k=$instruction/@k]]">
1667      <xsl:call-template name="renderText">
1668        <xsl:with-param name="instruction" select="$instruction"/>
1669      </xsl:call-template>
1670    </xsl:for-each>
1671
1672    <!-- Select all <way> elements -->
1673    <xsl:apply-templates select="$elements[name()='way']" mode="textPath">
1674      <xsl:with-param name="instruction" select="$instruction"/>
1675    </xsl:apply-templates>
1676  </xsl:template>
1677
1678
1679  <!-- Suppress output of any unhandled elements -->
1680  <xsl:template match="*" mode="textPath"/>
1681
1682
1683  <!-- Render textPaths for a way -->
1684  <xsl:template match="way" mode="textPath">
1685    <xsl:param name="instruction"/>
1686
1687    <!-- The current <way> element -->
1688    <xsl:variable name="way" select="."/>
1689
1690    <!-- DODI: !!!WORKAROUND!!! no text for one node ways-->
1691    <xsl:if test="count($way/nd) &gt; 1">
1692      <xsl:variable name='text'>
1693        <xsl:choose>
1694          <xsl:when test='$instruction/@k'>
1695            <xsl:value-of select='tag[@k=$instruction/@k]/@v'/>
1696          </xsl:when>
1697          <xsl:otherwise>
1698            <xsl:apply-templates select='$instruction' mode='textFormat'>
1699              <xsl:with-param name='way' select='$way'/>
1700            </xsl:apply-templates>
1701          </xsl:otherwise>
1702        </xsl:choose>
1703      </xsl:variable>
1704
1705      <xsl:if test='string($text)'>
1706
1707        <xsl:variable name="pathDirection">
1708          <xsl:choose>
1709            <!-- Manual override, reverse direction -->
1710            <xsl:when test="tag[@k='name_direction']/@v='-1' or tag[@k='osmarender:nameDirection']/@v='-1'">reverse</xsl:when>
1711            <!-- Manual override, normal direction -->
1712            <xsl:when test="tag[@k='name_direction']/@v='1' or tag[@k='osmarender:nameDirection']/@v='1'">normal</xsl:when>
1713            <!-- Automatic, reverse direction -->
1714            <xsl:when test="(key('nodeById',$way/nd[1]/@ref)/@lon &gt; key('nodeById',$way/nd[last()]/@ref)/@lon)">reverse</xsl:when>
1715            <!-- Automatic, normal direction -->
1716            <xsl:otherwise>normal</xsl:otherwise>
1717          </xsl:choose>
1718        </xsl:variable>
1719
1720        <xsl:variable name="wayPath">
1721          <xsl:choose>
1722            <!-- Normal -->
1723            <xsl:when test='$pathDirection="normal"'>
1724              <xsl:value-of select="concat('way_normal_',@id)"/>
1725            </xsl:when>
1726            <!-- Reverse -->
1727            <xsl:otherwise>
1728              <xsl:value-of select="concat('way_reverse_',@id)"/>
1729            </xsl:otherwise>
1730          </xsl:choose>
1731        </xsl:variable>
1732
1733        <xsl:call-template name="renderTextPath">
1734          <xsl:with-param name="instruction" select="$instruction"/>
1735          <xsl:with-param name="pathId" select="$wayPath"/>
1736          <xsl:with-param name="pathDirection" select="$pathDirection"/>
1737          <xsl:with-param name="text" select="$text"/>
1738        </xsl:call-template>
1739      </xsl:if>
1740    </xsl:if>
1741  </xsl:template>
1742
1743  <!-- Process extended form of text instruction -->
1744  <xsl:template match='text' mode='textFormat'>
1745    <xsl:param name='way'/>
1746
1747    <xsl:apply-templates mode='textFormat'>
1748      <xsl:with-param name='way' select='$way'/>
1749    </xsl:apply-templates>
1750  </xsl:template>
1751
1752
1753  <!-- Substitute a tag in a text instruction -->
1754  <xsl:template match='text/tag' mode='textFormat'>
1755    <xsl:param name='way'/>
1756
1757    <xsl:variable name='key' select='@k'/>
1758    <xsl:variable name='value'>
1759      <xsl:choose>
1760        <xsl:when test='$key="osm:user"'>
1761          <xsl:value-of select='$way/@user'/>
1762        </xsl:when>
1763        <xsl:when test='$key="osm:timestamp"'>
1764          <xsl:value-of select='$way/@timestamp'/>
1765        </xsl:when>
1766        <xsl:when test='$key="osm:id"'>
1767          <xsl:value-of select='$way/@id'/>
1768        </xsl:when>
1769        <xsl:otherwise>
1770          <xsl:value-of select='$way/tag[@k=$key]/@v'/>
1771        </xsl:otherwise>
1772      </xsl:choose>
1773    </xsl:variable>
1774    <xsl:choose>
1775      <xsl:when test='string($value)'>
1776        <xsl:value-of select='$value'/>
1777      </xsl:when>
1778      <xsl:otherwise>
1779        <xsl:value-of select='@default'/>
1780      </xsl:otherwise>
1781    </xsl:choose>
1782  </xsl:template>
1783
1784
1785
1786  <!-- Generate a way path for the current way element -->
1787  <xsl:template name="generateWayPaths">
1788    <!-- DODI: !!!WORKAROUND!!! skip one node ways -->
1789    <xsl:if test="count(nd) &gt; 1">
1790
1791      <!-- Generate a normal way path -->
1792      <xsl:variable name="pathWayNormal">
1793        <xsl:call-template name="generateWayPathNormal"/>
1794      </xsl:variable>
1795      <xsl:if test="$pathWayNormal!=''">
1796        <path id="way_normal_{@id}" d="{$pathWayNormal}"/>
1797      </xsl:if>
1798
1799      <!-- Generate a normal way path as area -->
1800      <!-- DODI: !!!WORKAROUND!!! added to generate "area for all ways, yes it is very dirty... but -->
1801      <!-- DODI: removed because of line2curves.pl duplicate node detection problem -->
1802      <!-- <xsl:variable name="pathArea">
1803      <xsl:call-template name="generateAreaPath"/>
1804    </xsl:variable>
1805    <path id="area_{@id}" d="{$pathArea}"/> -->
1806      <!-- Generate a reverse way path (if needed) -->
1807      <xsl:variable name="pathWayReverse">
1808        <xsl:choose>
1809          <!-- Manual override, reverse direction -->
1810          <xsl:when test="tag[@k='name_direction']/@v='-1' or tag[@k='osmarender:nameDirection']/@v='-1'">
1811            <xsl:call-template name="generateWayPathReverse"/>
1812          </xsl:when>
1813          <!-- Manual override, normal direction -->
1814          <xsl:when test="tag[@k='name_direction']/@v='1' or tag[@k='osmarender:nameDirection']/@v='1'">
1815            <!-- Generate nothing -->
1816          </xsl:when>
1817          <!-- Automatic, reverse direction -->
1818          <xsl:when test="(key('nodeById',nd[1]/@ref)/@lon &gt; key('nodeById',nd[last()]/@ref)/@lon)">
1819            <xsl:call-template name="generateWayPathReverse"/>
1820          </xsl:when>
1821        </xsl:choose>
1822      </xsl:variable>
1823      <xsl:if test="$pathWayReverse!=''">
1824        <path id="way_reverse_{@id}" d="{$pathWayReverse}"/>
1825      </xsl:if>
1826
1827      <!-- Generate the start, middle and end paths needed for smart-linecaps (TM). -->
1828      <xsl:variable name="pathWayStart">
1829        <xsl:call-template name="generatePathWayStart"/>
1830      </xsl:variable>
1831      <path id="way_start_{@id}" d="{$pathWayStart}"/>
1832
1833      <xsl:if test="count(nd) &gt; 1">
1834        <xsl:variable name="pathWayMid">
1835          <xsl:call-template name="generatePathWayMid"/>
1836        </xsl:variable>
1837        <path id="way_mid_{@id}" d="{$pathWayMid}"/>
1838      </xsl:if>
1839
1840      <xsl:variable name="pathWayEnd">
1841        <xsl:call-template name="generatePathWayEnd"/>
1842      </xsl:variable>
1843      <path id="way_end_{@id}" d="{$pathWayEnd}"/>
1844    </xsl:if >
1845  </xsl:template>
1846
1847
1848  <!-- Generate a normal way path -->
1849  <xsl:template name="generateWayPathNormal">
1850    <xsl:for-each select="nd[key('nodeById',@ref) ]">
1851      <xsl:choose>
1852        <xsl:when test="position()=1">
1853          <xsl:call-template name="moveToNode">
1854            <xsl:with-param name="node" select="key('nodeById',@ref)"/>
1855          </xsl:call-template>
1856        </xsl:when>
1857        <xsl:otherwise>
1858          <xsl:call-template name="lineToNode">
1859            <xsl:with-param name="node" select="key('nodeById',@ref)"/>
1860          </xsl:call-template>
1861        </xsl:otherwise>
1862      </xsl:choose>
1863    </xsl:for-each>
1864  </xsl:template>
1865
1866
1867  <!-- Generate a reverse way path -->
1868  <xsl:template name="generateWayPathReverse">
1869    <xsl:for-each select="nd[key('nodeById',@ref)]">
1870      <xsl:sort select="position()" data-type="number" order="descending"/>
1871      <xsl:choose>
1872        <xsl:when test="position()=1">
1873          <xsl:call-template name="moveToNode">
1874            <xsl:with-param name="node" select="key('nodeById',@ref)"/>
1875          </xsl:call-template>
1876        </xsl:when>
1877        <xsl:otherwise>
1878          <xsl:call-template name="lineToNode">
1879            <xsl:with-param name="node" select="key('nodeById',@ref)"/>
1880          </xsl:call-template>
1881        </xsl:otherwise>
1882      </xsl:choose>
1883    </xsl:for-each>
1884  </xsl:template>
1885
1886
1887  <!-- 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
1888         between the two paths is not at an angle.  -->
1889  <xsl:template name="generatePathWayStart">
1890    <xsl:call-template name="moveToNode">
1891      <xsl:with-param name="node" select="key('nodeById',nd[1]/@ref)"/>
1892    </xsl:call-template>
1893    <xsl:call-template name="lineToMidpointPlus">
1894      <xsl:with-param name="fromNode" select="key('nodeById',nd[1]/@ref)"/>
1895      <xsl:with-param name="toNode" select="key('nodeById',nd[2]/@ref)"/>
1896    </xsl:call-template>
1897  </xsl:template>
1898
1899
1900  <xsl:template name="generatePathWayEnd">
1901    <xsl:call-template name="moveToNode">
1902      <xsl:with-param name="node" select="key('nodeById',nd[position()=last()]/@ref)"/>
1903    </xsl:call-template>
1904    <xsl:call-template name="lineToMidpointMinus">
1905      <xsl:with-param name="fromNode" select="key('nodeById',nd[position()=(last()-1)]/@ref)"/>
1906      <xsl:with-param name="toNode" select="key('nodeById',nd[position()=last()]/@ref)"/>
1907    </xsl:call-template>
1908  </xsl:template>
1909
1910  <xsl:template name="generatePathWayMid">
1911    <xsl:for-each select="nd[key('nodeById',@ref)]">
1912      <xsl:choose>
1913        <xsl:when test="position()=1">
1914          <xsl:call-template name="moveToMidpointPlus">
1915            <xsl:with-param name="fromNode" select="key('nodeById',@ref)"/>
1916            <xsl:with-param name="toNode" select="key('nodeById',following-sibling::nd[1]/@ref)"/>
1917          </xsl:call-template>
1918        </xsl:when>
1919        <xsl:when test="position()=last()">
1920          <xsl:call-template name="lineToMidpointMinus">
1921            <xsl:with-param name="fromNode" select="key('nodeById',preceding-sibling::nd[1]/@ref)"/>
1922            <xsl:with-param name="toNode" select="key('nodeById',@ref)"/>
1923          </xsl:call-template>
1924        </xsl:when>
1925        <xsl:otherwise>
1926          <xsl:call-template name="lineToNode">
1927            <xsl:with-param name="node" select="key('nodeById',@ref)"/>
1928          </xsl:call-template>
1929        </xsl:otherwise>
1930      </xsl:choose>
1931    </xsl:for-each>
1932  </xsl:template>
1933
1934  <!-- Generate an area path for the current way or area element -->
1935  <xsl:template name="generateAreaPath">
1936    <xsl:variable name='relation' select="key('relationByWay',@id)[tag[@k='type' and @v='multipolygon']]"/>
1937    <xsl:choose>
1938      <xsl:when test='$relation'>
1939
1940        <!-- DODI: handling mulitpolygons: draw area only once
1941                   ways is a part of a multipolygon relation so we need process all members-->
1942        <xsl:variable name='firsrelationmember' select="$relation/member[@type='way'][key('wayById', @ref)][1]/@ref"/>
1943        <!-- DODI: if /me is a real first member, process all, otherwise skip it-->
1944        <xsl:if test='$firsrelationmember=@id'>
1945          <xsl:message>
1946            <xsl:value-of select='$relation/@id'/>
1947          </xsl:message>
1948          <xsl:for-each select="$relation/member[@type='way'][key('wayById', @ref)]">
1949            <xsl:call-template name='generateAreaSubPath'>
1950              <xsl:with-param name='way' select="key('wayById',@ref)"/>
1951              <xsl:with-param name='position' select="position()"/>
1952            </xsl:call-template>
1953          </xsl:for-each>
1954          <xsl:text>Z</xsl:text>
1955        </xsl:if>
1956
1957      </xsl:when>
1958      <xsl:otherwise>
1959        <xsl:call-template name='generateAreaSubPath'>
1960          <xsl:with-param name='way' select='.'/>
1961          <xsl:with-param name='position' select="'1'"/>
1962        </xsl:call-template>
1963        <xsl:text>Z</xsl:text>
1964      </xsl:otherwise>
1965    </xsl:choose>
1966  </xsl:template>
1967
1968
1969  <xsl:template name='generateAreaSubPath'>
1970    <xsl:param name='way'/>
1971    <xsl:param name='position'/>
1972
1973    <xsl:variable name='loop' select='$way/nd[1]/@ref=$way/nd[last()]/@ref'/>
1974    <xsl:message>
1975      WayId: <xsl:value-of select='$way/@id'/>
1976      Loop: <xsl:value-of select='$loop'/>
1977      Loop: <xsl:value-of select='$way/nd[1]/@ref'/>
1978      Loop: <xsl:value-of select='$way/nd[last()]/@ref'/>
1979    </xsl:message>
1980    <xsl:for-each select="$way/nd[key('nodeById',@ref)]">
1981      <xsl:choose>
1982        <xsl:when test="position()=1 and $loop">
1983          <xsl:if test='not($position=1)'>
1984            <xsl:text>Z</xsl:text>
1985          </xsl:if>
1986          <xsl:call-template name="moveToNode">
1987            <xsl:with-param name="node" select="key('nodeById',@ref)"/>
1988          </xsl:call-template>
1989        </xsl:when>
1990        <xsl:when test="$position=1 and position()=1 and not($loop=1)">
1991          <xsl:call-template name="moveToNode">
1992            <xsl:with-param name="node" select="key('nodeById',@ref)"/>
1993          </xsl:call-template>
1994        </xsl:when>
1995        <xsl:otherwise>
1996          <xsl:call-template name="lineToNode">
1997            <xsl:with-param name="node" select="key('nodeById',@ref)"/>
1998          </xsl:call-template>
1999        </xsl:otherwise>
2000      </xsl:choose>
2001    </xsl:for-each>
2002
2003
2004  </xsl:template>
2005
2006  <!-- Generate a MoveTo command for a node -->
2007  <xsl:template name="moveToNode">
2008    <xsl:param name='node' />
2009    <xsl:variable name="x1" select="($width)-((($topRightLongitude)-($node/@lon))*10000*$scale)"/>
2010    <xsl:variable name="y1" select="($height)+((($bottomLeftLatitude)-($node/@lat))*10000*$scale*$projection)"/>
2011    <xsl:text>M</xsl:text>
2012    <xsl:value-of select="$x1"/>
2013    <xsl:text> </xsl:text>
2014    <xsl:value-of select="$y1"/>
2015  </xsl:template>
2016
2017  <!-- Generate a LineTo command for a nd -->
2018  <xsl:template name="lineToNode">
2019    <xsl:param name='node'/>
2020
2021    <xsl:variable name="x1" select="($width)-((($topRightLongitude)-($node/@lon))*10000*$scale)"/>
2022    <xsl:variable name="y1" select="($height)+((($bottomLeftLatitude)-($node/@lat))*10000*$scale*$projection)"/>
2023    <xsl:text>L</xsl:text>
2024    <xsl:value-of select="$x1"/>
2025    <xsl:text> </xsl:text>
2026    <xsl:value-of select="$y1"/>
2027  </xsl:template>
2028
2029  <xsl:template name="lineToMidpointPlus">
2030    <xsl:param name='fromNode'/>
2031    <xsl:param name='toNode'/>
2032
2033    <xsl:variable name="x1" select="($width)-((($topRightLongitude)-($fromNode/@lon))*10000*$scale)"/>
2034    <xsl:variable name="y1" select="($height)+((($bottomLeftLatitude)-($fromNode/@lat))*10000*$scale*$projection)"/>
2035
2036    <xsl:variable name="x2" select="($width)-((($topRightLongitude)-($toNode/@lon))*10000*$scale)"/>
2037    <xsl:variable name="y2" select="($height)+((($bottomLeftLatitude)-($toNode/@lat))*10000*$scale*$projection)"/>
2038
2039    <xsl:text>L</xsl:text>
2040    <xsl:value-of select="$x1+(($x2 - $x1) div 1.9)"/>
2041    <xsl:text> </xsl:text>
2042    <xsl:value-of select="$y1+(($y2 - $y1) div 1.9)"/>
2043  </xsl:template>
2044
2045  <xsl:template name="lineToMidpointMinus">
2046    <xsl:param name='fromNode'/>
2047    <xsl:param name='toNode'/>
2048
2049    <xsl:variable name="x1" select="($width)-((($topRightLongitude)-($fromNode/@lon))*10000*$scale)"/>
2050    <xsl:variable name="y1" select="($height)+((($bottomLeftLatitude)-($fromNode/@lat))*10000*$scale*$projection)"/>
2051
2052    <xsl:variable name="x2" select="($width)-((($topRightLongitude)-($toNode/@lon))*10000*$scale)"/>
2053    <xsl:variable name="y2" select="($height)+((($bottomLeftLatitude)-($toNode/@lat))*10000*$scale*$projection)"/>
2054    <xsl:text>L</xsl:text>
2055    <xsl:value-of select="$x1+(($x2 - $x1) div 2.1)"/>
2056    <xsl:text> </xsl:text>
2057    <xsl:value-of select="$y1+(($y2 - $y1) div 2.1)"/>
2058  </xsl:template>
2059
2060
2061  <xsl:template name="moveToMidpointPlus">
2062    <xsl:param name='fromNode'/>
2063    <xsl:param name='toNode'/>
2064
2065    <xsl:variable name="x1" select="($width)-((($topRightLongitude)-($fromNode/@lon))*10000*$scale)"/>
2066    <xsl:variable name="y1" select="($height)+((($bottomLeftLatitude)-($fromNode/@lat))*10000*$scale*$projection)"/>
2067
2068    <xsl:variable name="x2" select="($width)-((($topRightLongitude)-($toNode/@lon))*10000*$scale)"/>
2069    <xsl:variable name="y2" select="($height)+((($bottomLeftLatitude)-($toNode/@lat))*10000*$scale*$projection)"/>
2070    <xsl:text>M</xsl:text>
2071    <xsl:value-of select="$x1+(($x2 - $x1) div 1.9)"/>
2072    <xsl:text> </xsl:text>
2073    <xsl:value-of select="$y1+(($y2 - $y1) div 1.9)"/>
2074  </xsl:template>
2075
2076  <!-- Some attribute shouldn't be copied -->
2077  <xsl:template match="@type|@ref|@scale|@smart-linecap" mode="copyAttributes" />
2078
2079  <!-- Copy all other attributes  -->
2080  <xsl:template match="@*" mode="copyAttributes">
2081    <xsl:copy/>
2082  </xsl:template>
2083
2084
2085  <!-- Rule processing engine -->
2086
2087  <!--
2088
2089                Calls all templates inside <rule> tags (including itself, if there are nested rules).
2090
2091                If the global var withOSMLayers is 'no', we don't care about layers and draw everything
2092                in one go. This is faster and is sometimes useful. For normal maps you want withOSMLayers
2093                to be 'yes', which is the default.
2094
2095        -->
2096  <xsl:template name="processRules">
2097
2098    <!-- First select all elements - exclude those marked as deleted by JOSM -->
2099    <xsl:variable name='elements' select="$data/osm/*[not(@action) or not(@action='delete')]" />
2100
2101    <xsl:choose>
2102
2103      <!-- Process all the rules, one layer at a time -->
2104      <xsl:when test="$withOSMLayers='yes'">
2105        <xsl:call-template name="processLayer">
2106          <xsl:with-param name="layer" select="'-5'"/>
2107          <xsl:with-param name="elements" select="$elements"/>
2108        </xsl:call-template>
2109        <xsl:call-template name="processLayer">
2110          <xsl:with-param name="layer" select="'-4'"/>
2111          <xsl:with-param name="elements" select="$elements"/>
2112        </xsl:call-template>
2113        <xsl:call-template name="processLayer">
2114          <xsl:with-param name="layer" select="'-3'"/>
2115          <xsl:with-param name="elements" select="$elements"/>
2116        </xsl:call-template>
2117        <xsl:call-template name="processLayer">
2118          <xsl:with-param name="layer" select="'-2'"/>
2119          <xsl:with-param name="elements" select="$elements"/>
2120        </xsl:call-template>
2121        <xsl:call-template name="processLayer">
2122          <xsl:with-param name="layer" select="'-1'"/>
2123          <xsl:with-param name="elements" select="$elements"/>
2124        </xsl:call-template>
2125        <xsl:call-template name="processLayer">
2126          <xsl:with-param name="layer" select="'0'"/>
2127          <xsl:with-param name="elements" select="$elements"/>
2128        </xsl:call-template>
2129        <xsl:call-template name="processLayer">
2130          <xsl:with-param name="layer" select="'1'"/>
2131          <xsl:with-param name="elements" select="$elements"/>
2132        </xsl:call-template>
2133        <xsl:call-template name="processLayer">
2134          <xsl:with-param name="layer" select="'2'"/>
2135          <xsl:with-param name="elements" select="$elements"/>
2136        </xsl:call-template>
2137        <xsl:call-template name="processLayer">
2138          <xsl:with-param name="layer" select="'3'"/>
2139          <xsl:with-param name="elements" select="$elements"/>
2140        </xsl:call-template>
2141        <xsl:call-template name="processLayer">
2142          <xsl:with-param name="layer" select="'4'"/>
2143          <xsl:with-param name="elements" select="$elements"/>
2144        </xsl:call-template>
2145        <xsl:call-template name="processLayer">
2146          <xsl:with-param name="layer" select="'5'"/>
2147          <xsl:with-param name="elements" select="$elements"/>
2148        </xsl:call-template>
2149      </xsl:when>
2150
2151      <!-- Process all the rules, without looking at the layers -->
2152      <xsl:otherwise>
2153        <xsl:apply-templates select="/rules/rule">
2154          <xsl:with-param name="elements" select="$elements"/>
2155          <xsl:with-param name="layer" select="'0'"/>
2156        </xsl:apply-templates>
2157      </xsl:otherwise>
2158
2159    </xsl:choose>
2160  </xsl:template>
2161
2162
2163  <xsl:template name="processLayer">
2164    <xsl:param name="layer"/>
2165    <xsl:param name="elements"/>
2166
2167    <g inkscape:groupmode="layer" id="layer{$layer}" inkscape:label="Layer {$layer}">
2168      <xsl:apply-templates select="/rules/rule">
2169        <xsl:with-param name="elements" select="$elements"/>
2170        <xsl:with-param name="layer" select="$layer"/>
2171      </xsl:apply-templates>
2172    </g>
2173  </xsl:template>
2174
2175
2176  <!-- Process a rule at a specific level -->
2177  <xsl:template match='rule'>
2178    <xsl:param name="elements"/>
2179    <xsl:param name="layer"/>
2180
2181    <!-- If the rule is for a specific layer and we are processing that layer then pass *all* elements
2182                     to the rule, otherwise just select the matching elements for this layer. -->
2183    <xsl:choose>
2184      <xsl:when test='$layer=@layer'>
2185        <xsl:call-template name="rule">
2186          <xsl:with-param name="elements" select="$elements"/>
2187          <xsl:with-param name="layer" select="$layer"/>
2188        </xsl:call-template>
2189      </xsl:when>
2190      <xsl:otherwise>
2191        <xsl:if test='not(@layer)'>
2192          <xsl:call-template name="rule">
2193            <xsl:with-param name="elements" select="$elements[
2194                                                        tag[@k='layer' and @v=$layer]
2195                                                        or ($layer='0' and count(tag[@k='layer'])=0)
2196                                                ]"/>
2197            <xsl:with-param name="layer" select="$layer"/>
2198          </xsl:call-template>
2199        </xsl:if>
2200      </xsl:otherwise>
2201    </xsl:choose>
2202  </xsl:template>
2203
2204
2205  <xsl:template name='rule'>
2206    <xsl:param name="elements"/>
2207    <xsl:param name="layer"/>
2208
2209    <!-- This is the rule currently being processed -->
2210    <xsl:variable name="rule" select="."/>
2211
2212    <!-- Make list of elements that this rule should be applied to -->
2213    <xsl:variable name="eBare">
2214      <xsl:choose>
2215        <xsl:when test="$rule/@e='*'">node|way</xsl:when>
2216        <xsl:when test="$rule/@e">
2217          <xsl:value-of select="$rule/@e"/>
2218        </xsl:when>
2219        <xsl:otherwise>node|way</xsl:otherwise>
2220      </xsl:choose>
2221    </xsl:variable>
2222
2223    <!-- List of keys that this rule should be applied to -->
2224    <xsl:variable name="kBare" select="$rule/@k"/>
2225
2226    <!-- List of values that this rule should be applied to -->
2227    <xsl:variable name="vBare" select="$rule/@v"/>
2228    <xsl:variable name="sBare" select="$rule/@s"/>
2229
2230    <!-- Top'n'tail selectors with | for contains usage -->
2231    <xsl:variable name="e">
2232      |<xsl:value-of select="$eBare"/>|
2233    </xsl:variable>
2234    <xsl:variable name="k">
2235      |<xsl:value-of select="$kBare"/>|
2236    </xsl:variable>
2237    <xsl:variable name="v">
2238      |<xsl:value-of select="$vBare"/>|
2239    </xsl:variable>
2240    <xsl:variable name="s">
2241      |<xsl:value-of select="$sBare"/>|
2242    </xsl:variable>
2243
2244    <xsl:variable
2245      name="selectedElements"
2246      select="$elements[contains($e,concat('|',name(),'|'))
2247            or
2248            (contains($e,'|node|') and name()='way' and key('wayByNode',@id))
2249            ]"/>
2250
2251
2252    <!-- Patch $s -->
2253    <xsl:choose>
2254      <!-- way selector -->
2255      <xsl:when test="contains($s,'|way|')">
2256        <xsl:choose>
2257          <!-- every key -->
2258          <xsl:when test="contains($k,'|*|')">
2259            <xsl:choose>
2260              <!-- every key ,no value defined -->
2261              <xsl:when test="contains($v,'|~|')">
2262                <xsl:variable name="elementsWithNoTags" select="$selectedElements[count(key('wayByNode',@id)/tag)=0]"/>
2263                <xsl:call-template name="processElements">
2264                  <xsl:with-param name="eBare" select="$eBare"/>
2265                  <xsl:with-param name="kBare" select="$kBare"/>
2266                  <xsl:with-param name="vBare" select="$vBare"/>
2267                  <xsl:with-param name="layer" select="$layer"/>
2268                  <xsl:with-param name="elements" select="$elementsWithNoTags"/>
2269                  <xsl:with-param name="rule" select="$rule"/>
2270                </xsl:call-template>
2271              </xsl:when>
2272              <!-- every key ,every value -->
2273              <xsl:when test="contains($v,'|*|')">
2274                <xsl:variable name="allElements" select="$selectedElements"/>
2275                <xsl:call-template name="processElements">
2276                  <xsl:with-param name="eBare" select="$eBare"/>
2277                  <xsl:with-param name="kBare" select="$kBare"/>
2278                  <xsl:with-param name="vBare" select="$vBare"/>
2279                  <xsl:with-param name="layer" select="$layer"/>
2280                  <xsl:with-param name="elements" select="$allElements"/>
2281                  <xsl:with-param name="rule" select="$rule"/>
2282                </xsl:call-template>
2283              </xsl:when>
2284              <!-- every key , selected values -->
2285              <xsl:otherwise>
2286                <xsl:variable name="allElementsWithValue" select="$selectedElements[key('wayByNode',@id)/tag[contains($v,concat('|',@v,'|'))]]"/>
2287                <xsl:call-template name="processElements">
2288                  <xsl:with-param name="eBare" select="$eBare"/>
2289                  <xsl:with-param name="kBare" select="$kBare"/>
2290                  <xsl:with-param name="vBare" select="$vBare"/>
2291                  <xsl:with-param name="layer" select="$layer"/>
2292                  <xsl:with-param name="elements" select="$allElementsWithValue"/>
2293                  <xsl:with-param name="rule" select="$rule"/>
2294                </xsl:call-template>
2295              </xsl:otherwise>
2296            </xsl:choose>
2297          </xsl:when>
2298          <!-- no value  -->
2299          <xsl:when test="contains($v,'|~|')">
2300            <xsl:variable name="elementsWithoutKey" select="$selectedElements[count(key('wayByNode',@id)/tag[contains($k,concat('|',@k,'|'))])=0]"/>
2301            <xsl:call-template name="processElements">
2302              <xsl:with-param name="eBare" select="$eBare"/>
2303              <xsl:with-param name="kBare" select="$kBare"/>
2304              <xsl:with-param name="vBare" select="$vBare"/>
2305              <xsl:with-param name="layer" select="$layer"/>
2306              <xsl:with-param name="elements" select="$elementsWithoutKey"/>
2307              <xsl:with-param name="rule" select="$rule"/>
2308            </xsl:call-template>
2309          </xsl:when>
2310          <!-- every value  -->
2311          <xsl:when test="contains($v,'|*|')">
2312            <xsl:variable name="allElementsWithKey" select="$selectedElements[key('wayByNode',@id)/tag[contains($k,concat('|',@k,'|'))]]"/>
2313            <xsl:call-template name="processElements">
2314              <xsl:with-param name="eBare" select="$eBare"/>
2315              <xsl:with-param name="kBare" select="$kBare"/>
2316              <xsl:with-param name="vBare" select="$vBare"/>
2317              <xsl:with-param name="layer" select="$layer"/>
2318              <xsl:with-param name="elements" select="$allElementsWithKey"/>
2319              <xsl:with-param name="rule" select="$rule"/>
2320            </xsl:call-template>
2321          </xsl:when>
2322
2323          <!-- defined key and defined value -->
2324          <xsl:otherwise>
2325            <xsl:variable name="elementsWithKey" select="$selectedElements[
2326                                                        key('wayByNode',@id)/tag[
2327                                                                contains($k,concat('|',@k,'|')) and contains($v,concat('|',@v,'|'))
2328                                                                ]
2329                                                        ]"/>
2330            <xsl:call-template name="processElements">
2331              <xsl:with-param name="eBare" select="$eBare"/>
2332              <xsl:with-param name="kBare" select="$kBare"/>
2333              <xsl:with-param name="vBare" select="$vBare"/>
2334              <xsl:with-param name="layer" select="$layer"/>
2335              <xsl:with-param name="elements" select="$elementsWithKey"/>
2336              <xsl:with-param name="rule" select="$rule"/>
2337            </xsl:call-template>
2338          </xsl:otherwise>
2339        </xsl:choose>
2340      </xsl:when>
2341
2342      <!-- other selector -->
2343      <xsl:otherwise>
2344        <xsl:choose>
2345          <xsl:when test="contains($k,'|*|')">
2346            <xsl:choose>
2347              <xsl:when test="contains($v,'|~|')">
2348                <xsl:variable name="elementsWithNoTags" select="$selectedElements[count(tag)=0]"/>
2349                <xsl:call-template name="processElements">
2350                  <xsl:with-param name="eBare" select="$eBare"/>
2351                  <xsl:with-param name="kBare" select="$kBare"/>
2352                  <xsl:with-param name="vBare" select="$vBare"/>
2353                  <xsl:with-param name="layer" select="$layer"/>
2354                  <xsl:with-param name="elements" select="$elementsWithNoTags"/>
2355                  <xsl:with-param name="rule" select="$rule"/>
2356                </xsl:call-template>
2357              </xsl:when>
2358              <xsl:when test="contains($v,'|*|')">
2359                <xsl:variable name="allElements" select="$selectedElements"/>
2360                <xsl:call-template name="processElements">
2361                  <xsl:with-param name="eBare" select="$eBare"/>
2362                  <xsl:with-param name="kBare" select="$kBare"/>
2363                  <xsl:with-param name="vBare" select="$vBare"/>
2364                  <xsl:with-param name="layer" select="$layer"/>
2365                  <xsl:with-param name="elements" select="$allElements"/>
2366                  <xsl:with-param name="rule" select="$rule"/>
2367                </xsl:call-template>
2368              </xsl:when>
2369              <xsl:otherwise>
2370                <xsl:variable name="allElementsWithValue" select="$selectedElements[tag[contains($v,concat('|',@v,'|'))]]"/>
2371                <xsl:call-template name="processElements">
2372                  <xsl:with-param name="eBare" select="$eBare"/>
2373                  <xsl:with-param name="kBare" select="$kBare"/>
2374                  <xsl:with-param name="vBare" select="$vBare"/>
2375                  <xsl:with-param name="layer" select="$layer"/>
2376                  <xsl:with-param name="elements" select="$allElementsWithValue"/>
2377                  <xsl:with-param name="rule" select="$rule"/>
2378                </xsl:call-template>
2379              </xsl:otherwise>
2380            </xsl:choose>
2381          </xsl:when>
2382          <xsl:when test="contains($v,'|~|')">
2383            <xsl:variable name="elementsWithoutKey" select="$selectedElements[count(tag[contains($k,concat('|',@k,'|'))])=0]"/>
2384            <xsl:call-template name="processElements">
2385              <xsl:with-param name="eBare" select="$eBare"/>
2386              <xsl:with-param name="kBare" select="$kBare"/>
2387              <xsl:with-param name="vBare" select="$vBare"/>
2388              <xsl:with-param name="layer" select="$layer"/>
2389              <xsl:with-param name="elements" select="$elementsWithoutKey"/>
2390              <xsl:with-param name="rule" select="$rule"/>
2391            </xsl:call-template>
2392          </xsl:when>
2393          <xsl:when test="contains($v,'|*|')">
2394            <xsl:variable name="allElementsWithKey" select="$selectedElements[tag[contains($k,concat('|',@k,'|'))]]"/>
2395            <xsl:call-template name="processElements">
2396              <xsl:with-param name="eBare" select="$eBare"/>
2397              <xsl:with-param name="kBare" select="$kBare"/>
2398              <xsl:with-param name="vBare" select="$vBare"/>
2399              <xsl:with-param name="layer" select="$layer"/>
2400              <xsl:with-param name="elements" select="$allElementsWithKey"/>
2401              <xsl:with-param name="rule" select="$rule"/>
2402            </xsl:call-template>
2403          </xsl:when>
2404          <xsl:otherwise>
2405            <xsl:variable name="elementsWithKey" select="$selectedElements[tag[contains($k,concat('|',@k,'|')) and contains($v,concat('|',@v,'|'))]]"/>
2406            <xsl:call-template name="processElements">
2407              <xsl:with-param name="eBare" select="$eBare"/>
2408              <xsl:with-param name="kBare" select="$kBare"/>
2409              <xsl:with-param name="vBare" select="$vBare"/>
2410              <xsl:with-param name="layer" select="$layer"/>
2411              <xsl:with-param name="elements" select="$elementsWithKey"/>
2412              <xsl:with-param name="rule" select="$rule"/>
2413            </xsl:call-template>
2414          </xsl:otherwise>
2415        </xsl:choose>
2416      </xsl:otherwise>
2417    </xsl:choose>
2418  </xsl:template>
2419
2420
2421  <xsl:template match="else">
2422    <xsl:param name="elements"/>
2423    <xsl:param name="layer"/>
2424
2425    <!-- This is the previous rule that is being negated -->
2426    <!-- TODO: abort if no preceding rule element -->
2427    <xsl:variable name="rule" select="preceding-sibling::rule[1]"/>
2428
2429    <!-- Make list of elements that this rule should be applied to -->
2430    <xsl:variable name="eBare">
2431      <xsl:choose>
2432        <xsl:when test="$rule/@e='*'">node|way</xsl:when>
2433        <xsl:when test="$rule/@e">
2434          <xsl:value-of select="$rule/@e"/>
2435        </xsl:when>
2436        <xsl:otherwise>node|way</xsl:otherwise>
2437      </xsl:choose>
2438    </xsl:variable>
2439
2440    <!-- List of keys that this rule should be applied to -->
2441    <xsl:variable name="kBare" select="$rule/@k"/>
2442
2443    <!-- List of values that this rule should be applied to -->
2444    <xsl:variable name="vBare" select="$rule/@v"/>
2445    <xsl:variable name="sBare" select="$rule/@s"/>
2446
2447
2448    <!-- Top'n'tail selectors with | for contains usage -->
2449    <xsl:variable name="e">
2450      |<xsl:value-of select="$eBare"/>|
2451    </xsl:variable>
2452    <xsl:variable name="k">
2453      |<xsl:value-of select="$kBare"/>|
2454    </xsl:variable>
2455    <xsl:variable name="v">
2456      |<xsl:value-of select="$vBare"/>|
2457    </xsl:variable>
2458    <xsl:variable name="s">
2459      |<xsl:value-of select="$sBare"/>|
2460    </xsl:variable>
2461
2462    <xsl:variable
2463      name="selectedElements"
2464      select="$elements[contains($e,concat('|',name(),'|'))
2465              or
2466              (contains($e,'|node|') and name()='way'and key('wayByNode',@id))
2467              ]"/>
2468
2469    <!-- Patch $s -->
2470    <xsl:choose>
2471      <xsl:when test="contains($s,'|way|')">
2472        <xsl:choose>
2473          <xsl:when test="contains($k,'|*|')">
2474            <xsl:choose>
2475              <xsl:when test="contains($v,'|~|')">
2476                <xsl:variable name="elementsWithNoTags" select="$selectedElements[count(key('wayByNode',@id)/tag)!=0]"/>
2477                <xsl:call-template name="processElements">
2478                  <xsl:with-param name="eBare" select="$eBare"/>
2479                  <xsl:with-param name="kBare" select="$kBare"/>
2480                  <xsl:with-param name="vBare" select="$vBare"/>
2481                  <xsl:with-param name="layer" select="$layer"/>
2482                  <xsl:with-param name="elements" select="$elementsWithNoTags"/>
2483                  <xsl:with-param name="rule" select="$rule"/>
2484                </xsl:call-template>
2485              </xsl:when>
2486              <xsl:when test="contains($v,'|*|')">
2487                <!-- no-op! -->
2488              </xsl:when>
2489              <xsl:otherwise>
2490                <xsl:variable name="allElementsWithValue" select="$selectedElements[not(key('wayByNode',@id)/tag[contains($v,concat('|',@v,'|'))])]"/>
2491                <xsl:call-template name="processElements">
2492                  <xsl:with-param name="eBare" select="$eBare"/>
2493                  <xsl:with-param name="kBare" select="$kBare"/>
2494                  <xsl:with-param name="vBare" select="$vBare"/>
2495                  <xsl:with-param name="layer" select="$layer"/>
2496                  <xsl:with-param name="elements" select="$allElementsWithValue"/>
2497                  <xsl:with-param name="rule" select="$rule"/>
2498                </xsl:call-template>
2499              </xsl:otherwise>
2500            </xsl:choose>
2501          </xsl:when>
2502          <xsl:when test="contains($v,'|~|')">
2503            <xsl:variable name="elementsWithoutKey" select="$selectedElements[count(key('wayByNode',@id)/tag[contains($k,concat('|',@k,'|'))])!=0]"/>
2504            <xsl:call-template name="processElements">
2505              <xsl:with-param name="eBare" select="$eBare"/>
2506              <xsl:with-param name="kBare" select="$kBare"/>
2507              <xsl:with-param name="vBare" select="$vBare"/>
2508              <xsl:with-param name="layer" select="$layer"/>
2509              <xsl:with-param name="elements" select="$elementsWithoutKey"/>
2510              <xsl:with-param name="rule" select="$rule"/>
2511            </xsl:call-template>
2512          </xsl:when>
2513          <xsl:when test="contains($v,'|*|')">
2514            <xsl:variable name="allElementsWithKey" select="$selectedElements[not(key('wayByNode',@id)/tag[contains($k,concat('|',@k,'|'))])]"/>
2515            <xsl:call-template name="processElements">
2516              <xsl:with-param name="eBare" select="$eBare"/>
2517              <xsl:with-param name="kBare" select="$kBare"/>
2518              <xsl:with-param name="vBare" select="$vBare"/>
2519              <xsl:with-param name="layer" select="$layer"/>
2520              <xsl:with-param name="elements" select="$allElementsWithKey"/>
2521              <xsl:with-param name="rule" select="$rule"/>
2522            </xsl:call-template>
2523          </xsl:when>
2524          <xsl:otherwise>
2525            <xsl:variable name="elementsWithKey" select="$selectedElements[not(
2526                         key('wayByNode',@id)/tag[
2527                            contains($k,concat('|',@k,'|')) and contains($v,concat('|',@v,'|'))
2528                            ]
2529                         )]"/>
2530            <xsl:call-template name="processElements">
2531              <xsl:with-param name="eBare" select="$eBare"/>
2532              <xsl:with-param name="kBare" select="$kBare"/>
2533              <xsl:with-param name="vBare" select="$vBare"/>
2534              <xsl:with-param name="layer" select="$layer"/>
2535              <xsl:with-param name="elements" select="$elementsWithKey"/>
2536              <xsl:with-param name="rule" select="$rule"/>
2537            </xsl:call-template>
2538          </xsl:otherwise>
2539        </xsl:choose>
2540      </xsl:when>
2541
2542      <xsl:otherwise>
2543        <!-- not contains $s -->
2544        <xsl:choose>
2545          <xsl:when test="contains($k,'|*|')">
2546            <xsl:choose>
2547              <xsl:when test="contains($v,'|~|')">
2548                <xsl:variable name="elementsWithNoTags" select="$selectedElements[count(tag)!=0]"/>
2549                <xsl:call-template name="processElements">
2550                  <xsl:with-param name="eBare" select="$eBare"/>
2551                  <xsl:with-param name="kBare" select="$kBare"/>
2552                  <xsl:with-param name="vBare" select="$vBare"/>
2553                  <xsl:with-param name="layer" select="$layer"/>
2554                  <xsl:with-param name="elements" select="$elementsWithNoTags"/>
2555                  <xsl:with-param name="rule" select="$rule"/>
2556                </xsl:call-template>
2557              </xsl:when>
2558              <xsl:when test="contains($v,'|*|')">
2559                <!-- no-op! -->
2560              </xsl:when>
2561              <xsl:otherwise>
2562                <xsl:variable name="allElementsWithValue" select="$selectedElements[not(tag[contains($v,concat('|',@v,'|'))])]"/>
2563                <xsl:call-template name="processElements">
2564                  <xsl:with-param name="eBare" select="$eBare"/>
2565                  <xsl:with-param name="kBare" select="$kBare"/>
2566                  <xsl:with-param name="vBare" select="$vBare"/>
2567                  <xsl:with-param name="layer" select="$layer"/>
2568                  <xsl:with-param name="elements" select="$allElementsWithValue"/>
2569                  <xsl:with-param name="rule" select="$rule"/>
2570                </xsl:call-template>
2571              </xsl:otherwise>
2572            </xsl:choose>
2573          </xsl:when>
2574          <xsl:when test="contains($v,'|~|')">
2575            <xsl:variable name="elementsWithoutKey" select="$selectedElements[count(tag[contains($k,concat('|',@k,'|'))])!=0]"/>
2576            <xsl:call-template name="processElements">
2577              <xsl:with-param name="eBare" select="$eBare"/>
2578              <xsl:with-param name="kBare" select="$kBare"/>
2579              <xsl:with-param name="vBare" select="$vBare"/>
2580              <xsl:with-param name="layer" select="$layer"/>
2581              <xsl:with-param name="elements" select="$elementsWithoutKey"/>
2582              <xsl:with-param name="rule" select="$rule"/>
2583            </xsl:call-template>
2584          </xsl:when>
2585          <xsl:when test="contains($v,'|*|')">
2586            <xsl:variable name="allElementsWithKey" select="$selectedElements[not(tag[contains($k,concat('|',@k,'|'))])]"/>
2587            <xsl:call-template name="processElements">
2588              <xsl:with-param name="eBare" select="$eBare"/>
2589              <xsl:with-param name="kBare" select="$kBare"/>
2590              <xsl:with-param name="vBare" select="$vBare"/>
2591              <xsl:with-param name="layer" select="$layer"/>
2592              <xsl:with-param name="elements" select="$allElementsWithKey"/>
2593              <xsl:with-param name="rule" select="$rule"/>
2594            </xsl:call-template>
2595          </xsl:when>
2596          <xsl:otherwise>
2597            <xsl:variable name="elementsWithKey" select="$selectedElements[not(tag[contains($k,concat('|',@k,'|')) and contains($v,concat('|',@v,'|'))])]"/>
2598            <xsl:call-template name="processElements">
2599              <xsl:with-param name="eBare" select="$eBare"/>
2600              <xsl:with-param name="kBare" select="$kBare"/>
2601              <xsl:with-param name="vBare" select="$vBare"/>
2602              <xsl:with-param name="layer" select="$layer"/>
2603              <xsl:with-param name="elements" select="$elementsWithKey"/>
2604              <xsl:with-param name="rule" select="$rule"/>
2605            </xsl:call-template>
2606          </xsl:otherwise>
2607        </xsl:choose>
2608      </xsl:otherwise>
2609    </xsl:choose>
2610  </xsl:template>
2611
2612
2613  <xsl:template name="processElements">
2614    <xsl:param name="eBare"/>
2615    <xsl:param name="kBare"/>
2616    <xsl:param name="vBare"/>
2617    <xsl:param name="layer"/>
2618    <xsl:param name="elements"/>
2619    <xsl:param name="rule"/>
2620
2621
2622    <xsl:if test="$elements">
2623 
2624      <!-- elementCount is the number of elements we started with (just used for the progress message) -->
2625      <xsl:variable name="elementCount" select="count($elements)"/>
2626      <!-- If there's a proximity attribute on the rule then filter elements based on proximity -->
2627      <xsl:choose>
2628        <xsl:when test='$rule/@verticalProximity'>
2629          <xsl:variable name='nearbyElements1'>
2630            <xsl:call-template name="proximityFilter">
2631              <xsl:with-param name="elements" select="$elements"/>
2632              <xsl:with-param name="horizontalProximity" select="$rule/@horizontalProximity div 32"/>
2633              <xsl:with-param name="verticalProximity" select="$rule/@verticalProximity div 32"/>
2634            </xsl:call-template>
2635          </xsl:variable>
2636          <xsl:variable name='nearbyElements2'>
2637            <xsl:call-template name="proximityFilter">
2638              <xsl:with-param name="elements" select="exslt:node-set($nearbyElements1)/*"/>
2639              <xsl:with-param name="horizontalProximity" select="$rule/@horizontalProximity div 16"/>
2640              <xsl:with-param name="verticalProximity" select="$rule/@verticalProximity div 16"/>
2641            </xsl:call-template>
2642          </xsl:variable>
2643          <xsl:variable name='nearbyElements3'>
2644            <xsl:call-template name="proximityFilter">
2645              <xsl:with-param name="elements" select="exslt:node-set($nearbyElements2)/*"/>
2646              <xsl:with-param name="horizontalProximity" select="$rule/@horizontalProximity div 8"/>
2647              <xsl:with-param name="verticalProximity" select="$rule/@verticalProximity div 8"/>
2648            </xsl:call-template>
2649          </xsl:variable>
2650          <xsl:variable name='nearbyElements4'>
2651            <xsl:call-template name="proximityFilter">
2652              <xsl:with-param name="elements" select="exslt:node-set($nearbyElements3)/*"/>
2653              <xsl:with-param name="horizontalProximity" select="$rule/@horizontalProximity div 4"/>
2654              <xsl:with-param name="verticalProximity" select="$rule/@verticalProximity div 4"/>
2655            </xsl:call-template>
2656          </xsl:variable>
2657          <xsl:variable name='nearbyElements5'>
2658            <xsl:call-template name="proximityFilter">
2659              <xsl:with-param name="elements" select="exslt:node-set($nearbyElements4)/*"/>
2660              <xsl:with-param name="horizontalProximity" select="$rule/@horizontalProximity div 2"/>
2661              <xsl:with-param name="verticalProximity" select="$rule/@verticalProximity div 2"/>
2662            </xsl:call-template>
2663          </xsl:variable>
2664          <xsl:variable name='nearbyElementsRtf'>
2665            <xsl:call-template name="proximityFilter">
2666              <xsl:with-param name="elements" select="exslt:node-set($nearbyElements5)/*"/>
2667              <xsl:with-param name="horizontalProximity" select="$rule/@horizontalProximity"/>
2668              <xsl:with-param name="verticalProximity" select="$rule/@verticalProximity"/>
2669            </xsl:call-template>
2670          </xsl:variable>
2671
2672          <!-- Convert nearbyElements rtf to a node-set -->
2673          <xsl:variable name="nearbyElements" select="exslt:node-set($nearbyElementsRtf)/*"/>
2674
2675          <xsl:message>
2676            Processing &lt;rule e="<xsl:value-of select="$eBare"/>" k="<xsl:value-of select="$kBare"/>" v="<xsl:value-of select="$vBare"/>"
2677                        horizontalProximity="<xsl:value-of select="$rule/@horizontalProximity"/>" verticalProximity="<xsl:value-of select="$rule/@verticalProximity"/>" &gt;
2678            Matched by <xsl:value-of select="count($nearbyElements)"/> out of <xsl:value-of select="count($elements)"/> elements for layer <xsl:value-of select="$layer"/>.
2679          </xsl:message>
2680
2681          <xsl:apply-templates select="*">
2682            <xsl:with-param name="layer" select="$layer"/>
2683            <xsl:with-param name="elements" select="$nearbyElements"/>
2684            <xsl:with-param name="rule" select="$rule"/>
2685          </xsl:apply-templates>
2686        </xsl:when>
2687        <xsl:otherwise>
2688
2689          <xsl:message>
2690            Processing &lt;rule e="<xsl:value-of select="$eBare"/>" k="<xsl:value-of select="$kBare"/>" v="<xsl:value-of select="$vBare"/>" &gt;
2691            Matched by <xsl:value-of select="count($elements)"/> elements for layer <xsl:value-of select="$layer"/>.
2692          </xsl:message>
2693
2694          <xsl:apply-templates select="*">
2695            <xsl:with-param name="layer" select="$layer"/>
2696            <xsl:with-param name="elements" select="$elements"/>
2697            <xsl:with-param name="rule" select="$rule"/>
2698          </xsl:apply-templates>
2699        </xsl:otherwise>
2700      </xsl:choose>
2701    </xsl:if>
2702  </xsl:template>
2703
2704
2705  <!-- Select elements that are not within the specified distance from any other element -->
2706  <xsl:template name="proximityFilter">
2707    <xsl:param name="elements"/>
2708    <xsl:param name="horizontalProximity"/>
2709    <xsl:param name="verticalProximity"/>
2710   
2711    <!-- Offsetting the rectangle to the right gives better results when there are a solitary pair of adjacent elements. 
2712         One will get selected but the other won't.  Without the offset neither will get selected.  -->
2713    <xsl:variable name="topOffset" select="90  + $verticalProximity"/>
2714    <xsl:variable name="bottomOffset" select="90  - $verticalProximity"/>
2715    <xsl:variable name="leftOffset" select="180 - ($horizontalProximity * 0.5)"/>
2716    <xsl:variable name="rightOffset" select="180 + ($horizontalProximity * 1.5)"/>
2717
2718    <!-- Test each element to see if it is near any other element -->
2719    <xsl:for-each select="$elements">
2720      <xsl:variable name="id" select="@id"/>
2721      <xsl:variable name="top"    select="@lat + $topOffset"/>
2722      <xsl:variable name="bottom" select="@lat + $bottomOffset"/>
2723      <xsl:variable name="left"   select="@lon + $leftOffset"/>
2724      <xsl:variable name="right"  select="@lon + $rightOffset"/>
2725      <!-- Iterate through all of the elements currently selected and if there are no elements other
2726           than the current element in the rectangle then select this element -->
2727      <xsl:if test="not($elements[not(@id=$id)
2728                                  and (@lon+180) &lt; $right
2729                                  and (@lon+180) &gt; $left
2730                                  and (@lat+90)  &lt; $top
2731                                  and (@lat+90)  &gt; $bottom
2732                                  ]
2733                        )">
2734        <xsl:copy-of select="."/>
2735      </xsl:if>
2736    </xsl:for-each>
2737  </xsl:template>
2738
2739
2740  <!-- Draw SVG layers -->
2741  <xsl:template match="layer">
2742    <xsl:param name="elements"/>
2743    <xsl:param name="layer"/>
2744    <xsl:param name="rule"/>
2745
2746    <xsl:message>
2747      Processing SVG layer: <xsl:value-of select="@name"/> (at OSM layer <xsl:value-of select="$layer"/>)
2748    </xsl:message>
2749
2750    <xsl:variable name="opacity">
2751      <xsl:if test="@opacity">
2752        <xsl:value-of select="concat('opacity:',@opacity,';')"/>
2753      </xsl:if>
2754    </xsl:variable>
2755
2756    <xsl:variable name="display">
2757      <xsl:if test="(@display='none') or (@display='off')">
2758        <xsl:text>display:none;</xsl:text>
2759      </xsl:if>
2760    </xsl:variable>
2761
2762    <g inkscape:groupmode="layer" id="{@name}-{$layer}" inkscape:label="{@name}">
2763      <xsl:if test="concat($opacity,$display)!=''">
2764        <xsl:attribute name="style">
2765          <xsl:value-of select="concat($opacity,$display)"/>
2766        </xsl:attribute>
2767      </xsl:if>
2768      <xsl:apply-templates select="*">
2769        <xsl:with-param name="layer" select="$layer"/>
2770        <xsl:with-param name="elements" select="$elements"/>
2771      </xsl:apply-templates>
2772    </g>
2773
2774  </xsl:template>
2775
2776
2777  <!-- Draw map border -->
2778  <xsl:template name="drawBorder">
2779    <!-- dasharray definitions here can be overridden in stylesheet -->
2780    <g id="border" inkscape:groupmode="layer" inkscape:label="Map Border">
2781      <line id="border-left-casing" x1="0" y1="0" x2="0" y2="{$documentHeight}" class="map-border-casing" stroke-dasharray="{($km div 10) - 1},1"/>
2782      <line id="border-top-casing" x1="0" y1="0" x2="{$documentWidth}" y2="0" class="map-border-casing" stroke-dasharray="{($km div 10) - 1},1"/>
2783      <line id="border-bottom-casing" x1="0" y1="{$documentHeight}" x2="{$documentWidth}" y2="{$documentHeight}" class="map-border-casing" stroke-dasharray="{($km div 10) - 1},1"/>
2784      <line id="border-right-casing" x1="{$documentWidth}" y1="0" x2="{$documentWidth}" y2="{$documentHeight}" class="map-border-casing" stroke-dasharray="{($km div 10) - 1},1"/>
2785
2786      <line id="border-left-core" x1="0" y1="0" x2="0" y2="{$documentHeight}" class="map-border-core" stroke-dasharray="{($km div 10) - 1},1"/>
2787      <line id="border-top-core" x1="0" y1="0" x2="{$documentWidth}" y2="0" class="map-border-core" stroke-dasharray="{($km div 10) - 1},1"/>
2788      <line id="border-bottom-core" x1="0" y1="{$documentHeight}" x2="{$documentWidth}" y2="{$documentHeight}" class="map-border-core" stroke-dasharray="{($km div 10) - 1},1"/>
2789      <line id="border-right-core" x1="{$documentWidth}" y1="0" x2="{$documentWidth}" y2="{$documentHeight}" class="map-border-core" stroke-dasharray="{($km div 10) - 1},1"/>
2790    </g>
2791  </xsl:template>
2792
2793
2794  <!-- Draw a grid over the map in 1km increments -->
2795  <xsl:template name="drawGrid">
2796    <g id="grid" inkscape:groupmode="layer" inkscape:label="Grid">
2797      <xsl:call-template name="drawGridHorizontals">
2798        <xsl:with-param name="line" select="'1'"/>
2799      </xsl:call-template>
2800      <xsl:call-template name="drawGridVerticals">
2801        <xsl:with-param name="line" select="'1'"/>
2802      </xsl:call-template>
2803    </g>
2804  </xsl:template>
2805
2806
2807  <xsl:template name="drawGridHorizontals">
2808    <xsl:param name="line"/>
2809    <xsl:if test="($line*$km) &lt; $documentHeight">
2810      <line id="grid-hori-{$line}" x1="0px" y1="{$line*$km}px" x2="{$documentWidth}px" y2="{$line*$km}px" class="map-grid-line"/>
2811      <xsl:call-template name="drawGridHorizontals">
2812        <xsl:with-param name="line" select="$line+1"/>
2813      </xsl:call-template>
2814    </xsl:if>
2815  </xsl:template>
2816
2817
2818  <xsl:template name="drawGridVerticals">
2819    <xsl:param name="line"/>
2820    <xsl:if test="($line*$km) &lt; $documentWidth">
2821      <line id="grid-vert-{$line}" x1="{$line*$km}px" y1="0px" x2="{$line*$km}px" y2="{$documentHeight}px" class="map-grid-line"/>
2822      <xsl:call-template name="drawGridVerticals">
2823        <xsl:with-param name="line" select="$line+1"/>
2824      </xsl:call-template>
2825    </xsl:if>
2826  </xsl:template>
2827
2828
2829  <!-- Draw map title -->
2830  <xsl:template name="drawTitle">
2831    <xsl:param name="title"/>
2832
2833    <xsl:variable name="x" select="$documentWidth div 2"/>
2834    <xsl:variable name="y" select="30"/>
2835
2836    <g id="marginalia-title" inkscape:groupmode="layer" inkscape:label="Title">
2837      <rect id="marginalia-title-background" x="0px" y="0px" height="{$marginaliaTopHeight - 5}px" width="{$documentWidth}px" class="map-title-background"/>
2838      <text id="marginalia-title-text" class="map-title" x="{$x}" y="{$y}">
2839        <xsl:value-of select="$title"/>
2840      </text>
2841    </g>
2842  </xsl:template>
2843
2844
2845  <!-- Draw an approximate scale in the bottom left corner of the map -->
2846  <xsl:template name="drawScale">
2847    <xsl:variable name="x1" select="14"/>
2848    <xsl:variable name="y1" select="round(($documentHeight)+((($bottomLeftLatitude)-(number($bottomLeftLatitude)))*10000*$scale*$projection))+28"/>
2849    <xsl:variable name="x2" select="$x1+$km"/>
2850    <xsl:variable name="y2" select="$y1"/>
2851
2852    <g id="marginalia-scale" inkscape:groupmode="layer" inkscape:label="Scale">
2853      <line id="marginalia-scale-casing" class="map-scale-casing" x1="{$x1}" y1="{$y1}" x2="{$x2}" y2="{$y2}"/>
2854
2855      <line id="marginalia-scale-core" class="map-scale-core" stroke-dasharray="{($km div 10)}" x1="{$x1}" y1="{$y1}" x2="{$x2}" y2="{$y2}"/>
2856
2857      <line id="marginalia-scale-bookend-from" class="map-scale-bookend" x1="{$x1}" y1="{$y1 + 2}" x2="{$x1}" y2="{$y1 - 10}"/>
2858
2859      <line id="marginalia-scale-bookend-to" class="map-scale-bookend" x1="{$x2}" y1="{$y2 + 2}" x2="{$x2}" y2="{$y2 - 10}"/>
2860
2861      <text id="marginalia-scale-text-from" class="map-scale-caption" x="{$x1}" y="{$y1 - 10}">0</text>
2862
2863      <text id="marginalia-scale-text-to" class="map-scale-caption" x="{$x2}" y="{$y2 - 10}">1km</text>
2864    </g>
2865  </xsl:template>
2866
2867
2868  <!-- Create a comment in SVG source code and RDF description of license -->
2869  <xsl:template name="metadata">
2870
2871    <xsl:comment>
2872
2873      Copyright (c) <xsl:value-of select="$year"/> OpenStreetMap
2874      www.openstreetmap.org
2875      This work is licensed under the
2876      Creative Commons Attribution-ShareAlike 2.0 License.
2877      http://creativecommons.org/licenses/by-sa/2.0/
2878
2879    </xsl:comment>
2880    <metadata id="metadata">
2881      <rdf:RDF xmlns="http://web.resource.org/cc/">
2882        <cc:Work rdf:about="">
2883          <cc:license rdf:resource="http://creativecommons.org/licenses/by-sa/2.0/"/>
2884          <dc:format>image/svg+xml</dc:format>
2885          <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
2886          <dc:title>
2887            <xsl:value-of select="$title"/>
2888          </dc:title>
2889          <dc:date>
2890            <xsl:value-of select="$date"/>
2891          </dc:date>
2892          <dc:source>http://www.openstreetmap.org/</dc:source>
2893        </cc:Work>
2894        <cc:License rdf:about="http://creativecommons.org/licenses/by-sa/2.0/">
2895          <cc:permits rdf:resource="http://web.resource.org/cc/Reproduction"/>
2896          <cc:permits rdf:resource="http://web.resource.org/cc/Distribution"/>
2897          <cc:permits rdf:resource="http://web.resource.org/cc/DerivativeWorks"/>
2898          <cc:requires rdf:resource="http://web.resource.org/cc/Notice"/>
2899          <cc:requires rdf:resource="http://web.resource.org/cc/Attribution"/>
2900          <cc:requires rdf:resource="http://web.resource.org/cc/ShareAlike"/>
2901        </cc:License>
2902      </rdf:RDF>
2903    </metadata>
2904  </xsl:template>
2905
2906  <!-- Create a license logo and description in the image -->
2907  <xsl:template name="in-image-license">
2908    <xsl:param name="dx"/>
2909    <xsl:param name="dy"/>
2910
2911    <g id="license" inkscape:groupmode="layer" inkscape:label="Copyright" transform="translate({$dx},{$dy})">
2912      <style type="text/css">
2913        <![CDATA[
2914                .license-text {
2915                    text-anchor: left;
2916                    font-family: "DejaVu Sans",sans-serif;
2917                    font-size: 6px;
2918                    fill: black;
2919                }
2920            ]]>
2921      </style>
2922      <a id="license-cc-logo-link" xlink:href="http://creativecommons.org/licenses/by-sa/2.0/">
2923        <g id="license-cc-logo" transform="scale(0.5,0.5) translate(-604,-49)">
2924          <path id="path3817_2_" nodetypes="ccccccc" d="M
2925                    182.23532,75.39014 L 296.29928,75.59326 C
2926                    297.89303,75.59326 299.31686,75.35644 299.31686,78.77344 L
2927                    299.17721,116.34033 L 179.3569,116.34033 L
2928                    179.3569,78.63379 C 179.3569,76.94922 179.51999,75.39014
2929                    182.23532,75.39014 z " style="fill:#aab2ab"/>
2930          <g id="g5908_2_" transform="matrix(0.872921,0,0,0.872921,50.12536,143.2144)">
2931            <path id="path5906_2_" type="arc" cx="296.35416"
2932            cy="264.3577" ry="22.939548" rx="22.939548" d="M
2933                        187.20944,-55.6792 C 187.21502,-46.99896
2934                        180.18158,-39.95825 171.50134,-39.95212 C
2935                        162.82113,-39.94708 155.77929,-46.97998
2936                        155.77426,-55.66016 C 155.77426,-55.66687
2937                        155.77426,-55.67249 155.77426,-55.6792 C
2938                        155.76922,-64.36054 162.80209,-71.40125
2939                        171.48233,-71.40631 C 180.16367,-71.41193
2940                        187.20441,-64.37842 187.20944,-55.69824 C
2941                        187.20944,-55.69263 187.20944,-55.68591
2942                        187.20944,-55.6792 z " style="fill:white"/>
2943            <g id="g5706_2_" transform="translate(-289.6157,99.0653)">
2944              <path id="path5708_2_" d="M 473.88455,-167.54724 C
2945                            477.36996,-164.06128 479.11294,-159.79333
2946                            479.11294,-154.74451 C 479.11294,-149.69513
2947                            477.40014,-145.47303 473.9746,-142.07715 C
2948                            470.33929,-138.50055 466.04281,-136.71283
2949                            461.08513,-136.71283 C 456.18736,-136.71283
2950                            451.96526,-138.48544 448.42003,-142.03238 C
2951                            444.87419,-145.57819 443.10158,-149.81537
2952                            443.10158,-154.74451 C 443.10158,-159.6731
2953                            444.87419,-163.94049 448.42003,-167.54724 C
2954                            451.87523,-171.03375 456.09728,-172.77618
2955                            461.08513,-172.77618 C 466.13342,-172.77618
2956                            470.39914,-171.03375 473.88455,-167.54724 z M
2957                            450.76657,-165.20239 C 447.81982,-162.22601
2958                            446.34701,-158.7395 446.34701,-154.74005 C
2959                            446.34701,-150.7417 447.80529,-147.28485
2960                            450.72125,-144.36938 C 453.63778,-141.45288
2961                            457.10974,-139.99462 461.1383,-139.99462 C
2962                            465.16683,-139.99462 468.66848,-141.46743
2963                            471.64486,-144.41363 C 474.47076,-147.14947
2964                            475.88427,-150.59069 475.88427,-154.74005 C
2965                            475.88427,-158.85809 474.44781,-162.35297
2966                            471.57659,-165.22479 C 468.70595,-168.09546
2967                            465.22671,-169.53131 461.1383,-169.53131 C
2968                            457.04993,-169.53131 453.59192,-168.08813
2969                            450.76657,-165.20239 z M 458.52106,-156.49927 C
2970                            458.07074,-157.4809 457.39673,-157.9715
2971                            456.49781,-157.9715 C 454.90867,-157.9715
2972                            454.11439,-156.90198 454.11439,-154.763 C
2973                            454.11439,-152.62341 454.90867,-151.55389
2974                            456.49781,-151.55389 C 457.54719,-151.55389
2975                            458.29676,-152.07519 458.74647,-153.11901 L
2976                            460.94923,-151.94598 C 459.8993,-150.0805
2977                            458.32417,-149.14697 456.22374,-149.14697 C
2978                            454.60384,-149.14697 453.30611,-149.64367
2979                            452.33168,-150.63653 C 451.35561,-151.62994
2980                            450.86894,-152.99926 450.86894,-154.7445 C
2981                            450.86894,-156.46008 451.37123,-157.82159
2982                            452.37642,-158.83013 C 453.38161,-159.83806
2983                            454.63347,-160.34264 456.13423,-160.34264 C
2984                            458.35435,-160.34264 459.94407,-159.46776
2985                            460.90504,-157.71978 L 458.52106,-156.49927 z M
2986                            468.8844,-156.49927 C 468.43353,-157.4809
2987                            467.77292,-157.9715 466.90201,-157.9715 C
2988                            465.28095,-157.9715 464.46988,-156.90198
2989                            464.46988,-154.763 C 464.46988,-152.62341
2990                            465.28095,-151.55389 466.90201,-151.55389 C
2991                            467.95304,-151.55389 468.68918,-152.07519
2992                            469.10925,-153.11901 L 471.36126,-151.94598 C
2993                            470.31301,-150.0805 468.74007,-149.14697
2994                            466.64358,-149.14697 C 465.02587,-149.14697
2995                            463.73095,-149.64367 462.75711,-150.63653 C
2996                            461.78494,-151.62994 461.29773,-152.99926
2997                            461.29773,-154.7445 C 461.29773,-156.46008
2998                            461.79221,-157.82159 462.78061,-158.83013 C
2999                            463.76843,-159.83806 465.02588,-160.34264
3000                            466.55408,-160.34264 C 468.77027,-160.34264
3001                            470.35776,-159.46776 471.3154,-157.71978 L
3002                            468.8844,-156.49927 z "/>
3003            </g>
3004          </g>
3005          <path d="M 297.29639,74.91064 L 181.06688,74.91064 C
3006                    179.8203,74.91064 178.80614,75.92529 178.80614,77.17187 L
3007                    178.80614,116.66748 C 178.80614,116.94922
3008                    179.03466,117.17822 179.31639,117.17822 L
3009                    299.04639,117.17822 C 299.32813,117.17822
3010                    299.55713,116.94922 299.55713,116.66748 L
3011                    299.55713,77.17188 C 299.55713,75.92529 298.54297,74.91064
3012                    297.29639,74.91064 z M 181.06688,75.93213 L
3013                    297.29639,75.93213 C 297.97998,75.93213 298.53565,76.48828
3014                    298.53565,77.17188 C 298.53565,77.17188 298.53565,93.09131
3015                    298.53565,104.59034 L 215.4619,104.59034 C
3016                    212.41698,110.09571 206.55077,113.83399 199.81835,113.83399
3017                    C 193.083,113.83399 187.21825,110.09913 184.1748,104.59034
3018                    L 179.82666,104.59034 C 179.82666,93.09132
3019                    179.82666,77.17188 179.82666,77.17188 C 179.82664,76.48828
3020                    180.38329,75.93213 181.06688,75.93213 z " id="frame"/>
3021          <g enable-background="new" id="g2821">
3022            <path d="M 265.60986,112.8833 C 265.68994,113.03906
3023                        265.79736,113.16504 265.93115,113.26172 C
3024                        266.06494,113.35791 266.22119,113.42969
3025                        266.40088,113.47608 C 266.58154,113.52296
3026                        266.76807,113.54639 266.96045,113.54639 C
3027                        267.09033,113.54639 267.22998,113.53565
3028                        267.3794,113.51368 C 267.52784,113.4922
3029                        267.66749,113.44972 267.79835,113.3877 C
3030                        267.92823,113.32569 268.03761,113.23975
3031                        268.12355,113.13086 C 268.21144,113.02197
3032                        268.25441,112.88379 268.25441,112.71533 C
3033                        268.25441,112.53515 268.19679,112.38916
3034                        268.08156,112.27685 C 267.9673,112.16455
3035                        267.81594,112.07177 267.62941,111.99658 C
3036                        267.44386,111.92236 267.23195,111.85693
3037                        266.9966,111.80078 C 266.76027,111.74463
3038                        266.52101,111.68262 266.27883,111.61377 C
3039                        266.02981,111.55176 265.78762,111.47559
3040                        265.55129,111.38525 C 265.31594,111.29541
3041                        265.10402,111.17822 264.9175,111.03515 C
3042                        264.73098,110.89208 264.58059,110.71337
3043                        264.46535,110.49853 C 264.35109,110.28369
3044                        264.29347,110.02392 264.29347,109.71923 C
3045                        264.29347,109.37646 264.36671,109.07958
3046                        264.51222,108.82763 C 264.6587,108.57568
3047                        264.85011,108.36572 265.08644,108.19726 C
3048                        265.32179,108.02929 265.58937,107.90478
3049                        265.8882,107.82372 C 266.18605,107.74315
3050                        266.48488,107.70263 266.78273,107.70263 C
3051                        267.13136,107.70263 267.46535,107.74169
3052                        267.78566,107.81982 C 268.105,107.89746
3053                        268.39015,108.02392 268.6382,108.19824 C
3054                        268.88722,108.37256 269.08449,108.59521
3055                        269.23097,108.86621 C 269.37648,109.13721
3056                        269.44972,109.46582 269.44972,109.85156 L
3057                        268.02784,109.85156 C 268.01514,109.65234
3058                        267.97315,109.4873 267.90284,109.35693 C
3059                        267.83155,109.22607 267.73682,109.12353
3060                        267.61964,109.04834 C 267.50148,108.97412
3061                        267.36671,108.9209 267.21534,108.89014 C
3062                        267.063,108.85889 266.89796,108.84326
3063                        266.71827,108.84326 C 266.60108,108.84326
3064                        266.48292,108.85596 266.36573,108.88037 C
3065                        266.24757,108.90576 266.14112,108.94922
3066                        266.04542,109.01123 C 265.94874,109.07373
3067                        265.86964,109.15137 265.80812,109.24463 C
3068                        265.7466,109.33838 265.71535,109.45654
3069                        265.71535,109.59961 C 265.71535,109.73047
3070                        265.73976,109.83643 265.78957,109.91699 C
3071                        265.83937,109.99804 265.93801,110.07275
3072                        266.08352,110.14111 C 266.22903,110.20947
3073                        266.43118,110.27832 266.68899,110.34668 C
3074                        266.9468,110.41504 267.28372,110.50244
3075                        267.70071,110.60791 C 267.82473,110.63281
3076                        267.99661,110.67822 268.21731,110.74365 C
3077                        268.43801,110.80908 268.65676,110.91308
3078                        268.87454,111.05615 C 269.09231,111.1997
3079                        269.27981,111.39111 269.43899,111.63037 C
3080                        269.59719,111.87012 269.67629,112.17676
3081                        269.67629,112.55029 C 269.67629,112.85547
3082                        269.61672,113.13867 269.49856,113.3999 C
3083                        269.3804,113.66162 269.20461,113.8872
3084                        268.97122,114.07666 C 268.73782,114.26709
3085                        268.44876,114.41455 268.10403,114.52051 C
3086                        267.75833,114.62647 267.35794,114.6792
3087                        266.90481,114.6792 C 266.53762,114.6792
3088                        266.18118,114.63379 265.83547,114.54346 C
3089                        265.49074,114.45313 265.18508,114.31104
3090                        264.92043,114.11768 C 264.65676,113.92432
3091                        264.4468,113.67774 264.29055,113.37891 C
3092                        264.13528,113.07959 264.06106,112.7251
3093                        264.06692,112.31397 L 265.4888,112.31397 C
3094                        265.48877,112.53809 265.52881,112.72803
3095                        265.60986,112.8833 z " id="path2823"
3096            style="fill:white"/>
3097            <path d="M 273.8667,107.8667 L
3098                        276.35986,114.53076 L 274.8374,114.53076 L
3099                        274.33349,113.04638 L 271.84033,113.04638 L
3100                        271.31787,114.53076 L 269.84326,114.53076 L
3101                        272.36377,107.8667 L 273.8667,107.8667 z M
3102                        273.95068,111.95264 L 273.11084,109.50928 L
3103                        273.09229,109.50928 L 272.22315,111.95264 L
3104                        273.95068,111.95264 z " id="path2825"
3105            style="fill:white"/>
3106          </g>
3107          <g enable-background="new" id="g2827">
3108            <path d="M 239.17821,107.8667 C 239.49559,107.8667
3109                        239.78563,107.89502 240.04735,107.95068 C
3110                        240.30907,108.00683 240.53368,108.09863
3111                        240.72118,108.22607 C 240.9077,108.35351
3112                        241.05321,108.52295 241.15575,108.73437 C
3113                        241.25829,108.94579 241.31005,109.20703
3114                        241.31005,109.51806 C 241.31005,109.854
3115                        241.23388,110.13329 241.08056,110.35742 C
3116                        240.92822,110.58154 240.70165,110.76465
3117                        240.40283,110.90771 C 240.81494,111.02587
3118                        241.12256,111.23291 241.32568,111.5288 C
3119                        241.5288,111.82469 241.63037,112.18114
3120                        241.63037,112.59814 C 241.63037,112.93408
3121                        241.56494,113.22509 241.43408,113.47119 C
3122                        241.30322,113.7168 241.12646,113.91748
3123                        240.90576,114.07324 C 240.68408,114.229
3124                        240.43115,114.34424 240.14795,114.41845 C
3125                        239.86377,114.49365 239.57275,114.53075
3126                        239.27295,114.53075 L 236.03662,114.53075 L
3127                        236.03662,107.86669 L 239.17821,107.86669 L
3128                        239.17821,107.8667 z M 238.99071,110.56201 C
3129                        239.25243,110.56201 239.46727,110.5 239.63622,110.37597
3130                        C 239.80419,110.25146 239.88817,110.05029
3131                        239.88817,109.77099 C 239.88817,109.61572
3132                        239.85985,109.48828 239.80419,109.38915 C
3133                        239.74755,109.28954 239.67333,109.21239
3134                        239.57958,109.15624 C 239.48583,109.10058
3135                        239.37841,109.06151 239.25731,109.04003 C
3136                        239.13524,109.01806 239.00926,109.00732
3137                        238.8784,109.00732 L 237.50535,109.00732 L
3138                        237.50535,110.56201 L 238.99071,110.56201 z M
3139                        239.07664,113.39014 C 239.22019,113.39014
3140                        239.35691,113.37647 239.48777,113.34815 C
3141                        239.61863,113.32032 239.73484,113.27344
3142                        239.83445,113.2085 C 239.93406,113.14307
3143                        240.01316,113.0542 240.07273,112.94239 C
3144                        240.1323,112.83058 240.1616,112.68751
3145                        240.1616,112.51319 C 240.1616,112.17139
3146                        240.06492,111.92725 239.87156,111.78126 C
3147                        239.6782,111.63527 239.42234,111.56202
3148                        239.10496,111.56202 L 237.50535,111.56202 L
3149                        237.50535,113.39014 L 239.07664,113.39014 z "
3150            id="path2829" style="fill:white"/>
3151            <path d="M 241.88914,107.8667 L 243.53269,107.8667 L
3152                        245.09324,110.49854 L 246.64402,107.8667 L
3153                        248.27781,107.8667 L 245.80418,111.97315 L
3154                        245.80418,114.53077 L 244.33543,114.53077 L
3155                        244.33543,111.93604 L 241.88914,107.8667 z "
3156            id="path2831" style="fill:white"/>
3157          </g>
3158          <g id="g6316_1_" transform="matrix(0.624995,0,0,0.624995,391.2294,176.9332)">
3159            <path id="path6318_1_" type="arc" cx="475.97119"
3160            cy="252.08646" ry="29.209877" rx="29.209877" d="M
3161                        -175.0083,-139.1153 C -175.00204,-129.7035
3162                        -182.62555,-122.06751 -192.03812,-122.06049 C
3163                        -201.44913,-122.05341 -209.08512,-129.67774
3164                        -209.09293,-139.09028 C -209.09293,-139.09809
3165                        -209.09293,-139.10749 -209.09293,-139.1153 C
3166                        -209.09919,-148.52784 -201.47413,-156.1623
3167                        -192.06311,-156.17011 C -182.65054,-156.17713
3168                        -175.01456,-148.55207 -175.0083,-139.14026 C
3169                        -175.0083,-139.13092 -175.0083,-139.1239
3170                        -175.0083,-139.1153 z " style="fill:white"/>
3171            <g id="g6320_1_" transform="translate(-23.9521,-89.72962)">
3172              <path id="path6322_1_" d="M -168.2204,-68.05536 C
3173                            -173.39234,-68.05536 -177.76892,-66.25067
3174                            -181.35175,-62.64203 C -185.02836,-58.90759
3175                            -186.86588,-54.48883 -186.86588,-49.38568 C
3176                            -186.86588,-44.28253 -185.02836,-39.89416
3177                            -181.35175,-36.22308 C -177.67673,-32.55114
3178                            -173.29859,-30.71521 -168.2204,-30.71521 C
3179                            -163.07974,-30.71521 -158.62503,-32.56677
3180                            -154.85312,-36.26996 C -151.30307,-39.78558
3181                            -149.52652,-44.15827 -149.52652,-49.38568 C
3182                            -149.52652,-54.6123 -151.33432,-59.03265
3183                            -154.94843,-62.64203 C -158.5625,-66.25067
3184                            -162.98599,-68.05536 -168.2204,-68.05536 z M
3185                            -168.17352,-64.69519 C -163.936,-64.69519
3186                            -160.33752,-63.20221 -157.37655,-60.21466 C
3187                            -154.38748,-57.25836 -152.89214,-53.64899
3188                            -152.89214,-49.38568 C -152.89214,-45.09186
3189                            -154.35466,-41.52856 -157.28438,-38.69653 C
3190                            -160.36876,-35.64727 -163.99849,-34.12304
3191                            -168.17351,-34.12304 C -172.34856,-34.12304
3192                            -175.94701,-35.63244 -178.96892,-38.64965 C
3193                            -181.9908,-41.66918 -183.50176,-45.24657
3194                            -183.50176,-49.38567 C -183.50176,-53.52398
3195                            -181.97518,-57.13414 -178.92205,-60.21465 C
3196                            -175.9939,-63.20221 -172.41107,-64.69519
3197                            -168.17352,-64.69519 z "/>
3198              <path id="path6324_1_" d="M -176.49548,-52.02087 C
3199                            -175.75171,-56.71856 -172.44387,-59.22949
3200                            -168.30008,-59.22949 C -162.33911,-59.22949
3201                            -158.70783,-54.90448 -158.70783,-49.1372 C
3202                            -158.70783,-43.50982 -162.57194,-39.13793
3203                            -168.39383,-39.13793 C -172.39856,-39.13793
3204                            -175.98297,-41.60277 -176.63611,-46.43877 L
3205                            -171.93292,-46.43877 C -171.7923,-43.92778
3206                            -170.1626,-43.04418 -167.83447,-43.04418 C
3207                            -165.1813,-43.04418 -163.4563,-45.50908
3208                            -163.4563,-49.27709 C -163.4563,-53.22942
3209                            -164.94693,-55.32244 -167.74228,-55.32244 C
3210                            -169.79074,-55.32244 -171.55948,-54.57787
3211                            -171.93292,-52.02087 L -170.56418,-52.02789 L
3212                            -174.26734,-48.32629 L -177.96894,-52.02789 L
3213                            -176.49548,-52.02087 z "/>
3214            </g>
3215          </g>
3216          <g id="g2838">
3217            <circle cx="242.56226" cy="90.224609" r="10.8064" id="circle2840" style="fill:white"/>
3218            <g id="g2842">
3219              <path d="M 245.68994,87.09766 C 245.68994,86.68116
3220                            245.35205,86.34424 244.93603,86.34424 L
3221                            240.16357,86.34424 C 239.74755,86.34424
3222                            239.40966,86.68115 239.40966,87.09766 L
3223                            239.40966,91.87061 L 240.74071,91.87061 L
3224                            240.74071,97.52295 L 244.3579,97.52295 L
3225                            244.3579,91.87061 L 245.68993,91.87061 L
3226                            245.68993,87.09766 L 245.68994,87.09766 z "
3227              id="path2844"/>
3228              <circle cx="242.5498" cy="84.083008" r="1.63232" id="circle2846"/>
3229            </g>
3230            <path clip-rule="evenodd" d="M 242.53467,78.31836 C
3231                        239.30322,78.31836 236.56641,79.4458 234.32715,81.70215
3232                        C 232.0293,84.03516 230.88086,86.79736
3233                        230.88086,89.98633 C 230.88086,93.1753
3234                        232.0293,95.91846 234.32715,98.21338 C
3235                        236.625,100.50781 239.36133,101.65527
3236                        242.53467,101.65527 C 245.74756,101.65527
3237                        248.53272,100.49853 250.88819,98.18359 C
3238                        253.10889,95.98681 254.21827,93.2539 254.21827,89.98632
3239                        C 254.21827,86.71874 253.08936,83.95751
3240                        250.83057,81.70214 C 248.57178,79.4458
3241                        245.80615,78.31836 242.53467,78.31836 z M
3242                        242.56396,80.41797 C 245.2124,80.41797
3243                        247.46142,81.35156 249.31103,83.21875 C
3244                        251.18115,85.06592 252.11572,87.32227
3245                        252.11572,89.98633 C 252.11572,92.66992
3246                        251.20068,94.89746 249.36963,96.66699 C
3247                        247.4419,98.57275 245.17334,99.52539 242.56397,99.52539
3248                        C 239.9546,99.52539 237.70557,98.58252
3249                        235.81739,96.6958 C 233.92774,94.80957
3250                        232.98389,92.57324 232.98389,89.98633 C
3251                        232.98389,87.3999 233.93799,85.14404 235.84619,83.21875
3252                        C 237.67676,81.35156 239.9165,80.41797
3253                        242.56396,80.41797 z " id="path2848"
3254            style="fill-rule:evenodd"/>
3255          </g>
3256        </g>
3257      </a>
3258      <a id="license-osm-link" xlink:href="http://www.openstreetmap.org/">
3259        <g transform="translate(-210,10)" id="license-osm-text">
3260          <text class="license-text" dx="0" dy="0">
3261            Copyright © <xsl:value-of select="$year"/> OpenStreetMap (openstreetmap.org)
3262          </text>
3263        </g>
3264      </a>
3265      <a id="license-cc-text-link" xlink:href="http://creativecommons.org/licenses/by-sa/2.0/">
3266        <g transform="translate(-150,18)" id="license-cc-text">
3267          <text class="license-text" dx="0" dy="0">This work is licensed under the Creative</text>
3268          <text class="license-text" dx="0" dy="8">Commons Attribution-ShareAlike 2.0 License.</text>
3269          <text class="license-text" dx="0" dy="16">http://creativecommons.org/licenses/by-sa/2.0/</text>
3270        </g>
3271      </a>
3272    </g>
3273  </xsl:template>
3274
3275
3276  <!-- Draw zoom controls -->
3277  <xsl:template name="zoomControl">
3278    <defs>
3279
3280      <style type="text/css">
3281        .fancyButton {
3282        stroke: #8080ff;
3283        stroke-width: 2px;
3284        fill: #fefefe;
3285        }
3286        .fancyButton:hover {
3287        stroke: red;
3288        }
3289      </style>
3290
3291      <filter id="fancyButton" filterUnits="userSpaceOnUse" x="0" y="0" width="200" height="350">
3292        <feGaussianBlur in="SourceAlpha" stdDeviation="4" result="blur"/>
3293        <feOffset in="blur" dx="2" dy="2" result="offsetBlur"/>
3294        <feSpecularLighting in="blur" surfaceScale="5" specularConstant=".75" specularExponent="20" lighting-color="white" result="specOut">
3295          <fePointLight x="-5000" y="-10000" z="7000"/>
3296        </feSpecularLighting>
3297        <feComposite in="specOut" in2="SourceAlpha" operator="in" result="specOut"/>
3298        <feComposite in="SourceGraphic" in2="specOut" operator="arithmetic" k1="0" k2="1" k3="1" k4="0" result="litPaint"/>
3299        <feMerge>
3300          <feMergeNode in="offsetBlur"/>
3301          <feMergeNode in="litPaint"/>
3302        </feMerge>
3303      </filter>
3304      <symbol id="panDown" viewBox="0 0 19 19" class="fancyButton">
3305        <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"/>
3306        <path d="M 9.5,5 L 9.5,14"/>
3307      </symbol>
3308      <symbol id="panUp" viewBox="0 0 19 19" class="fancyButton">
3309        <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"/>
3310        <path d="M 9.5,5 L 9.5,14"/>
3311      </symbol>
3312      <symbol id="panLeft" viewBox="0 0 19 19" class="fancyButton">
3313        <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"/>
3314        <path d="M 5,9.5 L 14,9.5"/>
3315      </symbol>
3316      <symbol id="panRight" viewBox="0 0 19 19" class="fancyButton">
3317        <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"/>
3318        <path d="M 5,9.5 L 14,9.5"/>
3319      </symbol>
3320      <symbol id="zoomIn" viewBox="0 0 19 19" class="fancyButton">
3321        <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"/>
3322        <path d="M 5,9.5 L 14,9.5 M 9.5,5 L 9.5,14"/>
3323      </symbol>
3324      <symbol id="zoomOut" viewBox="0 0 19 19" class="fancyButton">
3325        <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"/>
3326        <path d="M 5,9.5 L 14,9.5"/>
3327      </symbol>
3328
3329    </defs>
3330
3331    <g id="gPanDown" filter="url(#fancyButton)" onclick="fnPan('down')">
3332      <use x="18px" y="60px" xlink:href="#panDown" width="14px" height="14px"/>
3333    </g>
3334    <g id="gPanRight" filter="url(#fancyButton)" onclick="fnPan('right')">
3335      <use x="8px" y="70px" xlink:href="#panRight" width="14px" height="14px"/>
3336    </g>
3337    <g id="gPanLeft" filter="url(#fancyButton)" onclick="fnPan('left')">
3338      <use x="28px" y="70px" xlink:href="#panLeft" width="14px" height="14px"/>
3339    </g>
3340    <g id="gPanUp" filter="url(#fancyButton)" onclick="fnPan('up')">
3341      <use x="18px" y="80px" xlink:href="#panUp" width="14px" height="14px"/>
3342    </g>
3343
3344    <xsl:variable name="x1" select="25"/>
3345    <xsl:variable name="y1" select="105"/>
3346    <xsl:variable name="x2" select="25"/>
3347    <xsl:variable name="y2" select="300"/>
3348
3349    <line style="stroke-width: 10; stroke-linecap: butt; stroke: #8080ff;">
3350      <xsl:attribute name="x1">
3351        <xsl:value-of select="$x1"/>
3352      </xsl:attribute>
3353      <xsl:attribute name="y1">
3354        <xsl:value-of select="$y1"/>
3355      </xsl:attribute>
3356      <xsl:attribute name="x2">
3357        <xsl:value-of select="$x2"/>
3358      </xsl:attribute>
3359      <xsl:attribute name="y2">
3360        <xsl:value-of select="$y2"/>
3361      </xsl:attribute>
3362    </line>
3363
3364    <line style="stroke-width: 8; stroke-linecap: butt; stroke: white; stroke-dasharray: 10,1;">
3365      <xsl:attribute name="x1">
3366        <xsl:value-of select="$x1"/>
3367      </xsl:attribute>
3368      <xsl:attribute name="y1">
3369        <xsl:value-of select="$y1"/>
3370      </xsl:attribute>
3371      <xsl:attribute name="x2">
3372        <xsl:value-of select="$x2"/>
3373      </xsl:attribute>
3374      <xsl:attribute name="y2">
3375        <xsl:value-of select="$y2"/>
3376      </xsl:attribute>
3377    </line>
3378
3379    <!-- Need to use onmousedown because onclick is interfered with by the onmousedown handler for panning -->
3380    <g id="gZoomIn" filter="url(#fancyButton)" onmousedown="fnZoom('in')">
3381      <use x="15.5px" y="100px" xlink:href="#zoomIn" width="19px" height="19px"/>
3382    </g>
3383
3384    <!-- Need to use onmousedown because onclick is interfered with by the onmousedown handler for panning -->
3385    <g id="gZoomOut" filter="url(#fancyButton)" onmousedown="fnZoom('out')">
3386      <use x="15.5px" y="288px" xlink:href="#zoomOut" width="19px" height="19px"/>
3387    </g>
3388  </xsl:template>
3389
3390  <xsl:template name="javaScript">
3391    <script>
3392      /*
3393
3394      Osmarender
3395
3396      interactive.js
3397
3398      */
3399
3400      function fnResize() {
3401      fnResizeElement("gAttribution")
3402      fnResizeElement("gLicense")
3403      fnResizeElement("gZoomIn")
3404      fnResizeElement("gZoomOut")
3405      }
3406
3407
3408      function fnResizeElement(e) {
3409      //
3410      var oSVG,scale,currentTranslateX,currentTranslateY,oe
3411      //
3412      oSVG=document.rootElement
3413      scale=1/oSVG.currentScale
3414      currentTranslateX=oSVG.currentTranslate.x
3415      currentTranslateY=oSVG.currentTranslate.y
3416      oe=document.getElementById(e)
3417      if (oe) oe.setAttributeNS(null,"transform","scale("+scale+","+scale+") translate("+(-currentTranslateX)+","+(-currentTranslateY)+")")
3418      }
3419
3420
3421      function fnToggleImage(osmImage) {
3422      var xlink = 'http://www.w3.org/1999/xlink';
3423      ogThumbnail=document.getElementById('gThumbnail')
3424      if (ogThumbnail.getAttributeNS(null,"visibility")=="visible") fnHideImage()
3425      else {
3426      ogThumbnail.setAttributeNS(null,"visibility","visible")
3427      oThumbnail=document.getElementById('thumbnail')
3428      oThumbnail.setAttributeNS(xlink,"href",osmImage)
3429      }
3430      }
3431
3432      function fnHideImage() {
3433      ogThumbnail=document.getElementById('gThumbnail')
3434      ogThumbnail.setAttributeNS(null,"visibility","hidden")
3435      }
3436
3437
3438      /* The following code originally written by Jonathan Watt (http://jwatt.org/), Aug. 2005 */
3439
3440      if (!window)
3441      window = this;
3442
3443
3444      function fnOnLoad(evt) {
3445      if (!document) window.document = evt.target.ownerDocument
3446      }
3447
3448
3449      /**
3450      * Event handlers to change the current user space for the zoom and pan
3451      * controls to make them appear to be scale invariant.
3452      */
3453
3454      function fnOnZoom(evt) {
3455      try {
3456      if (evt.newScale == undefined) throw 'bad interface'
3457      // update the transform list that adjusts for zoom and pan
3458      var tlist = document.getElementById('staticElements').transform.baseVal
3459      tlist.getItem(0).setScale(1/evt.newScale, 1/evt.newScale)
3460      tlist.getItem(1).setTranslate(-evt.newTranslate.x, -evt.newTranslate.y)
3461      }
3462      catch (e) {
3463      // work around difficiencies in non-moz implementations (some don't
3464      // implement the SVGZoomEvent or SVGAnimatedTransform interfaces)
3465      var de = document.documentElement
3466      var tform = 'scale(' + 1/de.currentScale + ') ' + 'translate(' + (-de.currentTranslate.x) + ', ' + (-de.currentTranslate.y) + ')'
3467      document.getElementById('staticElements').setAttributeNS(null, 'transform', tform)
3468      }
3469      }
3470
3471
3472      function fnOnScroll(evt) {
3473      var ct = document.documentElement.currentTranslate
3474      try {
3475      // update the transform list that adjusts for zoom and pan
3476      var tlist = document.getElementById('staticElements').transform.baseVal
3477      tlist.getItem(1).setTranslate(-ct.x, -ct.y)
3478      }
3479      catch (e) {
3480      // work around difficiencies in non-moz implementations (some don't
3481      // implement the SVGAnimatedTransform interface)
3482      var tform = 'scale(' + 1/document.documentElement.currentScale + ') ' + 'translate(' + (-ct.x) + ', ' + (-ct.y) + ')';
3483      document.getElementById('staticElements').setAttributeNS(null, 'transform', tform)
3484      }
3485      }
3486
3487
3488      function fnZoom(type) {
3489      var de = document.documentElement;
3490      var oldScale = de.currentScale;
3491      var oldTranslate = { x: de.currentTranslate.x, y: de.currentTranslate.y };
3492      var s = 2;
3493      if (type == 'in') {de.currentScale *= 1.5;}
3494      if (type == 'out') {de.currentScale /= 1.4;}
3495      // correct currentTranslate so zooming is to the center of the viewport:
3496
3497      var vp_width, vp_height;
3498      try {
3499      vp_width = de.viewport.width;
3500      vp_height = de.viewport.height;
3501      }
3502      catch (e) {
3503      // work around difficiency in moz ('viewport' property not implemented)
3504      vp_width = window.innerWidth;
3505      vp_height = window.innerHeight;
3506      }
3507      de.currentTranslate.x = vp_width/2 - ((de.currentScale/oldScale) * (vp_width/2 - oldTranslate.x));
3508      de.currentTranslate.y = vp_height/2 - ((de.currentScale/oldScale) * (vp_height/2 - oldTranslate.y));
3509
3510      }
3511
3512
3513      function fnPan(type) {
3514      var de = document.documentElement;
3515      var ct = de.currentTranslate;
3516      var t = 150;
3517      if (type == 'right') ct.x += t;
3518      if (type == 'down') ct.y += t;
3519      if (type == 'left') ct.x -= t;
3520      if (type == 'up') ct.y -= t;
3521      }
3522
3523
3524      var gCurrentX,gCurrentY
3525      var gDeltaX,gDeltaY
3526      var gMouseDown=false
3527      var gCurrentTranslate=document.documentElement.currentTranslate
3528
3529      function fnOnMouseDown(evt) {
3530      gCurrentX=gCurrentTranslate.x
3531      gCurrentY=gCurrentTranslate.y
3532      gDeltaX=evt.clientX
3533      gDeltaY=evt.clientY
3534      gMouseDown=true
3535      evt.target.ownerDocument.rootElement.setAttributeNS(null,"cursor","move")
3536      }
3537
3538
3539      function fnOnMouseUp(evt) {
3540      gMouseDown=false
3541      evt.target.ownerDocument.rootElement.setAttribute("cursor","default")
3542      }
3543
3544
3545      function fnOnMouseMove(evt) {
3546      var id
3547      if (gMouseDown) {
3548      gCurrentTranslate.x=gCurrentX+evt.clientX-gDeltaX
3549      gCurrentTranslate.y=gCurrentY+evt.clientY-gDeltaY
3550      }
3551      }
3552
3553
3554    </script>
3555  </xsl:template>
3556
3557</xsl:stylesheet>
Note: See TracBrowser for help on using the repository browser.