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

Last change on this file since 9574 was 9574, checked in by bobkare, 7 years ago

Fairly big osmarender change doing some refactoring on the rule parsing and falling back to simple BBOX center for areas with more than 150 nodes. Adds size-dependent rendering of names for large natural features (fixes #716) and suppresses labels for highway areas with same name as connected features (fixes #642).

r8442@pastry: bob | 2008-06-24 21:48:19 +0200
Creating a branch for my osmarender <rule> refactoring.
r8443@pastry: bob | 2008-06-24 22:10:21 +0200
Committing old <rule> refactoring code
r17179@pastry: bob | 2008-08-03 21:59:35 +0200
Merge back from muffin now that pastry is online again
r17180@pastry: bob | 2008-08-03 23:21:16 +0200
Merged from trunk
r17181@pastry: bob | 2008-08-05 17:57:55 +0200
Reintroducing some areaCenter changes I thought didn't have anything to do with this patch but it turns out the minSize stuff broke areaCenter because it used node-set on an RTF, which meant the nodes came from another document or something, which in turn meant key() no longer worked on the whole osm document
r17182@pastry: bob | 2008-08-05 19:13:57 +0200
Fixed wrong placement of minSize rule in z12, and did some work on styling all the minSize captions
r17183@pastry: bob | 2008-08-05 20:35:24 +0200
Cleaned up the rules for notConnectedSameTag on highway areas and junctions
r17588@pastry: bob | 2008-08-08 17:27:38 +0200
Implemented fallback to areaBBOXCenter for polygons with more than 150 nodes

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