source: subversion/applications/rendering/tilesAtHome/frollo2.xsl @ 2706

Last change on this file since 2706 was 2706, checked in by jdschmidt, 13 years ago

Implemented empty sea tile detection speeding up client by upto 60 on some coastline tiles. Implemented configurable layer upload, set in tilesAtHome.conf. Changed frollo2 limit to 600 to fix water rendering on complex tiles.

File size: 16.0 KB
Line 
1<?xml version="1.0" encoding="UTF-8"?>
2<!--
3==============================================================================
4
5Frollo - Osmarender pre-processor
6         Part 2, for each way sort the segments into a series of best-fit linear
7         paths.  Annotate <seg> elements with osma:reverse=1 where the segment
8         is pointing in the wrong direction and annotate with osma:sub-path=1
9         when the segemnts are not contiguous.
10
11==============================================================================
12
13Copyright (C) 2007 Etienne Cherdlu
14
15This program is free software; you can redistribute it and/or modify
16it under the terms of the GNU General Public License as published by
17the Free Software Foundation; either version 2 of the License, or
18(at your option) any later version.
19
20This program is distributed in the hope that it will be useful,
21but WITHOUT ANY WARRANTY; without even the implied warranty of
22MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23GNU General Public License for more details.
24
25You should have received a copy of the GNU General Public License
26along with this program; if not, write to the Free Software
27Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
28
29==============================================================================
30-->
31
32<!-- Strategy.  Find a loose end.  Follow that loose end until we reach the end or another segment that has
33                already been processed.  Repeat until all loose ends have been processed.  Finally pick
34                up any unprocessed segments and follow them.  Repeat until all segments processed.
35
36                                A loose end is any segment in a way that does not have any other segments (in that way) leading
37                                to it.  We will also look for segments that have no other segments leading from them and process
38                                these in the reverse direction.
39                               
40                                We follow the path of a way along its segments using the following rules in this order:
41                                1) If the to end of the current segment connect to the from end of the next segment in the
42                                   way then use that segment
43                                2) If the to end of the current segment connect to the to end of the next segment in the way
44                                   then use that segment in reverse
45                                3) If the to end of the current segment connects to the from end of any other segments in the
46                                   way then use the first such segment
47                                4) If the to end of the current segment connects to the to end of any other segments in the way
48                                   then use the first such segment in reverse
49                                5) Find the next loose end, if there is one, and start a new sub-path
50                                6) Find the next unprocessed segment, if there is one, and start a new sub-path
51
52                                In all cases, if the segment is being processed in reverse then treat the from end as the to end and
53                                vice-versa.
54                       
55-->
56
57<xsl:stylesheet version="1.0"
58  xmlns:osma="http://wiki.openstreetmap.org/index.php/Osmarender/Frollo/1.0"
59  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes='osma'>
60
61    <xsl:output method="xml" omit-xml-declaration="no" indent="yes" encoding="UTF-8"/>
62
63        <!-- Some xsl processors are a bit recursion challenged (eg xalan-j).  This variable enables you to restrict the number of segs that
64             get sorted.  If a way has more than this number of segs then the rest just get output in their original order.  -->
65    <!-- reduced from 800 to 400 by framm as some t@h renderers were reporting
66    "possible endless recursion" errors -->
67    <!-- increased from 400 to 600 by Dutch as some tiles were not rendered correctly after close-areas preprocessor was
68    implemented -->
69
70        <xsl:variable name='maximumNumberOfSegs' select='"600"'/>
71               
72
73        <!-- Keys -->
74        <!-- Lookup for segments by segment id -->
75    <xsl:key name="segmentById" match="/osm/segment" use="@id"/>
76   
77   
78    <!-- Add an attribute to the osm element to indicate that this file has been frolloised -->
79    <xsl:template match='/osm'>
80                <osm>
81                        <xsl:attribute name='osma:frollo'>1</xsl:attribute>
82                        <xsl:apply-templates select='@*|node()'/>
83                </osm>
84    </xsl:template>
85   
86   
87    <!-- Process each way -->
88        <xsl:template match='way'>
89                <way>
90                        <xsl:apply-templates select='@*'/>
91
92                        <!-- If there are any segs, then make the first seg the context node and then find the next loose end -->
93                        <xsl:for-each select='seg[1]'>
94                                <xsl:call-template name='nextSeg'>
95                                        <xsl:with-param name='processedSegs' select='"|"'/>
96                                        <xsl:with-param name='debug' select='"firstSeg"'/>
97                                </xsl:call-template>                   
98                        </xsl:for-each>
99
100                        <xsl:apply-templates select='*'/>
101                </way>
102        </xsl:template>   
103   
104   
105        <!-- Process the next most suitable seg.  This will either be the first loose end, or, if there are no more unprocessed
106             loose ends then it will be the next unprocessed seg in original seg order. -->
107        <xsl:template name='nextSeg'>
108                <xsl:param name='processedSegs'/>
109                <xsl:param name='debug'/>
110               
111                <!-- A loose-end is any seg that has no other segs connecting to/from it in this way.  We prefer "from" loose-ends but
112                     will be happy with "to" loose-ends if necessary.  If there are no loose-ends (eg a roundabout) then use the
113                     first unprocessed seg in the set.  -->
114                <xsl:variable name='fromLooseEnds' select='../seg[not(contains($processedSegs,concat("|",@id,"|")))][@osma:fromCount="0"]'/>
115                <xsl:variable name='toLooseEnds' select='../seg[not(contains($processedSegs,concat("|",@id,"|")))][@osma:toCount="0"]'/>
116
117                <xsl:choose>
118                        <!-- are there any "from" loose ends? -->
119                        <xsl:when test='$fromLooseEnds'>
120                                <xsl:for-each select='$fromLooseEnds[1]'>
121                                        <xsl:call-template name='processSeg'>
122                                                <xsl:with-param name='currentSeg' select='.'/>
123                                                <xsl:with-param name='processedSegs' select='$processedSegs'/>
124                                                <xsl:with-param name='subPath' select='true()'/>
125                                                <xsl:with-param name='debug' select='"fromLooseEnd"'/>
126                                        </xsl:call-template>
127                                </xsl:for-each>
128                        </xsl:when>
129                        <!-- are there any "to" loose ends? -->
130                        <xsl:when test='$toLooseEnds'>
131                                <xsl:for-each select='$toLooseEnds[1]'>
132                                        <xsl:call-template name='processSeg'>
133                                                <xsl:with-param name='currentSeg' select='.'/>
134                                                <xsl:with-param name='processedSegs' select='$processedSegs'/>
135                                                <xsl:with-param name='subPath' select='true()'/>
136                                                <xsl:with-param name='reverse' select='true()'/>
137                                                <xsl:with-param name='debug' select='"toLooseEnd"'/>
138                                        </xsl:call-template>
139                                </xsl:for-each>
140                        </xsl:when>
141                        <xsl:otherwise>
142                                <!-- otherwise use the first unprocessed seg in the set -->
143                                <xsl:for-each select='../seg[not(contains($processedSegs,concat("|",@id,"|")))][1]'>
144                                        <xsl:call-template name='processSeg'>
145                                                <xsl:with-param name='currentSeg' select='.'/>
146                                                <xsl:with-param name='processedSegs' select='$processedSegs'/>
147                                                <xsl:with-param name='subPath' select='true()'/>
148                                                <xsl:with-param name='debug' select='"firstSegment"'/>
149                                        </xsl:call-template>
150                                </xsl:for-each>                                                                 
151                        </xsl:otherwise>
152               
153                </xsl:choose>
154        </xsl:template>   
155     
156   
157        <!-- Process a seg.  First output the seg, then add it to the processed segs list and finally start searching
158             for the next seg that needs processing -->
159        <xsl:template name='processSeg'>
160                <xsl:param name='currentSeg'/>
161                <xsl:param name='reverse'/>
162                <xsl:param name='subPath'/>
163                <xsl:param name='processedSegs'/>
164                <xsl:param name='debug'/>
165
166                <!-- Output current seg -->
167                <seg>
168                        <xsl:apply-templates select='$currentSeg/@*|$currentSeg'/>                     
169                        <!--<xsl:attribute name='id'><xsl:value-of select='$currentSeg/@id'/></xsl:attribute>-->
170                        <xsl:if test='$reverse'>
171                                <xsl:attribute name='osma:reverse'>1</xsl:attribute>
172                        </xsl:if>
173                        <xsl:if test='$subPath'>
174                                <xsl:attribute name='osma:sub-path'>1</xsl:attribute>
175                        </xsl:if>
176                        <!-- <xsl:attribute name='osma:debug'><xsl:value-of select='$debug'/></xsl:attribute> -->
177                </seg>
178
179                <!-- Add current seg to the processed segs list -->
180                <xsl:variable name='newProcessedSegs' select='concat($processedSegs,$currentSeg/@id,"|")'/>
181       
182                <xsl:choose>
183                        <xsl:when test='string-length(translate($processedSegs,"-0123456789",""))&lt;$maximumNumberOfSegs'>
184                                <!-- Start searching for next seg -->
185                                <xsl:variable name='nextSeg' select='$currentSeg/following-sibling::seg[1]'/>
186                                <xsl:variable name='alreadyProcessed' select='contains($newProcessedSegs,concat("|",$nextSeg/@id,"|"))'/>
187
188                                <xsl:variable name='currentSegToNodeId' select="key('segmentById',$currentSeg/@id)/@to" />
189                                <xsl:variable name='currentSegFromNodeId' select="key('segmentById',$currentSeg/@id)/@from" />
190                                <xsl:variable name='nextSegToNodeId' select="key('segmentById',$nextSeg/@id)/@to" />
191                                <xsl:variable name='nextSegFromNodeId' select="key('segmentById',$nextSeg/@id)/@from" />
192
193
194                                <!-- If there is another segment -->
195                                <xsl:choose>
196                                        <xsl:when test='$nextSeg and not($alreadyProcessed)'>
197                                                <xsl:choose>
198                                                        <xsl:when test='not($reverse)'>
199                                                                <xsl:choose>
200                                                                        <xsl:when test='$currentSegToNodeId=$nextSegFromNodeId'>
201                                                                                <xsl:call-template name='processSeg'>
202                                                                                        <xsl:with-param name='currentSeg' select='$nextSeg'/>
203                                                                                        <xsl:with-param name='processedSegs' select='$newProcessedSegs'/>
204                                                                                        <xsl:with-param name='debug' select='"currentSegTo=nextSegFrom"'/>
205                                                                                </xsl:call-template>
206                                                                        </xsl:when>
207                                                                        <xsl:when test='$currentSegToNodeId=$nextSegToNodeId'>
208                                                                                <xsl:call-template name='processSeg'>
209                                                                                        <xsl:with-param name='currentSeg' select='$nextSeg'/>
210                                                                                        <xsl:with-param name='reverse' select='true()'/>
211                                                                                        <xsl:with-param name='processedSegs' select='$newProcessedSegs'/>
212                                                                                        <xsl:with-param name='debug' select='"currentSegTo=nextSegTo"'/>
213                                                                                </xsl:call-template>
214                                                                        </xsl:when>
215                                                                        <xsl:otherwise> <!-- not connected to the next seg -->
216                                                                                <xsl:call-template name='linkedSeg'>
217                                                                                        <xsl:with-param name='currentSeg' select='$currentSeg'/>
218                                                                                        <xsl:with-param name='reverse' select='$reverse'/>
219                                                                                        <xsl:with-param name='processedSegs' select='$newProcessedSegs'/>
220                                                                                </xsl:call-template>                                                   
221                                                                        </xsl:otherwise>
222                                                                </xsl:choose>
223                                                        </xsl:when>
224                                                        <xsl:otherwise> <!-- $reverse -->
225                                                                <xsl:choose>
226                                                                        <xsl:when test='$currentSegFromNodeId=$nextSegFromNodeId'>
227                                                                                <xsl:call-template name='processSeg'>
228                                                                                        <xsl:with-param name='currentSeg' select='$nextSeg'/>
229                                                                                        <xsl:with-param name='processedSegs' select='$newProcessedSegs'/>
230                                                                                        <xsl:with-param name='debug' select='"currentSegFrom=nextSegFrom"'/>
231                                                                                </xsl:call-template>
232                                                                        </xsl:when>
233                                                                        <xsl:when test='$currentSegFromNodeId=$nextSegToNodeId'>
234                                                                                <xsl:call-template name='processSeg'>
235                                                                                        <xsl:with-param name='currentSeg' select='$nextSeg'/>
236                                                                                        <xsl:with-param name='reverse' select='true()'/>
237                                                                                        <xsl:with-param name='processedSegs' select='$newProcessedSegs'/>
238                                                                                        <xsl:with-param name='debug' select='"currentSegFrom=nextSegTo"'/>
239                                                                                </xsl:call-template>
240                                                                        </xsl:when>
241                                                                        <xsl:otherwise> <!-- not connected to the next seg -->
242                                                                                <xsl:call-template name='linkedSeg'>
243                                                                                        <xsl:with-param name='currentSeg' select='$currentSeg'/>
244                                                                                        <xsl:with-param name='reverse' select='$reverse'/>
245                                                                                        <xsl:with-param name='processedSegs' select='$newProcessedSegs'/>
246                                                                                </xsl:call-template>   
247                                                                        </xsl:otherwise>
248                                                                </xsl:choose>                           
249                                                        </xsl:otherwise>
250                                                </xsl:choose>
251                                        </xsl:when>
252                                        <xsl:otherwise> <!-- there's no next seg that has not already been processed -->
253                                                <xsl:call-template name='linkedSeg'>
254                                                        <xsl:with-param name='currentSeg' select='$currentSeg'/>
255                                                        <xsl:with-param name='reverse' select='$reverse'/>
256                                                        <xsl:with-param name='processedSegs' select='$newProcessedSegs'/>
257                                                </xsl:call-template>
258                                        </xsl:otherwise>               
259                                </xsl:choose>                   
260                        </xsl:when>
261                        <xsl:otherwise> <!-- If there are too many segments, output the remainder in original order -->
262                                <xsl:for-each select='../seg[not(contains($newProcessedSegs,concat("|",@id,"|")))]'>
263                                        <seg>
264                                                <xsl:apply-templates select='@*|node()'/>                       
265                                        </seg>
266                                </xsl:for-each>
267                        </xsl:otherwise>
268                </xsl:choose>
269        </xsl:template>
270
271
272        <!-- Find any linked segment -->
273        <!-- The next seg was not connected to the current seg, so now we need to look for any other seg that is connected to
274             the current seg.  If we can't find one then we'll just take the next loose-end.  -->
275        <xsl:template name='linkedSeg'>
276                <xsl:param name='currentSeg'/>
277                <xsl:param name='reverse'/>
278                <xsl:param name='processedSegs'/>
279
280                <xsl:variable name='currentSegToNodeId' select="key('segmentById',$currentSeg/@id)/@to" />
281                <xsl:variable name='currentSegFromNodeId' select="key('segmentById',$currentSeg/@id)/@from" />
282
283                <!-- Find the any segment that matches now -->
284                <xsl:variable name='unprocessedSegs' select='../seg[not($currentSeg/@id=@id)][not(contains($processedSegs,concat("|",@id,"|")))]'/>
285                <xsl:variable name='linkedToFromSeg' select='$unprocessedSegs[$currentSegToNodeId=key("segmentById",@id)/@from]' />
286                <xsl:variable name='linkedToToSeg' select='$unprocessedSegs[$currentSegToNodeId=key("segmentById",@id)/@to]' />
287                <xsl:variable name='linkedFromFromSeg' select='$unprocessedSegs[$currentSegFromNodeId=key("segmentById",@id)/@from]' />
288                <xsl:variable name='linkedFromToSeg' select='$unprocessedSegs[$currentSegFromNodeId=key("segmentById",@id)/@to]' />
289
290                <xsl:choose>
291                        <xsl:when test='not($reverse)'>
292                                <xsl:choose>
293                                        <xsl:when test='$linkedToFromSeg'>
294                                                <xsl:call-template name='processSeg'>
295                                                        <xsl:with-param name='currentSeg' select='$linkedToFromSeg'/>
296                                                        <xsl:with-param name='processedSegs' select='$processedSegs'/>
297                                                        <xsl:with-param name='debug' select='"linkedToFromSeg"'/>
298                                                </xsl:call-template>   
299                                        </xsl:when>
300                                        <xsl:when test='$linkedToToSeg'>
301                                                <xsl:call-template name='processSeg'>
302                                                        <xsl:with-param name='currentSeg' select='$linkedToToSeg'/>
303                                                        <xsl:with-param name='reverse' select='true()'/>
304                                                        <xsl:with-param name='processedSegs' select='$processedSegs'/>
305                                                        <xsl:with-param name='debug' select='"linkedToToSeg"'/>
306                                                </xsl:call-template>
307                                        </xsl:when>
308                                        <xsl:otherwise> <!-- not linked -->
309                                                <xsl:call-template name='nextSeg'>
310                                                        <xsl:with-param name='processedSegs' select='$processedSegs'/>
311                                                        <xsl:with-param name='debug' select='"nextSeg-ToToSeg"'/>
312                                                </xsl:call-template>                                   
313                                        </xsl:otherwise>
314                                </xsl:choose>
315                        </xsl:when>
316                        <xsl:otherwise> <!-- $reverse -->
317                                <xsl:choose>
318                                        <xsl:when test='$linkedFromToSeg'>
319                                                <xsl:call-template name='processSeg'>
320                                                        <xsl:with-param name='currentSeg' select='$linkedFromToSeg'/>
321                                                        <xsl:with-param name='reverse' select='true()'/>
322                                                        <xsl:with-param name='processedSegs' select='$processedSegs'/>
323                                                        <xsl:with-param name='debug' select='"linkedFromToSeg"'/>
324                                                </xsl:call-template>   
325                                        </xsl:when>
326                                        <xsl:when test='$linkedFromFromSeg'>
327                                                <xsl:call-template name='processSeg'>
328                                                        <xsl:with-param name='currentSeg' select='$linkedFromFromSeg'/>
329                                                        <xsl:with-param name='processedSegs' select='$processedSegs'/>
330                                                        <xsl:with-param name='debug' select='"linkedFromFromSeg"'/>
331                                                </xsl:call-template>   
332                                        </xsl:when>
333                                        <xsl:otherwise> <!-- not linked -->
334                                                <xsl:call-template name='nextSeg'>
335                                                        <xsl:with-param name='processedSegs' select='$processedSegs'/>
336                                                        <xsl:with-param name='debug' select='"nextSeg-FromFromSeg"'/>
337                                                </xsl:call-template>                                   
338                                        </xsl:otherwise>
339                                </xsl:choose>
340                        </xsl:otherwise>
341                </xsl:choose>   
342        </xsl:template>
343
344
345        <!-- Suppress original seg elements -->
346        <xsl:template match='seg' />
347
348        <!-- Suppress created by tags -->
349        <xsl:template match="tag[@k='created_by']" />
350
351        <!-- Suppress timestamp attributes -->
352        <xsl:template match="@timestamp" />
353
354        <!-- Identity Transform -->
355        <xsl:template match="@*|node()">
356          <xsl:copy>
357            <xsl:apply-templates select="@*|node()"/>
358          </xsl:copy>
359        </xsl:template>
360
361</xsl:stylesheet>
Note: See TracBrowser for help on using the repository browser.