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

Last change on this file since 5992 was 2741, checked in by deelkar, 13 years ago

Reduce the maximum segments limit to 400 again because of possible endless recursion.

File size: 16.3 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    <!-- decreased to 400 from 600 by Deelkar because of "possible endless recursion. since frollo runs first currently not really needed at 600 -->
70
71        <xsl:variable name='maximumNumberOfSegs' select='"400"'/>
72               
73
74        <!-- Keys -->
75        <!-- Lookup for segments by segment id -->
76    <xsl:key name="segmentById" match="/osm/segment" use="@id"/>
77   
78   
79    <!-- Add an attribute to the osm element to indicate that this file has been frolloised -->
80    <xsl:template match='/osm'>
81                <osm>
82                        <xsl:attribute name='osma:frollo'>1</xsl:attribute>
83                        <xsl:apply-templates select='@*|node()'/>
84                </osm>
85    </xsl:template>
86   
87   
88    <!-- Process each way -->
89        <xsl:template match='way'>
90                <way>
91                        <xsl:apply-templates select='@*'/>
92
93                        <!-- If there are any segs, then make the first seg the context node and then find the next loose end -->
94                        <xsl:for-each select='seg[1]'>
95                                <xsl:call-template name='nextSeg'>
96                                        <xsl:with-param name='processedSegs' select='"|"'/>
97                                        <xsl:with-param name='debug' select='"firstSeg"'/>
98                                </xsl:call-template>                   
99                        </xsl:for-each>
100
101                        <xsl:apply-templates select='*'/>
102                </way>
103        </xsl:template>   
104   
105   
106        <!-- Process the next most suitable seg.  This will either be the first loose end, or, if there are no more unprocessed
107             loose ends then it will be the next unprocessed seg in original seg order. -->
108        <xsl:template name='nextSeg'>
109                <xsl:param name='processedSegs'/>
110                <xsl:param name='debug'/>
111               
112                <!-- A loose-end is any seg that has no other segs connecting to/from it in this way.  We prefer "from" loose-ends but
113                     will be happy with "to" loose-ends if necessary.  If there are no loose-ends (eg a roundabout) then use the
114                     first unprocessed seg in the set.  -->
115                <xsl:variable name='fromLooseEnds' select='../seg[not(contains($processedSegs,concat("|",@id,"|")))][@osma:fromCount="0"]'/>
116                <xsl:variable name='toLooseEnds' select='../seg[not(contains($processedSegs,concat("|",@id,"|")))][@osma:toCount="0"]'/>
117
118                <xsl:choose>
119                        <!-- are there any "from" loose ends? -->
120                        <xsl:when test='$fromLooseEnds'>
121                                <xsl:for-each select='$fromLooseEnds[1]'>
122                                        <xsl:call-template name='processSeg'>
123                                                <xsl:with-param name='currentSeg' select='.'/>
124                                                <xsl:with-param name='processedSegs' select='$processedSegs'/>
125                                                <xsl:with-param name='subPath' select='true()'/>
126                                                <xsl:with-param name='debug' select='"fromLooseEnd"'/>
127                                        </xsl:call-template>
128                                </xsl:for-each>
129                        </xsl:when>
130                        <!-- are there any "to" loose ends? -->
131                        <xsl:when test='$toLooseEnds'>
132                                <xsl:for-each select='$toLooseEnds[1]'>
133                                        <xsl:call-template name='processSeg'>
134                                                <xsl:with-param name='currentSeg' select='.'/>
135                                                <xsl:with-param name='processedSegs' select='$processedSegs'/>
136                                                <xsl:with-param name='subPath' select='true()'/>
137                                                <xsl:with-param name='reverse' select='true()'/>
138                                                <xsl:with-param name='debug' select='"toLooseEnd"'/>
139                                        </xsl:call-template>
140                                </xsl:for-each>
141                        </xsl:when>
142                        <xsl:otherwise>
143                                <!-- otherwise use the first unprocessed seg in the set -->
144                                <xsl:for-each select='../seg[not(contains($processedSegs,concat("|",@id,"|")))][1]'>
145                                        <xsl:call-template name='processSeg'>
146                                                <xsl:with-param name='currentSeg' select='.'/>
147                                                <xsl:with-param name='processedSegs' select='$processedSegs'/>
148                                                <xsl:with-param name='subPath' select='true()'/>
149                                                <xsl:with-param name='debug' select='"firstSegment"'/>
150                                        </xsl:call-template>
151                                </xsl:for-each>                                                                 
152                        </xsl:otherwise>
153               
154                </xsl:choose>
155        </xsl:template>   
156     
157   
158        <!-- Process a seg.  First output the seg, then add it to the processed segs list and finally start searching
159             for the next seg that needs processing -->
160        <xsl:template name='processSeg'>
161                <xsl:param name='currentSeg'/>
162                <xsl:param name='reverse'/>
163                <xsl:param name='subPath'/>
164                <xsl:param name='processedSegs'/>
165                <xsl:param name='debug'/>
166
167                <!-- Output current seg -->
168                <seg>
169                        <xsl:apply-templates select='$currentSeg/@*|$currentSeg'/>                     
170                        <!--<xsl:attribute name='id'><xsl:value-of select='$currentSeg/@id'/></xsl:attribute>-->
171                        <xsl:if test='$reverse'>
172                                <xsl:attribute name='osma:reverse'>1</xsl:attribute>
173                        </xsl:if>
174                        <xsl:if test='$subPath'>
175                                <xsl:attribute name='osma:sub-path'>1</xsl:attribute>
176                        </xsl:if>
177                        <!-- <xsl:attribute name='osma:debug'><xsl:value-of select='$debug'/></xsl:attribute> -->
178                </seg>
179
180                <!-- Add current seg to the processed segs list -->
181                <xsl:variable name='newProcessedSegs' select='concat($processedSegs,$currentSeg/@id,"|")'/>
182       
183                <xsl:choose>
184                        <xsl:when test='string-length(translate($processedSegs,"-0123456789",""))&lt;$maximumNumberOfSegs'>
185                                <!-- Start searching for next seg -->
186                                <xsl:variable name='nextSeg' select='$currentSeg/following-sibling::seg[1]'/>
187                                <xsl:variable name='alreadyProcessed' select='contains($newProcessedSegs,concat("|",$nextSeg/@id,"|"))'/>
188
189                                <xsl:variable name='currentSegToNodeId' select="key('segmentById',$currentSeg/@id)/@to" />
190                                <xsl:variable name='currentSegFromNodeId' select="key('segmentById',$currentSeg/@id)/@from" />
191                                <xsl:variable name='nextSegToNodeId' select="key('segmentById',$nextSeg/@id)/@to" />
192                                <xsl:variable name='nextSegFromNodeId' select="key('segmentById',$nextSeg/@id)/@from" />
193
194
195                                <!-- If there is another segment -->
196                                <xsl:choose>
197                                        <xsl:when test='$nextSeg and not($alreadyProcessed)'>
198                                                <xsl:choose>
199                                                        <xsl:when test='not($reverse)'>
200                                                                <xsl:choose>
201                                                                        <xsl:when test='$currentSegToNodeId=$nextSegFromNodeId'>
202                                                                                <xsl:call-template name='processSeg'>
203                                                                                        <xsl:with-param name='currentSeg' select='$nextSeg'/>
204                                                                                        <xsl:with-param name='processedSegs' select='$newProcessedSegs'/>
205                                                                                        <xsl:with-param name='debug' select='"currentSegTo=nextSegFrom"'/>
206                                                                                </xsl:call-template>
207                                                                        </xsl:when>
208                                                                        <xsl:when test='$currentSegToNodeId=$nextSegToNodeId'>
209                                                                                <xsl:call-template name='processSeg'>
210                                                                                        <xsl:with-param name='currentSeg' select='$nextSeg'/>
211                                                                                        <xsl:with-param name='reverse' select='true()'/>
212                                                                                        <xsl:with-param name='processedSegs' select='$newProcessedSegs'/>
213                                                                                        <xsl:with-param name='debug' select='"currentSegTo=nextSegTo"'/>
214                                                                                </xsl:call-template>
215                                                                        </xsl:when>
216                                                                        <xsl:otherwise> <!-- not connected to the next seg -->
217                                                                                <xsl:call-template name='linkedSeg'>
218                                                                                        <xsl:with-param name='currentSeg' select='$currentSeg'/>
219                                                                                        <xsl:with-param name='reverse' select='$reverse'/>
220                                                                                        <xsl:with-param name='processedSegs' select='$newProcessedSegs'/>
221                                                                                </xsl:call-template>                                                   
222                                                                        </xsl:otherwise>
223                                                                </xsl:choose>
224                                                        </xsl:when>
225                                                        <xsl:otherwise> <!-- $reverse -->
226                                                                <xsl:choose>
227                                                                        <xsl:when test='$currentSegFromNodeId=$nextSegFromNodeId'>
228                                                                                <xsl:call-template name='processSeg'>
229                                                                                        <xsl:with-param name='currentSeg' select='$nextSeg'/>
230                                                                                        <xsl:with-param name='processedSegs' select='$newProcessedSegs'/>
231                                                                                        <xsl:with-param name='debug' select='"currentSegFrom=nextSegFrom"'/>
232                                                                                </xsl:call-template>
233                                                                        </xsl:when>
234                                                                        <xsl:when test='$currentSegFromNodeId=$nextSegToNodeId'>
235                                                                                <xsl:call-template name='processSeg'>
236                                                                                        <xsl:with-param name='currentSeg' select='$nextSeg'/>
237                                                                                        <xsl:with-param name='reverse' select='true()'/>
238                                                                                        <xsl:with-param name='processedSegs' select='$newProcessedSegs'/>
239                                                                                        <xsl:with-param name='debug' select='"currentSegFrom=nextSegTo"'/>
240                                                                                </xsl:call-template>
241                                                                        </xsl:when>
242                                                                        <xsl:otherwise> <!-- not connected to the next seg -->
243                                                                                <xsl:call-template name='linkedSeg'>
244                                                                                        <xsl:with-param name='currentSeg' select='$currentSeg'/>
245                                                                                        <xsl:with-param name='reverse' select='$reverse'/>
246                                                                                        <xsl:with-param name='processedSegs' select='$newProcessedSegs'/>
247                                                                                </xsl:call-template>   
248                                                                        </xsl:otherwise>
249                                                                </xsl:choose>                           
250                                                        </xsl:otherwise>
251                                                </xsl:choose>
252                                        </xsl:when>
253                                        <xsl:otherwise> <!-- there's no next seg that has not already been processed -->
254                                                <xsl:call-template name='linkedSeg'>
255                                                        <xsl:with-param name='currentSeg' select='$currentSeg'/>
256                                                        <xsl:with-param name='reverse' select='$reverse'/>
257                                                        <xsl:with-param name='processedSegs' select='$newProcessedSegs'/>
258                                                </xsl:call-template>
259                                        </xsl:otherwise>               
260                                </xsl:choose>                   
261                        </xsl:when>
262                        <xsl:otherwise> <!-- If there are too many segments, output the remainder in original order -->
263                                <xsl:for-each select='../seg[not(contains($newProcessedSegs,concat("|",@id,"|")))]'>
264                                        <seg>
265                                                <xsl:apply-templates select='@*|node()'/>                       
266                                        </seg>
267                                </xsl:for-each>
268                        </xsl:otherwise>
269                </xsl:choose>
270        </xsl:template>
271
272
273        <!-- Find any linked segment -->
274        <!-- The next seg was not connected to the current seg, so now we need to look for any other seg that is connected to
275             the current seg.  If we can't find one then we'll just take the next loose-end.  -->
276        <xsl:template name='linkedSeg'>
277                <xsl:param name='currentSeg'/>
278                <xsl:param name='reverse'/>
279                <xsl:param name='processedSegs'/>
280
281                <xsl:variable name='currentSegToNodeId' select="key('segmentById',$currentSeg/@id)/@to" />
282                <xsl:variable name='currentSegFromNodeId' select="key('segmentById',$currentSeg/@id)/@from" />
283
284                <!-- Find the any segment that matches now -->
285                <xsl:variable name='unprocessedSegs' select='../seg[not($currentSeg/@id=@id)][not(contains($processedSegs,concat("|",@id,"|")))]'/>
286                <xsl:variable name='linkedToFromSeg' select='$unprocessedSegs[$currentSegToNodeId=key("segmentById",@id)/@from]' />
287                <xsl:variable name='linkedToToSeg' select='$unprocessedSegs[$currentSegToNodeId=key("segmentById",@id)/@to]' />
288                <xsl:variable name='linkedFromFromSeg' select='$unprocessedSegs[$currentSegFromNodeId=key("segmentById",@id)/@from]' />
289                <xsl:variable name='linkedFromToSeg' select='$unprocessedSegs[$currentSegFromNodeId=key("segmentById",@id)/@to]' />
290
291                <xsl:choose>
292                        <xsl:when test='not($reverse)'>
293                                <xsl:choose>
294                                        <xsl:when test='$linkedToFromSeg'>
295                                                <xsl:call-template name='processSeg'>
296                                                        <xsl:with-param name='currentSeg' select='$linkedToFromSeg'/>
297                                                        <xsl:with-param name='processedSegs' select='$processedSegs'/>
298                                                        <xsl:with-param name='debug' select='"linkedToFromSeg"'/>
299                                                </xsl:call-template>   
300                                        </xsl:when>
301                                        <xsl:when test='$linkedToToSeg'>
302                                                <xsl:call-template name='processSeg'>
303                                                        <xsl:with-param name='currentSeg' select='$linkedToToSeg'/>
304                                                        <xsl:with-param name='reverse' select='true()'/>
305                                                        <xsl:with-param name='processedSegs' select='$processedSegs'/>
306                                                        <xsl:with-param name='debug' select='"linkedToToSeg"'/>
307                                                </xsl:call-template>
308                                        </xsl:when>
309                                        <xsl:otherwise> <!-- not linked -->
310                                                <xsl:call-template name='nextSeg'>
311                                                        <xsl:with-param name='processedSegs' select='$processedSegs'/>
312                                                        <xsl:with-param name='debug' select='"nextSeg-ToToSeg"'/>
313                                                </xsl:call-template>                                   
314                                        </xsl:otherwise>
315                                </xsl:choose>
316                        </xsl:when>
317                        <xsl:otherwise> <!-- $reverse -->
318                                <xsl:choose>
319                                        <xsl:when test='$linkedFromToSeg'>
320                                                <xsl:call-template name='processSeg'>
321                                                        <xsl:with-param name='currentSeg' select='$linkedFromToSeg'/>
322                                                        <xsl:with-param name='reverse' select='true()'/>
323                                                        <xsl:with-param name='processedSegs' select='$processedSegs'/>
324                                                        <xsl:with-param name='debug' select='"linkedFromToSeg"'/>
325                                                </xsl:call-template>   
326                                        </xsl:when>
327                                        <xsl:when test='$linkedFromFromSeg'>
328                                                <xsl:call-template name='processSeg'>
329                                                        <xsl:with-param name='currentSeg' select='$linkedFromFromSeg'/>
330                                                        <xsl:with-param name='processedSegs' select='$processedSegs'/>
331                                                        <xsl:with-param name='debug' select='"linkedFromFromSeg"'/>
332                                                </xsl:call-template>   
333                                        </xsl:when>
334                                        <xsl:otherwise> <!-- not linked -->
335                                                <xsl:call-template name='nextSeg'>
336                                                        <xsl:with-param name='processedSegs' select='$processedSegs'/>
337                                                        <xsl:with-param name='debug' select='"nextSeg-FromFromSeg"'/>
338                                                </xsl:call-template>                                   
339                                        </xsl:otherwise>
340                                </xsl:choose>
341                        </xsl:otherwise>
342                </xsl:choose>   
343        </xsl:template>
344
345
346        <!-- Suppress original seg elements -->
347        <xsl:template match='seg' />
348
349        <!-- Suppress created by tags -->
350        <xsl:template match="tag[@k='created_by']" />
351
352        <!-- Suppress timestamp attributes -->
353        <xsl:template match="@timestamp" />
354
355        <!-- Identity Transform -->
356        <xsl:template match="@*|node()">
357          <xsl:copy>
358            <xsl:apply-templates select="@*|node()"/>
359          </xsl:copy>
360        </xsl:template>
361
362</xsl:stylesheet>
Note: See TracBrowser for help on using the repository browser.