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

Last change on this file since 9914 was 9900, checked in by jttt, 11 years ago

Add position="center" attribute to automatically center symbols, allows symbols to be saved as normal svg images

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