source: subversion/applications/rendering/osmarender5/osmarender.xsl @ 4380

Last change on this file since 4380 was 4380, checked in by etienne, 13 years ago

Osmarender 5
Extensive changes to rendering engine.
Lots of new and changed cartography in all the rules files.
More details of changes on the mailing list and wiki in due course.

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