Check out the latest version of Routino: svn co http://routino.org/svn/trunk routino
Annotation of /trunk/src/optimiser.c
Parent Directory
|
Revision Log
Revision 1634 -
(hide annotations)
(download)
(as text)
Sat Mar 28 14:23:23 2015 UTC (9 years, 11 months ago) by amb
File MIME type: text/x-csrc
File size: 49666 byte(s)
Sat Mar 28 14:23:23 2015 UTC (9 years, 11 months ago) by amb
File MIME type: text/x-csrc
File size: 49666 byte(s)
The new FindStartRoutes() function does not need to be so complicated.
1 | amb | 2 | /*************************************** |
2 | Routing optimiser. | ||
3 | amb | 151 | |
4 | Part of the Routino routing software. | ||
5 | amb | 2 | ******************/ /****************** |
6 | amb | 1625 | This file Copyright 2008-2015 Andrew M. Bishop |
7 | amb | 2 | |
8 | amb | 151 | This program is free software: you can redistribute it and/or modify |
9 | it under the terms of the GNU Affero General Public License as published by | ||
10 | the Free Software Foundation, either version 3 of the License, or | ||
11 | (at your option) any later version. | ||
12 | |||
13 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | GNU Affero General Public License for more details. | ||
17 | |||
18 | You should have received a copy of the GNU Affero General Public License | ||
19 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
20 | amb | 2 | ***************************************/ |
21 | |||
22 | |||
23 | amb | 96 | #include "types.h" |
24 | amb | 109 | #include "nodes.h" |
25 | #include "segments.h" | ||
26 | #include "ways.h" | ||
27 | amb | 596 | #include "relations.h" |
28 | amb | 449 | |
29 | amb | 519 | #include "logging.h" |
30 | amb | 449 | #include "functions.h" |
31 | amb | 532 | #include "fakes.h" |
32 | amb | 28 | #include "results.h" |
33 | amb | 2 | |
34 | amb | 26 | |
35 | amb | 1278 | /*+ To help when debugging +*/ |
36 | #define DEBUG 0 | ||
37 | |||
38 | |||
39 | amb | 685 | /* Global variables */ |
40 | |||
41 | amb | 113 | /*+ The option not to print any progress information. +*/ |
42 | amb | 107 | extern int option_quiet; |
43 | amb | 2 | |
44 | amb | 113 | /*+ The option to calculate the quickest route insted of the shortest. +*/ |
45 | extern int option_quickest; | ||
46 | amb | 31 | |
47 | amb | 113 | |
48 | amb | 685 | /* Local functions */ |
49 | |||
50 | amb | 1497 | static index_t FindSuperSegment(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,index_t finish_node,index_t finish_segment); |
51 | static Results *FindSuperRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,index_t start_node,index_t finish_node); | ||
52 | amb | 685 | |
53 | |||
54 | amb | 2 | /*++++++++++++++++++++++++++++++++++++++ |
55 | amb | 727 | Find the optimum route between two nodes not passing through a super-node. |
56 | amb | 2 | |
57 | amb | 238 | Results *FindNormalRoute Returns a set of results. |
58 | amb | 26 | |
59 | Nodes *nodes The set of nodes to use. | ||
60 | |||
61 | Segments *segments The set of segments to use. | ||
62 | |||
63 | amb | 54 | Ways *ways The set of ways to use. |
64 | |||
65 | amb | 542 | Relations *relations The set of relations to use. |
66 | |||
67 | amb | 721 | Profile *profile The profile containing the transport type, speeds and allowed highways. |
68 | |||
69 | amb | 605 | index_t start_node The start node. |
70 | amb | 2 | |
71 | amb | 605 | index_t prev_segment The previous segment before the start node. |
72 | amb | 54 | |
73 | amb | 605 | index_t finish_node The finish node. |
74 | amb | 2 | ++++++++++++++++++++++++++++++++++++++*/ |
75 | |||
76 | amb | 723 | Results *FindNormalRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,index_t start_node,index_t prev_segment,index_t finish_node) |
77 | amb | 2 | { |
78 | amb | 31 | Results *results; |
79 | amb | 469 | Queue *queue; |
80 | amb | 166 | score_t finish_score; |
81 | amb | 219 | double finish_lat,finish_lon; |
82 | amb | 605 | Result *finish_result; |
83 | amb | 469 | Result *result1,*result2; |
84 | amb | 1068 | int force_uturn=0; |
85 | amb | 2 | |
86 | amb | 1278 | #if DEBUG |
87 | printf(" FindNormalRoute(...,start_node=%"Pindex_t" prev_segment=%"Pindex_t" finish_node=%"Pindex_t")\n",start_node,prev_segment,finish_node); | ||
88 | #endif | ||
89 | |||
90 | amb | 10 | /* Set up the finish conditions */ |
91 | |||
92 | amb | 176 | finish_score=INF_SCORE; |
93 | amb | 605 | finish_result=NULL; |
94 | amb | 10 | |
95 | amb | 605 | if(IsFakeNode(finish_node)) |
96 | GetFakeLatLong(finish_node,&finish_lat,&finish_lon); | ||
97 | amb | 303 | else |
98 | amb | 1291 | GetLatLong(nodes,finish_node,NULL,&finish_lat,&finish_lon); |
99 | amb | 119 | |
100 | amb | 165 | /* Create the list of results and insert the first node into the queue */ |
101 | amb | 2 | |
102 | amb | 1286 | results=NewResultsList(8); |
103 | amb | 1289 | queue=NewQueueList(8); |
104 | amb | 2 | |
105 | amb | 605 | results->start_node=start_node; |
106 | amb | 617 | results->prev_segment=prev_segment; |
107 | amb | 165 | |
108 | amb | 735 | result1=InsertResult(results,results->start_node,results->prev_segment); |
109 | amb | 28 | |
110 | amb | 1289 | InsertInQueue(queue,result1,0); |
111 | amb | 236 | |
112 | amb | 1068 | /* Check for barrier at start waypoint - must perform U-turn */ |
113 | |||
114 | if(prev_segment!=NO_SEGMENT && !IsFakeNode(start_node)) | ||
115 | { | ||
116 | amb | 1078 | Node *startp=LookupNode(nodes,start_node,1); |
117 | amb | 1068 | |
118 | amb | 1078 | if(!(startp->allow&profile->allow)) |
119 | amb | 1068 | force_uturn=1; |
120 | } | ||
121 | |||
122 | amb | 2 | /* Loop across all nodes in the queue */ |
123 | |||
124 | amb | 236 | while((result1=PopFromQueue(queue))) |
125 | amb | 2 | { |
126 | amb | 885 | Node *node1p=NULL; |
127 | amb | 1078 | Segment *segmentp; |
128 | amb | 637 | index_t node1,seg1,seg1r; |
129 | amb | 608 | index_t turnrelation=NO_RELATION; |
130 | amb | 594 | |
131 | amb | 680 | /* score must be better than current best score */ |
132 | amb | 1066 | if(result1->score>=finish_score) |
133 | amb | 119 | continue; |
134 | |||
135 | amb | 43 | node1=result1->node; |
136 | amb | 605 | seg1=result1->segment; |
137 | amb | 2 | |
138 | amb | 637 | if(IsFakeSegment(seg1)) |
139 | seg1r=IndexRealSegment(seg1); | ||
140 | else | ||
141 | seg1r=seg1; | ||
142 | |||
143 | amb | 885 | if(!IsFakeNode(node1)) |
144 | node1p=LookupNode(nodes,node1,1); | ||
145 | |||
146 | amb | 680 | /* lookup if a turn restriction applies */ |
147 | amb | 885 | if(profile->turns && node1p && IsTurnRestrictedNode(node1p)) |
148 | amb | 637 | turnrelation=FindFirstTurnRelation2(relations,node1,seg1r); |
149 | amb | 596 | |
150 | amb | 680 | /* Loop across all segments */ |
151 | |||
152 | amb | 303 | if(IsFakeNode(node1)) |
153 | amb | 1078 | segmentp=FirstFakeSegment(node1); |
154 | amb | 303 | else |
155 | amb | 1078 | segmentp=FirstSegment(segments,node1p,1); |
156 | amb | 2 | |
157 | amb | 1078 | while(segmentp) |
158 | amb | 2 | { |
159 | amb | 885 | Node *node2p=NULL; |
160 | amb | 1078 | Way *wayp; |
161 | amb | 637 | index_t node2,seg2,seg2r; |
162 | amb | 298 | score_t segment_pref,segment_score,cumulative_score; |
163 | int i; | ||
164 | amb | 59 | |
165 | amb | 1078 | node2=OtherNode(segmentp,node1); /* need this here because we use node2 at the end of the loop */ |
166 | amb | 303 | |
167 | amb | 680 | /* must be a normal segment */ |
168 | amb | 1078 | if(!IsNormalSegment(segmentp)) |
169 | amb | 90 | goto endloop; |
170 | |||
171 | amb | 680 | /* must obey one-way restrictions (unless profile allows) */ |
172 | amb | 1078 | if(profile->oneway && IsOnewayTo(segmentp,node1)) |
173 | amb | 1497 | { |
174 | if(profile->allow!=Transports_Bicycle) | ||
175 | goto endloop; | ||
176 | amb | 64 | |
177 | amb | 1497 | wayp=LookupWay(ways,segmentp->way,1); |
178 | |||
179 | amb | 1559 | if(!(wayp->type&Highway_CycleBothWays)) |
180 | amb | 1497 | goto endloop; |
181 | } | ||
182 | |||
183 | amb | 605 | if(IsFakeNode(node1) || IsFakeNode(node2)) |
184 | amb | 637 | { |
185 | amb | 1078 | seg2 =IndexFakeSegment(segmentp); |
186 | amb | 637 | seg2r=IndexRealSegment(seg2); |
187 | } | ||
188 | amb | 605 | else |
189 | amb | 637 | { |
190 | amb | 1078 | seg2 =IndexSegment(segments,segmentp); |
191 | amb | 637 | seg2r=seg2; |
192 | } | ||
193 | amb | 603 | |
194 | amb | 1068 | /* must perform U-turn in special cases */ |
195 | if(force_uturn && node1==results->start_node) | ||
196 | { | ||
197 | if(seg2r!=result1->segment) | ||
198 | goto endloop; | ||
199 | } | ||
200 | else | ||
201 | /* must not perform U-turn (unless profile allows) */ | ||
202 | if(profile->turns && (seg1==seg2 || seg1==seg2r || seg1r==seg2 || (seg1r==seg2r && IsFakeUTurn(seg1,seg2)))) | ||
203 | goto endloop; | ||
204 | amb | 636 | |
205 | amb | 680 | /* must obey turn relations */ |
206 | amb | 637 | if(turnrelation!=NO_RELATION && !IsTurnAllowed(relations,turnrelation,node1,seg1r,seg2r,profile->allow)) |
207 | amb | 608 | goto endloop; |
208 | amb | 596 | |
209 | amb | 885 | if(!IsFakeNode(node2)) |
210 | node2p=LookupNode(nodes,node2,2); | ||
211 | |||
212 | amb | 723 | /* must not pass over super-node */ |
213 | amb | 885 | if(node2!=finish_node && node2p && IsSuperNode(node2p)) |
214 | amb | 238 | goto endloop; |
215 | |||
216 | amb | 1078 | wayp=LookupWay(ways,segmentp->way,1); |
217 | amb | 54 | |
218 | amb | 680 | /* mode of transport must be allowed on the highway */ |
219 | amb | 1078 | if(!(wayp->allow&profile->allow)) |
220 | amb | 54 | goto endloop; |
221 | |||
222 | amb | 680 | /* must obey weight restriction (if exists) */ |
223 | amb | 1078 | if(wayp->weight && wayp->weight<profile->weight) |
224 | amb | 135 | goto endloop; |
225 | |||
226 | amb | 1066 | /* must obey height/width/length restriction (if exist) */ |
227 | amb | 1078 | if((wayp->height && wayp->height<profile->height) || |
228 | (wayp->width && wayp->width <profile->width ) || | ||
229 | (wayp->length && wayp->length<profile->length)) | ||
230 | amb | 135 | goto endloop; |
231 | |||
232 | amb | 1078 | segment_pref=profile->highway[HIGHWAY(wayp->type)]; |
233 | amb | 298 | |
234 | amb | 1066 | /* highway preferences must allow this highway */ |
235 | if(segment_pref==0) | ||
236 | goto endloop; | ||
237 | |||
238 | amb | 298 | for(i=1;i<Property_Count;i++) |
239 | amb | 1550 | if(ways->file.props & PROPERTIES(i)) |
240 | { | ||
241 | if(wayp->props & PROPERTIES(i)) | ||
242 | segment_pref*=profile->props_yes[i]; | ||
243 | else | ||
244 | segment_pref*=profile->props_no[i]; | ||
245 | } | ||
246 | amb | 298 | |
247 | amb | 680 | /* profile preferences must allow this highway */ |
248 | amb | 298 | if(segment_pref==0) |
249 | goto endloop; | ||
250 | |||
251 | amb | 1068 | /* mode of transport must be allowed through node2 unless it is the final node */ |
252 | if(node2p && node2!=finish_node && !(node2p->allow&profile->allow)) | ||
253 | amb | 885 | goto endloop; |
254 | amb | 469 | |
255 | amb | 1625 | /* calculate the score for the segment and cumulative */ |
256 | amb | 166 | if(option_quickest==0) |
257 | amb | 1168 | segment_score=(score_t)DISTANCE(segmentp->distance)/segment_pref; |
258 | amb | 166 | else |
259 | amb | 1078 | segment_score=(score_t)Duration(segmentp,wayp,profile)/segment_pref; |
260 | amb | 59 | |
261 | amb | 170 | cumulative_score=result1->score+segment_score; |
262 | amb | 166 | |
263 | amb | 680 | /* score must be better than current best score */ |
264 | amb | 1066 | if(cumulative_score>=finish_score) |
265 | amb | 2 | goto endloop; |
266 | |||
267 | amb | 1625 | /* find whether the node/segment combination already exists */ |
268 | amb | 605 | result2=FindResult(results,node2,seg2); |
269 | amb | 42 | |
270 | amb | 680 | if(!result2) /* New end node/segment combination */ |
271 | amb | 2 | { |
272 | amb | 605 | result2=InsertResult(results,node2,seg2); |
273 | result2->prev=result1; | ||
274 | amb | 170 | result2->score=cumulative_score; |
275 | amb | 2 | } |
276 | amb | 605 | else if(cumulative_score<result2->score) /* New score for end node/segment combination is better */ |
277 | amb | 2 | { |
278 | amb | 605 | result2->prev=result1; |
279 | amb | 170 | result2->score=cumulative_score; |
280 | amb | 605 | result2->segment=seg2; |
281 | amb | 1217 | } |
282 | else | ||
283 | goto endloop; | ||
284 | amb | 166 | |
285 | amb | 1217 | if(node2==finish_node) |
286 | { | ||
287 | finish_score=cumulative_score; | ||
288 | finish_result=result2; | ||
289 | amb | 1627 | |
290 | results->finish_node=node2; | ||
291 | results->last_segment=seg2; | ||
292 | amb | 2 | } |
293 | amb | 1217 | else |
294 | amb | 1289 | InsertInQueue(queue,result2,result2->score); |
295 | amb | 2 | |
296 | endloop: | ||
297 | |||
298 | amb | 303 | if(IsFakeNode(node1)) |
299 | amb | 1078 | segmentp=NextFakeSegment(segmentp,node1); |
300 | amb | 303 | else if(IsFakeNode(node2)) |
301 | amb | 1078 | segmentp=NULL; /* cannot call NextSegment() with a fake segment */ |
302 | amb | 303 | else |
303 | { | ||
304 | amb | 1078 | segmentp=NextSegment(segments,segmentp,node1); |
305 | amb | 303 | |
306 | amb | 1078 | if(!segmentp && IsFakeNode(finish_node)) |
307 | segmentp=ExtraFakeSegment(node1,finish_node); | ||
308 | amb | 303 | } |
309 | amb | 2 | } |
310 | } | ||
311 | |||
312 | amb | 236 | FreeQueueList(queue); |
313 | |||
314 | amb | 77 | /* Check it worked */ |
315 | |||
316 | amb | 605 | if(!finish_result) |
317 | amb | 77 | { |
318 | amb | 1278 | #if DEBUG |
319 | printf(" Failed\n"); | ||
320 | #endif | ||
321 | |||
322 | amb | 77 | FreeResultsList(results); |
323 | return(NULL); | ||
324 | } | ||
325 | |||
326 | amb | 605 | FixForwardRoute(results,finish_result); |
327 | amb | 31 | |
328 | amb | 1278 | #if DEBUG |
329 | Result *r=FindResult(results,results->start_node,results->prev_segment); | ||
330 | |||
331 | while(r) | ||
332 | { | ||
333 | printf(" node=%"Pindex_t" segment=%"Pindex_t" score=%f\n",r->node,r->segment,r->score); | ||
334 | |||
335 | r=r->next; | ||
336 | } | ||
337 | #endif | ||
338 | |||
339 | amb | 31 | return(results); |
340 | amb | 2 | } |
341 | |||
342 | |||
343 | /*++++++++++++++++++++++++++++++++++++++ | ||
344 | amb | 680 | Find the optimum route between two nodes where the start and end are a set of pre/post-routed super-nodes. |
345 | amb | 34 | |
346 | amb | 238 | Results *FindMiddleRoute Returns a set of results. |
347 | amb | 34 | |
348 | amb | 95 | Nodes *nodes The set of nodes to use. |
349 | amb | 34 | |
350 | amb | 95 | Segments *segments The set of segments to use. |
351 | amb | 34 | |
352 | amb | 95 | Ways *ways The set of ways to use. |
353 | amb | 54 | |
354 | amb | 542 | Relations *relations The set of relations to use. |
355 | |||
356 | amb | 721 | Profile *profile The profile containing the transport type, speeds and allowed highways. |
357 | |||
358 | amb | 34 | Results *begin The initial portion of the route. |
359 | |||
360 | Results *end The final portion of the route. | ||
361 | ++++++++++++++++++++++++++++++++++++++*/ | ||
362 | |||
363 | amb | 721 | Results *FindMiddleRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,Results *begin,Results *end) |
364 | amb | 34 | { |
365 | Results *results; | ||
366 | amb | 469 | Queue *queue; |
367 | amb | 605 | Result *finish_result; |
368 | amb | 166 | score_t finish_score; |
369 | amb | 219 | double finish_lat,finish_lon; |
370 | amb | 632 | Result *result1,*result2,*result3,*result4; |
371 | amb | 1068 | int force_uturn=0; |
372 | amb | 34 | |
373 | amb | 1278 | #if DEBUG |
374 | printf(" FindMiddleRoute(...,[begin has %d nodes],[end has %d nodes])\n",begin->number,end->number); | ||
375 | #endif | ||
376 | |||
377 | #if !DEBUG | ||
378 | amb | 227 | if(!option_quiet) |
379 | amb | 1600 | printf_first("Finding Middle Route: Super-Nodes checked = 0"); |
380 | amb | 1278 | #endif |
381 | amb | 227 | |
382 | amb | 34 | /* Set up the finish conditions */ |
383 | |||
384 | amb | 1210 | finish_score=INF_SCORE; |
385 | amb | 605 | finish_result=NULL; |
386 | amb | 34 | |
387 | amb | 605 | if(IsFakeNode(end->finish_node)) |
388 | GetFakeLatLong(end->finish_node,&finish_lat,&finish_lon); | ||
389 | amb | 303 | else |
390 | amb | 1291 | GetLatLong(nodes,end->finish_node,NULL,&finish_lat,&finish_lon); |
391 | amb | 119 | |
392 | amb | 165 | /* Create the list of results and insert the first node into the queue */ |
393 | amb | 34 | |
394 | amb | 1286 | results=NewResultsList(20); |
395 | amb | 1289 | queue=NewQueueList(12); |
396 | amb | 34 | |
397 | amb | 605 | results->start_node=begin->start_node; |
398 | results->prev_segment=begin->prev_segment; | ||
399 | amb | 34 | |
400 | amb | 1627 | if(begin->number==1 && begin->prev_segment!=NO_SEGMENT) |
401 | amb | 688 | { |
402 | amb | 1627 | index_t superseg=FindSuperSegment(nodes,segments,ways,relations,profile,begin->start_node,begin->prev_segment); |
403 | amb | 34 | |
404 | amb | 1627 | results->prev_segment=superseg; |
405 | amb | 688 | } |
406 | |||
407 | result1=InsertResult(results,results->start_node,results->prev_segment); | ||
408 | |||
409 | amb | 685 | /* Insert the finish points of the beginning part of the path into the queue, |
410 | translating the segments into super-segments. */ | ||
411 | amb | 34 | |
412 | amb | 79 | result3=FirstResult(begin); |
413 | |||
414 | while(result3) | ||
415 | { | ||
416 | amb | 735 | if((results->start_node!=result3->node || results->prev_segment!=result3->segment) && |
417 | amb | 1553 | !IsFakeNode(result3->node) && IsSuperNode(LookupNode(nodes,result3->node,3))) |
418 | amb | 45 | { |
419 | amb | 722 | Result *result5=result1; |
420 | amb | 1497 | index_t superseg=FindSuperSegment(nodes,segments,ways,relations,profile,result3->node,result3->segment); |
421 | amb | 34 | |
422 | amb | 722 | if(superseg!=result3->segment) |
423 | { | ||
424 | result5=InsertResult(results,result3->node,result3->segment); | ||
425 | |||
426 | amb | 1553 | result5->score=result3->score; |
427 | |||
428 | amb | 722 | result5->prev=result1; |
429 | } | ||
430 | |||
431 | amb | 703 | if(!FindResult(results,result3->node,superseg)) |
432 | { | ||
433 | result2=InsertResult(results,result3->node,superseg); | ||
434 | amb | 722 | result2->prev=result5; |
435 | amb | 685 | |
436 | amb | 703 | result2->score=result3->score; |
437 | amb | 119 | |
438 | amb | 1289 | InsertInQueue(queue,result2,result3->score); |
439 | amb | 632 | |
440 | amb | 703 | if((result4=FindResult(end,result2->node,result2->segment))) |
441 | amb | 632 | { |
442 | amb | 703 | if((result2->score+result4->score)<finish_score) |
443 | { | ||
444 | finish_score=result2->score+result4->score; | ||
445 | finish_result=result2; | ||
446 | } | ||
447 | amb | 632 | } |
448 | } | ||
449 | amb | 45 | } |
450 | amb | 34 | |
451 | amb | 79 | result3=NextResult(begin,result3); |
452 | } | ||
453 | |||
454 | amb | 238 | if(begin->number==1) |
455 | amb | 1289 | InsertInQueue(queue,result1,0); |
456 | amb | 238 | |
457 | amb | 1068 | /* Check for barrier at start waypoint - must perform U-turn */ |
458 | |||
459 | if(begin->number==1 && results->prev_segment!=NO_SEGMENT) | ||
460 | { | ||
461 | amb | 1078 | Node *startp=LookupNode(nodes,result1->node,1); |
462 | amb | 1068 | |
463 | amb | 1078 | if(!(startp->allow&profile->allow)) |
464 | amb | 1068 | force_uturn=1; |
465 | } | ||
466 | |||
467 | amb | 95 | /* Loop across all nodes in the queue */ |
468 | amb | 34 | |
469 | amb | 236 | while((result1=PopFromQueue(queue))) |
470 | amb | 34 | { |
471 | amb | 885 | Node *node1p; |
472 | amb | 1078 | Segment *segmentp; |
473 | amb | 605 | index_t node1,seg1; |
474 | amb | 596 | index_t turnrelation=NO_RELATION; |
475 | amb | 594 | |
476 | amb | 680 | /* score must be better than current best score */ |
477 | amb | 1066 | if(result1->score>=finish_score) |
478 | amb | 119 | continue; |
479 | |||
480 | amb | 43 | node1=result1->node; |
481 | amb | 605 | seg1=result1->segment; |
482 | amb | 34 | |
483 | amb | 885 | node1p=LookupNode(nodes,node1,1); /* node1 cannot be a fake node (must be a super-node) */ |
484 | |||
485 | amb | 680 | /* lookup if a turn restriction applies */ |
486 | amb | 885 | if(profile->turns && IsTurnRestrictedNode(node1p)) /* node1 cannot be a fake node (must be a super-node) */ |
487 | amb | 605 | turnrelation=FindFirstTurnRelation2(relations,node1,seg1); |
488 | amb | 596 | |
489 | amb | 680 | /* Loop across all segments */ |
490 | amb | 34 | |
491 | amb | 1078 | segmentp=FirstSegment(segments,node1p,1); /* node1 cannot be a fake node (must be a super-node) */ |
492 | amb | 680 | |
493 | amb | 1078 | while(segmentp) |
494 | amb | 34 | { |
495 | amb | 885 | Node *node2p; |
496 | amb | 1078 | Way *wayp; |
497 | amb | 603 | index_t node2,seg2; |
498 | amb | 298 | score_t segment_pref,segment_score,cumulative_score; |
499 | int i; | ||
500 | amb | 59 | |
501 | amb | 680 | /* must be a super segment */ |
502 | amb | 1078 | if(!IsSuperSegment(segmentp)) |
503 | amb | 95 | goto endloop; |
504 | |||
505 | amb | 680 | /* must obey one-way restrictions (unless profile allows) */ |
506 | amb | 1078 | if(profile->oneway && IsOnewayTo(segmentp,node1)) |
507 | amb | 1497 | { |
508 | if(profile->allow!=Transports_Bicycle) | ||
509 | goto endloop; | ||
510 | amb | 64 | |
511 | amb | 1497 | wayp=LookupWay(ways,segmentp->way,1); |
512 | |||
513 | amb | 1559 | if(!(wayp->type&Highway_CycleBothWays)) |
514 | amb | 1497 | goto endloop; |
515 | } | ||
516 | |||
517 | amb | 1078 | seg2=IndexSegment(segments,segmentp); /* segment cannot be a fake segment (must be a super-segment) */ |
518 | amb | 34 | |
519 | amb | 1068 | /* must perform U-turn in special cases */ |
520 | if(force_uturn && node1==results->start_node) | ||
521 | { | ||
522 | if(seg2!=result1->segment) | ||
523 | goto endloop; | ||
524 | } | ||
525 | else | ||
526 | /* must not perform U-turn */ | ||
527 | if(seg1==seg2) /* No fake segments, applies to all profiles */ | ||
528 | goto endloop; | ||
529 | amb | 636 | |
530 | amb | 680 | /* must obey turn relations */ |
531 | amb | 605 | if(turnrelation!=NO_RELATION && !IsTurnAllowed(relations,turnrelation,node1,seg1,seg2,profile->allow)) |
532 | amb | 596 | goto endloop; |
533 | |||
534 | amb | 1078 | wayp=LookupWay(ways,segmentp->way,1); |
535 | amb | 54 | |
536 | amb | 1066 | /* mode of transport must be allowed on the highway */ |
537 | amb | 1078 | if(!(wayp->allow&profile->allow)) |
538 | amb | 54 | goto endloop; |
539 | |||
540 | amb | 680 | /* must obey weight restriction (if exists) */ |
541 | amb | 1078 | if(wayp->weight && wayp->weight<profile->weight) |
542 | amb | 135 | goto endloop; |
543 | |||
544 | amb | 1066 | /* must obey height/width/length restriction (if exist) */ |
545 | amb | 1078 | if((wayp->height && wayp->height<profile->height) || |
546 | (wayp->width && wayp->width <profile->width ) || | ||
547 | (wayp->length && wayp->length<profile->length)) | ||
548 | amb | 135 | goto endloop; |
549 | |||
550 | amb | 1078 | segment_pref=profile->highway[HIGHWAY(wayp->type)]; |
551 | amb | 298 | |
552 | amb | 1066 | /* highway preferences must allow this highway */ |
553 | if(segment_pref==0) | ||
554 | goto endloop; | ||
555 | |||
556 | amb | 298 | for(i=1;i<Property_Count;i++) |
557 | amb | 1550 | if(ways->file.props & PROPERTIES(i)) |
558 | { | ||
559 | if(wayp->props & PROPERTIES(i)) | ||
560 | segment_pref*=profile->props_yes[i]; | ||
561 | else | ||
562 | segment_pref*=profile->props_no[i]; | ||
563 | } | ||
564 | amb | 298 | |
565 | amb | 680 | /* profile preferences must allow this highway */ |
566 | amb | 298 | if(segment_pref==0) |
567 | goto endloop; | ||
568 | |||
569 | amb | 1078 | node2=OtherNode(segmentp,node1); |
570 | amb | 1066 | |
571 | amb | 885 | node2p=LookupNode(nodes,node2,2); /* node2 cannot be a fake node (must be a super-node) */ |
572 | amb | 469 | |
573 | amb | 1068 | /* mode of transport must be allowed through node2 unless it is the final node */ |
574 | if(node2!=end->finish_node && !(node2p->allow&profile->allow)) | ||
575 | amb | 469 | goto endloop; |
576 | |||
577 | amb | 1625 | /* calculate the score for the segment and cumulative */ |
578 | amb | 166 | if(option_quickest==0) |
579 | amb | 1168 | segment_score=(score_t)DISTANCE(segmentp->distance)/segment_pref; |
580 | amb | 166 | else |
581 | amb | 1078 | segment_score=(score_t)Duration(segmentp,wayp,profile)/segment_pref; |
582 | amb | 34 | |
583 | amb | 170 | cumulative_score=result1->score+segment_score; |
584 | amb | 166 | |
585 | amb | 680 | /* score must be better than current best score */ |
586 | amb | 1066 | if(cumulative_score>=finish_score) |
587 | amb | 34 | goto endloop; |
588 | |||
589 | amb | 1625 | /* find whether the node/segment combination already exists */ |
590 | amb | 605 | result2=FindResult(results,node2,seg2); |
591 | amb | 42 | |
592 | amb | 680 | if(!result2) /* New end node/segment pair */ |
593 | amb | 34 | { |
594 | amb | 605 | result2=InsertResult(results,node2,seg2); |
595 | result2->prev=result1; | ||
596 | amb | 170 | result2->score=cumulative_score; |
597 | amb | 34 | } |
598 | amb | 605 | else if(cumulative_score<result2->score) /* New end node/segment pair is better */ |
599 | amb | 34 | { |
600 | amb | 605 | result2->prev=result1; |
601 | amb | 170 | result2->score=cumulative_score; |
602 | amb | 1217 | } |
603 | else | ||
604 | goto endloop; | ||
605 | amb | 166 | |
606 | amb | 1217 | if((result3=FindResult(end,node2,seg2))) |
607 | { | ||
608 | if((result2->score+result3->score)<finish_score) | ||
609 | amb | 34 | { |
610 | amb | 1217 | finish_score=result2->score+result3->score; |
611 | finish_result=result2; | ||
612 | amb | 1627 | |
613 | results->finish_node=node2; | ||
614 | results->last_segment=seg2; | ||
615 | amb | 34 | } |
616 | amb | 1217 | } |
617 | else | ||
618 | { | ||
619 | double lat,lon; | ||
620 | distance_t direct; | ||
621 | amb | 1289 | score_t potential_score; |
622 | amb | 34 | |
623 | amb | 1291 | GetLatLong(nodes,node2,node2p,&lat,&lon); /* node2 cannot be a fake node (must be a super-node) */ |
624 | amb | 680 | |
625 | amb | 1217 | direct=Distance(lat,lon,finish_lat,finish_lon); |
626 | amb | 166 | |
627 | amb | 1217 | if(option_quickest==0) |
628 | amb | 1289 | potential_score=result2->score+(score_t)direct/profile->max_pref; |
629 | amb | 1217 | else |
630 | amb | 1289 | potential_score=result2->score+(score_t)distance_speed_to_duration(direct,profile->max_speed)/profile->max_pref; |
631 | amb | 119 | |
632 | amb | 1289 | if(potential_score<finish_score) |
633 | InsertInQueue(queue,result2,potential_score); | ||
634 | amb | 34 | } |
635 | |||
636 | amb | 627 | endloop: |
637 | |||
638 | amb | 1078 | segmentp=NextSegment(segments,segmentp,node1); /* node1 cannot be a fake node (must be a super-node) */ |
639 | amb | 34 | } |
640 | } | ||
641 | |||
642 | amb | 236 | FreeQueueList(queue); |
643 | |||
644 | amb | 77 | /* Check it worked */ |
645 | |||
646 | amb | 605 | if(!finish_result) |
647 | amb | 77 | { |
648 | amb | 1278 | #if DEBUG |
649 | printf(" Failed\n"); | ||
650 | #endif | ||
651 | |||
652 | amb | 1600 | #if !DEBUG |
653 | if(!option_quiet) | ||
654 | printf_last("Found Middle Route: Super-Nodes checked = %d - Fail",results->number); | ||
655 | #endif | ||
656 | |||
657 | amb | 77 | FreeResultsList(results); |
658 | return(NULL); | ||
659 | } | ||
660 | |||
661 | amb | 616 | FixForwardRoute(results,finish_result); |
662 | |||
663 | amb | 1278 | #if DEBUG |
664 | Result *r=FindResult(results,results->start_node,results->prev_segment); | ||
665 | |||
666 | while(r) | ||
667 | { | ||
668 | printf(" node=%"Pindex_t" segment=%"Pindex_t" score=%f\n",r->node,r->segment,r->score); | ||
669 | |||
670 | r=r->next; | ||
671 | } | ||
672 | #endif | ||
673 | |||
674 | amb | 1600 | #if !DEBUG |
675 | if(!option_quiet) | ||
676 | printf_last("Found Middle Route: Super-Nodes checked = %d",results->number); | ||
677 | #endif | ||
678 | |||
679 | amb | 34 | return(results); |
680 | } | ||
681 | |||
682 | |||
683 | /*++++++++++++++++++++++++++++++++++++++ | ||
684 | amb | 685 | Find the super-segment that represents the route that contains a particular segment. |
685 | |||
686 | index_t FindSuperSegment Returns the index of the super-segment. | ||
687 | |||
688 | Nodes *nodes The set of nodes to use. | ||
689 | |||
690 | Segments *segments The set of segments to use. | ||
691 | |||
692 | Ways *ways The set of ways to use. | ||
693 | |||
694 | Relations *relations The set of relations to use. | ||
695 | |||
696 | amb | 1497 | Profile *profile The profile containing the transport type, speeds and allowed highways. |
697 | |||
698 | amb | 1061 | index_t finish_node The super-node that the route ends at. |
699 | amb | 685 | |
700 | amb | 1061 | index_t finish_segment The segment that the route ends with. |
701 | amb | 685 | ++++++++++++++++++++++++++++++++++++++*/ |
702 | |||
703 | amb | 1497 | static index_t FindSuperSegment(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,index_t finish_node,index_t finish_segment) |
704 | amb | 685 | { |
705 | amb | 1078 | Node *supernodep; |
706 | Segment *supersegmentp; | ||
707 | amb | 685 | |
708 | amb | 1061 | if(IsFakeSegment(finish_segment)) |
709 | finish_segment=IndexRealSegment(finish_segment); | ||
710 | amb | 699 | |
711 | amb | 1553 | supernodep=LookupNode(nodes,finish_node,3); /* finish_node cannot be a fake node (must be a super-node) */ |
712 | supersegmentp=LookupSegment(segments,finish_segment,4); /* finish_segment cannot be a fake segment. */ | ||
713 | amb | 687 | |
714 | amb | 1078 | if(IsSuperSegment(supersegmentp)) |
715 | amb | 1061 | return(finish_segment); |
716 | amb | 687 | |
717 | amb | 685 | /* Loop across all segments */ |
718 | |||
719 | amb | 1553 | supersegmentp=FirstSegment(segments,supernodep,4); /* supernode cannot be a fake node (must be a super-node) */ |
720 | amb | 685 | |
721 | amb | 1078 | while(supersegmentp) |
722 | amb | 685 | { |
723 | amb | 1078 | if(IsSuperSegment(supersegmentp)) |
724 | amb | 685 | { |
725 | Results *results; | ||
726 | amb | 1063 | Result *result; |
727 | index_t start_node; | ||
728 | amb | 685 | |
729 | amb | 1078 | start_node=OtherNode(supersegmentp,finish_node); |
730 | amb | 685 | |
731 | amb | 1497 | results=FindSuperRoute(nodes,segments,ways,relations,profile,start_node,finish_node); |
732 | amb | 685 | |
733 | amb | 1063 | if(!results) |
734 | continue; | ||
735 | amb | 1061 | |
736 | amb | 1063 | result=FindResult(results,finish_node,finish_segment); |
737 | amb | 1061 | |
738 | amb | 1168 | if(result && (distance_t)result->score==DISTANCE(supersegmentp->distance)) |
739 | amb | 1063 | { |
740 | FreeResultsList(results); | ||
741 | amb | 1078 | return(IndexSegment(segments,supersegmentp)); |
742 | amb | 1063 | } |
743 | amb | 1061 | |
744 | amb | 1063 | if(results) |
745 | FreeResultsList(results); | ||
746 | } | ||
747 | amb | 1061 | |
748 | amb | 1078 | supersegmentp=NextSegment(segments,supersegmentp,finish_node); /* finish_node cannot be a fake node (must be a super-node) */ |
749 | amb | 1063 | } |
750 | amb | 1061 | |
751 | amb | 1063 | return(finish_segment); |
752 | } | ||
753 | amb | 1061 | |
754 | |||
755 | amb | 1063 | /*++++++++++++++++++++++++++++++++++++++ |
756 | Find the shortest route between two super-nodes using only normal nodes. | ||
757 | This is effectively the same function as is used in superx.c when finding super-segments initially. | ||
758 | amb | 1061 | |
759 | amb | 1063 | Results *FindSuperRoute Returns a set of results. |
760 | amb | 1061 | |
761 | amb | 1063 | Nodes *nodes The set of nodes to use. |
762 | amb | 1061 | |
763 | amb | 1063 | Segments *segments The set of segments to use. |
764 | amb | 1061 | |
765 | amb | 1063 | Ways *ways The set of ways to use. |
766 | amb | 1061 | |
767 | amb | 1063 | Relations *relations The set of relations to use. |
768 | amb | 1061 | |
769 | amb | 1497 | Profile *profile The profile containing the transport type, speeds and allowed highways. |
770 | |||
771 | amb | 1063 | index_t start_node The start node. |
772 | amb | 1061 | |
773 | amb | 1063 | index_t finish_node The finish node. |
774 | ++++++++++++++++++++++++++++++++++++++*/ | ||
775 | amb | 1061 | |
776 | amb | 1497 | static Results *FindSuperRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,index_t start_node,index_t finish_node) |
777 | amb | 1063 | { |
778 | Results *results; | ||
779 | Queue *queue; | ||
780 | Result *result1,*result2; | ||
781 | amb | 1061 | |
782 | amb | 1278 | #if DEBUG |
783 | printf(" FindSuperRoute(...,start_node=%"Pindex_t" finish_node=%"Pindex_t")\n",start_node,finish_node); | ||
784 | #endif | ||
785 | |||
786 | amb | 1063 | /* Create the list of results and insert the first node into the queue */ |
787 | amb | 1061 | |
788 | amb | 1286 | results=NewResultsList(8); |
789 | amb | 1289 | queue=NewQueueList(8); |
790 | amb | 1061 | |
791 | amb | 1063 | results->start_node=start_node; |
792 | results->prev_segment=NO_SEGMENT; | ||
793 | amb | 1061 | |
794 | amb | 1063 | result1=InsertResult(results,results->start_node,results->prev_segment); |
795 | amb | 1061 | |
796 | amb | 1289 | InsertInQueue(queue,result1,0); |
797 | amb | 1061 | |
798 | amb | 1063 | /* Loop across all nodes in the queue */ |
799 | amb | 1061 | |
800 | amb | 1063 | while((result1=PopFromQueue(queue))) |
801 | { | ||
802 | Node *node1p=NULL; | ||
803 | amb | 1078 | Segment *segmentp; |
804 | amb | 1063 | index_t node1,seg1; |
805 | amb | 1061 | |
806 | amb | 1063 | node1=result1->node; |
807 | seg1=result1->segment; | ||
808 | amb | 1061 | |
809 | amb | 1553 | node1p=LookupNode(nodes,node1,3); /* node1 cannot be a fake node */ |
810 | amb | 1061 | |
811 | amb | 1063 | /* Loop across all segments */ |
812 | amb | 1061 | |
813 | amb | 1553 | segmentp=FirstSegment(segments,node1p,3); /* node1 cannot be a fake node */ |
814 | amb | 1061 | |
815 | amb | 1078 | while(segmentp) |
816 | amb | 1063 | { |
817 | Node *node2p=NULL; | ||
818 | index_t node2,seg2; | ||
819 | score_t cumulative_score; | ||
820 | amb | 1061 | |
821 | amb | 1063 | /* must be a normal segment */ |
822 | amb | 1078 | if(!IsNormalSegment(segmentp)) |
823 | amb | 1063 | goto endloop; |
824 | amb | 1061 | |
825 | amb | 1063 | /* must obey one-way restrictions */ |
826 | amb | 1078 | if(IsOnewayTo(segmentp,node1)) |
827 | amb | 1497 | { |
828 | Way *wayp; | ||
829 | amb | 1061 | |
830 | amb | 1497 | if(profile->allow!=Transports_Bicycle) |
831 | goto endloop; | ||
832 | |||
833 | amb | 1553 | wayp=LookupWay(ways,segmentp->way,2); |
834 | amb | 1497 | |
835 | amb | 1559 | if(!(wayp->type&Highway_CycleBothWays)) |
836 | amb | 1497 | goto endloop; |
837 | } | ||
838 | |||
839 | amb | 1078 | seg2=IndexSegment(segments,segmentp); |
840 | amb | 1061 | |
841 | amb | 1063 | /* must not perform U-turn */ |
842 | if(seg1==seg2) | ||
843 | goto endloop; | ||
844 | amb | 1061 | |
845 | amb | 1078 | node2=OtherNode(segmentp,node1); |
846 | amb | 1061 | |
847 | amb | 1553 | node2p=LookupNode(nodes,node2,4); /* node2 cannot be a fake node */ |
848 | amb | 1061 | |
849 | amb | 1063 | /* must not pass over super-node */ |
850 | if(node2!=finish_node && IsSuperNode(node2p)) | ||
851 | goto endloop; | ||
852 | amb | 1061 | |
853 | amb | 1066 | /* Specifically looking for the shortest route to emulate superx.c */ |
854 | amb | 1168 | cumulative_score=result1->score+(score_t)DISTANCE(segmentp->distance); |
855 | amb | 1061 | |
856 | amb | 1063 | result2=FindResult(results,node2,seg2); |
857 | |||
858 | if(!result2) /* New end node/segment combination */ | ||
859 | amb | 1061 | { |
860 | amb | 1063 | result2=InsertResult(results,node2,seg2); |
861 | result2->prev=result1; | ||
862 | result2->score=cumulative_score; | ||
863 | amb | 798 | } |
864 | amb | 1063 | else if(cumulative_score<result2->score) /* New score for end node/segment combination is better */ |
865 | { | ||
866 | result2->prev=result1; | ||
867 | result2->segment=seg2; | ||
868 | result2->score=cumulative_score; | ||
869 | } | ||
870 | amb | 1217 | else goto endloop; |
871 | amb | 1063 | |
872 | amb | 1217 | /* don't route beyond a super-node. */ |
873 | if(!IsSuperNode(node2p)) | ||
874 | amb | 1289 | InsertInQueue(queue,result2,result2->score); |
875 | amb | 1217 | |
876 | amb | 1063 | endloop: |
877 | |||
878 | amb | 1078 | segmentp=NextSegment(segments,segmentp,node1); |
879 | amb | 685 | } |
880 | } | ||
881 | |||
882 | amb | 1063 | FreeQueueList(queue); |
883 | |||
884 | amb | 1278 | #if DEBUG |
885 | Result *r=FindResult(results,results->start_node,results->prev_segment); | ||
886 | |||
887 | while(r) | ||
888 | { | ||
889 | printf(" node=%"Pindex_t" segment=%"Pindex_t" score=%f\n",r->node,r->segment,r->score); | ||
890 | |||
891 | r=r->next; | ||
892 | } | ||
893 | #endif | ||
894 | |||
895 | amb | 1063 | return(results); |
896 | amb | 685 | } |
897 | |||
898 | |||
899 | /*++++++++++++++++++++++++++++++++++++++ | ||
900 | amb | 95 | Find all routes from a specified node to any super-node. |
901 | amb | 3 | |
902 | amb | 126 | Results *FindStartRoutes Returns a set of results. |
903 | amb | 31 | |
904 | Nodes *nodes The set of nodes to use. | ||
905 | |||
906 | Segments *segments The set of segments to use. | ||
907 | |||
908 | amb | 54 | Ways *ways The set of ways to use. |
909 | |||
910 | amb | 542 | Relations *relations The set of relations to use. |
911 | |||
912 | amb | 721 | Profile *profile The profile containing the transport type, speeds and allowed highways. |
913 | |||
914 | amb | 605 | index_t start_node The start node. |
915 | amb | 31 | |
916 | amb | 605 | index_t prev_segment The previous segment before the start node. |
917 | |||
918 | amb | 729 | index_t finish_node The finish node. |
919 | amb | 31 | ++++++++++++++++++++++++++++++++++++++*/ |
920 | |||
921 | amb | 1278 | Results *FindStartRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,index_t start_node,index_t prev_segment,index_t finish_node) |
922 | amb | 31 | { |
923 | Results *results; | ||
924 | amb | 1632 | Queue *queue,*superqueue; |
925 | amb | 469 | Result *result1,*result2; |
926 | amb | 1632 | Result *finish_result=NULL; |
927 | score_t finish_score=INF_SCORE; | ||
928 | amb | 1278 | int nsuper=0,force_uturn=0; |
929 | amb | 31 | |
930 | amb | 1278 | #if DEBUG |
931 | printf(" FindStartRoutes(...,start_node=%"Pindex_t" prev_segment=%"Pindex_t" finish_node=%"Pindex_t")\n",start_node,prev_segment,finish_node); | ||
932 | #endif | ||
933 | |||
934 | amb | 1600 | #if !DEBUG |
935 | if(!option_quiet) | ||
936 | printf_first("Finding Start Route: Nodes checked = 0"); | ||
937 | #endif | ||
938 | |||
939 | amb | 1068 | /* Create the list of results and insert the first node into the queue */ |
940 | amb | 31 | |
941 | amb | 1286 | results=NewResultsList(8); |
942 | amb | 1289 | queue=NewQueueList(8); |
943 | amb | 1632 | superqueue=NewQueueList(8); |
944 | amb | 31 | |
945 | amb | 605 | results->start_node=start_node; |
946 | results->prev_segment=prev_segment; | ||
947 | amb | 165 | |
948 | amb | 735 | result1=InsertResult(results,results->start_node,results->prev_segment); |
949 | amb | 31 | |
950 | amb | 1289 | InsertInQueue(queue,result1,0); |
951 | amb | 531 | |
952 | amb | 1068 | /* Check for barrier at start waypoint - must perform U-turn */ |
953 | amb | 31 | |
954 | amb | 1068 | if(prev_segment!=NO_SEGMENT && !IsFakeNode(start_node)) |
955 | { | ||
956 | amb | 1078 | Node *startp=LookupNode(nodes,start_node,1); |
957 | amb | 236 | |
958 | amb | 1078 | if(!(startp->allow&profile->allow)) |
959 | amb | 1068 | force_uturn=1; |
960 | } | ||
961 | |||
962 | amb | 31 | /* Loop across all nodes in the queue */ |
963 | |||
964 | amb | 236 | while((result1=PopFromQueue(queue))) |
965 | amb | 31 | { |
966 | amb | 885 | Node *node1p=NULL; |
967 | amb | 1078 | Segment *segmentp; |
968 | amb | 637 | index_t node1,seg1,seg1r; |
969 | amb | 719 | index_t turnrelation=NO_RELATION; |
970 | amb | 594 | |
971 | amb | 1632 | /* score must be better than current best score */ |
972 | if(result1->score>=finish_score) | ||
973 | continue; | ||
974 | |||
975 | amb | 43 | node1=result1->node; |
976 | amb | 605 | seg1=result1->segment; |
977 | amb | 31 | |
978 | amb | 637 | if(IsFakeSegment(seg1)) |
979 | seg1r=IndexRealSegment(seg1); | ||
980 | else | ||
981 | seg1r=seg1; | ||
982 | |||
983 | amb | 885 | if(!IsFakeNode(node1)) |
984 | node1p=LookupNode(nodes,node1,1); | ||
985 | |||
986 | amb | 719 | /* lookup if a turn restriction applies */ |
987 | amb | 885 | if(profile->turns && node1p && IsTurnRestrictedNode(node1p)) |
988 | amb | 719 | turnrelation=FindFirstTurnRelation2(relations,node1,seg1r); |
989 | amb | 680 | |
990 | /* Loop across all segments */ | ||
991 | |||
992 | amb | 303 | if(IsFakeNode(node1)) |
993 | amb | 1078 | segmentp=FirstFakeSegment(node1); |
994 | amb | 303 | else |
995 | amb | 1078 | segmentp=FirstSegment(segments,node1p,1); |
996 | amb | 31 | |
997 | amb | 1078 | while(segmentp) |
998 | amb | 31 | { |
999 | amb | 885 | Node *node2p=NULL; |
1000 | amb | 1078 | Way *wayp; |
1001 | amb | 637 | index_t node2,seg2,seg2r; |
1002 | amb | 298 | score_t segment_pref,segment_score,cumulative_score; |
1003 | int i; | ||
1004 | amb | 59 | |
1005 | amb | 1078 | node2=OtherNode(segmentp,node1); /* need this here because we use node2 at the end of the loop */ |
1006 | amb | 734 | |
1007 | amb | 680 | /* must be a normal segment */ |
1008 | amb | 1078 | if(!IsNormalSegment(segmentp)) |
1009 | amb | 95 | goto endloop; |
1010 | |||
1011 | amb | 680 | /* must obey one-way restrictions (unless profile allows) */ |
1012 | amb | 1078 | if(profile->oneway && IsOnewayTo(segmentp,node1)) |
1013 | amb | 1497 | { |
1014 | if(profile->allow!=Transports_Bicycle) | ||
1015 | goto endloop; | ||
1016 | amb | 64 | |
1017 | amb | 1497 | wayp=LookupWay(ways,segmentp->way,1); |
1018 | |||
1019 | amb | 1559 | if(!(wayp->type&Highway_CycleBothWays)) |
1020 | amb | 1497 | goto endloop; |
1021 | } | ||
1022 | |||
1023 | amb | 605 | if(IsFakeNode(node1) || IsFakeNode(node2)) |
1024 | amb | 637 | { |
1025 | amb | 1078 | seg2 =IndexFakeSegment(segmentp); |
1026 | amb | 637 | seg2r=IndexRealSegment(seg2); |
1027 | } | ||
1028 | amb | 605 | else |
1029 | amb | 637 | { |
1030 | amb | 1078 | seg2 =IndexSegment(segments,segmentp); |
1031 | amb | 637 | seg2r=seg2; |
1032 | } | ||
1033 | amb | 603 | |
1034 | amb | 1068 | /* must perform U-turn in special cases */ |
1035 | if(node1==start_node && force_uturn) | ||
1036 | { | ||
1037 | if(seg2r!=result1->segment) | ||
1038 | goto endloop; | ||
1039 | } | ||
1040 | else | ||
1041 | /* must not perform U-turn (unless profile allows) */ | ||
1042 | if(profile->turns && (seg1==seg2 || seg1==seg2r || seg1r==seg2 || (seg1r==seg2r && IsFakeUTurn(seg1,seg2)))) | ||
1043 | goto endloop; | ||
1044 | amb | 636 | |
1045 | amb | 719 | /* must obey turn relations */ |
1046 | if(turnrelation!=NO_RELATION && !IsTurnAllowed(relations,turnrelation,node1,seg1r,seg2r,profile->allow)) | ||
1047 | goto endloop; | ||
1048 | amb | 596 | |
1049 | amb | 1078 | wayp=LookupWay(ways,segmentp->way,1); |
1050 | amb | 54 | |
1051 | amb | 680 | /* mode of transport must be allowed on the highway */ |
1052 | amb | 1078 | if(!(wayp->allow&profile->allow)) |
1053 | amb | 54 | goto endloop; |
1054 | |||
1055 | amb | 680 | /* must obey weight restriction (if exists) */ |
1056 | amb | 1078 | if(wayp->weight && wayp->weight<profile->weight) |
1057 | amb | 135 | goto endloop; |
1058 | |||
1059 | amb | 680 | /* must obey height/width/length restriction (if exists) */ |
1060 | amb | 1078 | if((wayp->height && wayp->height<profile->height) || |
1061 | (wayp->width && wayp->width <profile->width ) || | ||
1062 | (wayp->length && wayp->length<profile->length)) | ||
1063 | amb | 135 | goto endloop; |
1064 | |||
1065 | amb | 1078 | segment_pref=profile->highway[HIGHWAY(wayp->type)]; |
1066 | amb | 298 | |
1067 | amb | 1066 | /* highway preferences must allow this highway */ |
1068 | if(segment_pref==0) | ||
1069 | goto endloop; | ||
1070 | |||
1071 | amb | 298 | for(i=1;i<Property_Count;i++) |
1072 | amb | 1550 | if(ways->file.props & PROPERTIES(i)) |
1073 | { | ||
1074 | if(wayp->props & PROPERTIES(i)) | ||
1075 | segment_pref*=profile->props_yes[i]; | ||
1076 | else | ||
1077 | segment_pref*=profile->props_no[i]; | ||
1078 | } | ||
1079 | amb | 298 | |
1080 | amb | 680 | /* profile preferences must allow this highway */ |
1081 | amb | 298 | if(segment_pref==0) |
1082 | goto endloop; | ||
1083 | |||
1084 | amb | 471 | if(!IsFakeNode(node2)) |
1085 | amb | 885 | node2p=LookupNode(nodes,node2,2); |
1086 | amb | 469 | |
1087 | amb | 1068 | /* mode of transport must be allowed through node2 unless it is the final node */ |
1088 | if(node2p && node2!=finish_node && !(node2p->allow&profile->allow)) | ||
1089 | amb | 885 | goto endloop; |
1090 | amb | 469 | |
1091 | amb | 1625 | /* calculate the score for the segment and cumulative */ |
1092 | amb | 166 | if(option_quickest==0) |
1093 | amb | 1168 | segment_score=(score_t)DISTANCE(segmentp->distance)/segment_pref; |
1094 | amb | 166 | else |
1095 | amb | 1078 | segment_score=(score_t)Duration(segmentp,wayp,profile)/segment_pref; |
1096 | amb | 59 | |
1097 | amb | 1626 | /* prefer not to follow two fake segments when one would do (special case) */ |
1098 | if(IsFakeSegment(seg2)) | ||
1099 | segment_score*=1.01; | ||
1100 | |||
1101 | amb | 170 | cumulative_score=result1->score+segment_score; |
1102 | amb | 166 | |
1103 | amb | 1632 | /* score must be better than current best score */ |
1104 | if(cumulative_score>=finish_score) | ||
1105 | goto endloop; | ||
1106 | |||
1107 | amb | 1625 | /* find whether the node/segment combination already exists */ |
1108 | amb | 605 | result2=FindResult(results,node2,seg2); |
1109 | amb | 31 | |
1110 | amb | 680 | if(!result2) /* New end node/segment combination */ |
1111 | amb | 31 | { |
1112 | amb | 605 | result2=InsertResult(results,node2,seg2); |
1113 | result2->prev=result1; | ||
1114 | amb | 170 | result2->score=cumulative_score; |
1115 | amb | 31 | |
1116 | amb | 885 | if(node2p && IsSuperNode(node2p)) |
1117 | amb | 1278 | nsuper++; |
1118 | amb | 31 | } |
1119 | amb | 1066 | else if(cumulative_score<result2->score) /* New score for end node/segment combination is better */ |
1120 | amb | 31 | { |
1121 | amb | 605 | result2->prev=result1; |
1122 | amb | 170 | result2->score=cumulative_score; |
1123 | amb | 1632 | } |
1124 | else | ||
1125 | goto endloop; | ||
1126 | amb | 1281 | |
1127 | amb | 1632 | if(node2==finish_node) |
1128 | { | ||
1129 | if(!finish_result) | ||
1130 | amb | 1281 | { |
1131 | amb | 1632 | Result *result3; |
1132 | |||
1133 | while((result3=PopFromQueue(superqueue))) | ||
1134 | InsertInQueue(queue,result3,result3->score); | ||
1135 | } | ||
1136 | |||
1137 | if(cumulative_score<finish_score) | ||
1138 | { | ||
1139 | finish_score=cumulative_score; | ||
1140 | finish_result=result2; | ||
1141 | |||
1142 | amb | 1627 | results->finish_node=node2; |
1143 | amb | 1281 | results->last_segment=seg2; |
1144 | } | ||
1145 | amb | 1217 | } |
1146 | amb | 31 | |
1147 | amb | 1632 | if(finish_result || (node2p && !IsSuperNode(node2p))) |
1148 | amb | 1289 | InsertInQueue(queue,result2,result2->score); |
1149 | amb | 1632 | else if(node2p && IsSuperNode(node2p)) |
1150 | InsertInQueue(superqueue,result2,result2->score); | ||
1151 | amb | 31 | |
1152 | endloop: | ||
1153 | |||
1154 | amb | 303 | if(IsFakeNode(node1)) |
1155 | amb | 1078 | segmentp=NextFakeSegment(segmentp,node1); |
1156 | amb | 729 | else if(IsFakeNode(node2)) |
1157 | amb | 1078 | segmentp=NULL; /* cannot call NextSegment() with a fake segment */ |
1158 | amb | 303 | else |
1159 | amb | 729 | { |
1160 | amb | 1078 | segmentp=NextSegment(segments,segmentp,node1); |
1161 | amb | 678 | |
1162 | amb | 1078 | if(!segmentp && IsFakeNode(finish_node)) |
1163 | segmentp=ExtraFakeSegment(node1,finish_node); | ||
1164 | amb | 729 | } |
1165 | amb | 31 | } |
1166 | } | ||
1167 | |||
1168 | amb | 236 | FreeQueueList(queue); |
1169 | amb | 1632 | FreeQueueList(superqueue); |
1170 | amb | 236 | |
1171 | amb | 112 | /* Check it worked */ |
1172 | |||
1173 | amb | 1632 | if(results->number==1 || (nsuper==0 && !finish_result)) |
1174 | amb | 112 | { |
1175 | amb | 1278 | #if DEBUG |
1176 | printf(" Failed (%d results, %d super)\n",results->number,nsuper); | ||
1177 | #endif | ||
1178 | |||
1179 | amb | 1600 | #if !DEBUG |
1180 | if(!option_quiet) | ||
1181 | printf_last("Found Start Route: Nodes checked = %d - Fail",results->number); | ||
1182 | #endif | ||
1183 | |||
1184 | amb | 112 | FreeResultsList(results); |
1185 | return(NULL); | ||
1186 | } | ||
1187 | |||
1188 | amb | 1634 | /* If we found the finish node then make a proper route */ |
1189 | |||
1190 | if(finish_result) | ||
1191 | FixForwardRoute(results,finish_result); | ||
1192 | |||
1193 | amb | 1278 | #if DEBUG |
1194 | Result *s=FirstResult(results); | ||
1195 | |||
1196 | while(s) | ||
1197 | { | ||
1198 | if(s->node==finish_node) | ||
1199 | { | ||
1200 | Result *r=FindResult(results,s->node,s->segment); | ||
1201 | |||
1202 | printf(" -------- route to finish node\n"); | ||
1203 | |||
1204 | while(r) | ||
1205 | { | ||
1206 | printf(" node=%"Pindex_t" segment=%"Pindex_t" score=%f\n",r->node,r->segment,r->score); | ||
1207 | |||
1208 | r=r->prev; | ||
1209 | } | ||
1210 | } | ||
1211 | |||
1212 | if(!IsFakeNode(s->node)) | ||
1213 | { | ||
1214 | Node *n=LookupNode(nodes,s->node,1); | ||
1215 | |||
1216 | if(IsSuperNode(n)) | ||
1217 | { | ||
1218 | Result *r=FindResult(results,s->node,s->segment); | ||
1219 | |||
1220 | printf(" -------- route to super node\n"); | ||
1221 | |||
1222 | while(r) | ||
1223 | { | ||
1224 | printf(" node=%"Pindex_t" segment=%"Pindex_t" score=%f\n",r->node,r->segment,r->score); | ||
1225 | |||
1226 | r=r->prev; | ||
1227 | } | ||
1228 | } | ||
1229 | } | ||
1230 | |||
1231 | s=NextResult(results,s); | ||
1232 | } | ||
1233 | #endif | ||
1234 | |||
1235 | amb | 1600 | #if !DEBUG |
1236 | if(!option_quiet) | ||
1237 | printf_last("Found Start Route: Nodes checked = %d",results->number); | ||
1238 | #endif | ||
1239 | |||
1240 | amb | 1278 | return(results); |
1241 | } | ||
1242 | |||
1243 | |||
1244 | /*++++++++++++++++++++++++++++++++++++++ | ||
1245 | amb | 680 | Find all routes from any super-node to a specific node (by working backwards from the specific node to all super-nodes). |
1246 | amb | 34 | |
1247 | amb | 126 | Results *FindFinishRoutes Returns a set of results. |
1248 | amb | 34 | |
1249 | Nodes *nodes The set of nodes to use. | ||
1250 | |||
1251 | Segments *segments The set of segments to use. | ||
1252 | |||
1253 | amb | 54 | Ways *ways The set of ways to use. |
1254 | |||
1255 | amb | 542 | Relations *relations The set of relations to use. |
1256 | |||
1257 | amb | 721 | Profile *profile The profile containing the transport type, speeds and allowed highways. |
1258 | |||
1259 | amb | 605 | index_t finish_node The finishing node. |
1260 | amb | 34 | ++++++++++++++++++++++++++++++++++++++*/ |
1261 | |||
1262 | amb | 721 | Results *FindFinishRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,index_t finish_node) |
1263 | amb | 34 | { |
1264 | amb | 605 | Results *results,*results2; |
1265 | amb | 469 | Queue *queue; |
1266 | amb | 605 | Result *result1,*result2,*result3; |
1267 | amb | 34 | |
1268 | amb | 1278 | #if DEBUG |
1269 | printf(" FindFinishRoutes(...,finish_node=%"Pindex_t")\n",finish_node); | ||
1270 | #endif | ||
1271 | |||
1272 | amb | 1600 | #if !DEBUG |
1273 | if(!option_quiet) | ||
1274 | printf_first("Finding Finish Route: Nodes checked = 0"); | ||
1275 | #endif | ||
1276 | |||
1277 | amb | 1068 | /* Create the results and insert the finish node into the queue */ |
1278 | amb | 34 | |
1279 | amb | 1286 | results=NewResultsList(8); |
1280 | amb | 1289 | queue=NewQueueList(8); |
1281 | amb | 34 | |
1282 | amb | 605 | results->finish_node=finish_node; |
1283 | amb | 165 | |
1284 | amb | 605 | result1=InsertResult(results,finish_node,NO_SEGMENT); |
1285 | amb | 34 | |
1286 | amb | 1289 | InsertInQueue(queue,result1,0); |
1287 | amb | 236 | |
1288 | amb | 34 | /* Loop across all nodes in the queue */ |
1289 | |||
1290 | amb | 236 | while((result1=PopFromQueue(queue))) |
1291 | amb | 34 | { |
1292 | amb | 885 | Node *node1p=NULL; |
1293 | amb | 1078 | Segment *segmentp; |
1294 | amb | 637 | index_t node1,seg1,seg1r; |
1295 | amb | 596 | index_t turnrelation=NO_RELATION; |
1296 | amb | 594 | |
1297 | amb | 43 | node1=result1->node; |
1298 | amb | 605 | seg1=result1->segment; |
1299 | amb | 34 | |
1300 | amb | 1579 | if(seg1!=NO_SEGMENT && IsFakeSegment(seg1)) |
1301 | amb | 637 | seg1r=IndexRealSegment(seg1); |
1302 | else | ||
1303 | seg1r=seg1; | ||
1304 | |||
1305 | amb | 885 | if(!IsFakeNode(node1)) |
1306 | node1p=LookupNode(nodes,node1,1); | ||
1307 | |||
1308 | amb | 680 | /* lookup if a turn restriction applies */ |
1309 | amb | 885 | if(profile->turns && node1p && IsTurnRestrictedNode(node1p)) |
1310 | amb | 596 | turnrelation=FindFirstTurnRelation1(relations,node1); /* working backwards => turn relation sort order doesn't help */ |
1311 | |||
1312 | amb | 680 | /* Loop across all segments */ |
1313 | |||
1314 | amb | 303 | if(IsFakeNode(node1)) |
1315 | amb | 1078 | segmentp=FirstFakeSegment(node1); |
1316 | amb | 303 | else |
1317 | amb | 1078 | segmentp=FirstSegment(segments,node1p,1); |
1318 | amb | 34 | |
1319 | amb | 1078 | while(segmentp) |
1320 | amb | 34 | { |
1321 | amb | 885 | Node *node2p=NULL; |
1322 | amb | 1078 | Way *wayp; |
1323 | amb | 637 | index_t node2,seg2,seg2r; |
1324 | amb | 298 | score_t segment_pref,segment_score,cumulative_score; |
1325 | int i; | ||
1326 | amb | 59 | |
1327 | amb | 1066 | /* must be a normal segment unless node1 is a super-node (see below). */ |
1328 | amb | 1078 | if((IsFakeNode(node1) || !IsSuperNode(node1p)) && !IsNormalSegment(segmentp)) |
1329 | amb | 34 | goto endloop; |
1330 | |||
1331 | amb | 1066 | /* must be a super segment if node1 is a super-node to give starting super-segment for finding middle route. */ |
1332 | amb | 1078 | if((!IsFakeNode(node1) && IsSuperNode(node1p)) && !IsSuperSegment(segmentp)) |
1333 | amb | 1066 | goto endloop; |
1334 | |||
1335 | amb | 680 | /* must obey one-way restrictions (unless profile allows) */ |
1336 | amb | 1078 | if(profile->oneway && IsOnewayFrom(segmentp,node1)) /* working backwards => disallow oneway *from* node1 */ |
1337 | amb | 1497 | { |
1338 | if(profile->allow!=Transports_Bicycle) | ||
1339 | goto endloop; | ||
1340 | amb | 95 | |
1341 | amb | 1497 | wayp=LookupWay(ways,segmentp->way,1); |
1342 | |||
1343 | amb | 1559 | if(!(wayp->type&Highway_CycleBothWays)) |
1344 | amb | 1497 | goto endloop; |
1345 | } | ||
1346 | |||
1347 | amb | 1078 | node2=OtherNode(segmentp,node1); |
1348 | amb | 64 | |
1349 | amb | 605 | if(IsFakeNode(node1) || IsFakeNode(node2)) |
1350 | amb | 637 | { |
1351 | amb | 1078 | seg2 =IndexFakeSegment(segmentp); |
1352 | amb | 637 | seg2r=IndexRealSegment(seg2); |
1353 | } | ||
1354 | amb | 605 | else |
1355 | amb | 637 | { |
1356 | amb | 1078 | seg2 =IndexSegment(segments,segmentp); |
1357 | amb | 637 | seg2r=seg2; |
1358 | } | ||
1359 | amb | 605 | |
1360 | amb | 699 | /* must not perform U-turn (unless profile allows) */ |
1361 | amb | 1579 | if(profile->turns && seg1!=NO_SEGMENT) |
1362 | amb | 1553 | { |
1363 | if(IsFakeNode(node1) || !IsSuperNode(node1p)) | ||
1364 | { | ||
1365 | if(seg1==seg2 || seg1==seg2r || seg1r==seg2 || (seg1r==seg2r && IsFakeUTurn(seg1,seg2))) | ||
1366 | goto endloop; | ||
1367 | } | ||
1368 | else | ||
1369 | { | ||
1370 | index_t superseg=FindSuperSegment(nodes,segments,ways,relations,profile,node1,seg1); | ||
1371 | |||
1372 | if(seg2==superseg) | ||
1373 | goto endloop; | ||
1374 | } | ||
1375 | } | ||
1376 | |||
1377 | amb | 680 | /* must obey turn relations */ |
1378 | amb | 1579 | if(turnrelation!=NO_RELATION && seg1!=NO_SEGMENT) |
1379 | amb | 596 | { |
1380 | amb | 637 | index_t turnrelation2=FindFirstTurnRelation2(relations,node1,seg2r); /* node2 -> node1 -> result1->next->node */ |
1381 | amb | 596 | |
1382 | amb | 637 | if(turnrelation2!=NO_RELATION && !IsTurnAllowed(relations,turnrelation2,node1,seg2r,seg1r,profile->allow)) |
1383 | amb | 596 | goto endloop; |
1384 | } | ||
1385 | |||
1386 | amb | 1078 | wayp=LookupWay(ways,segmentp->way,1); |
1387 | amb | 54 | |
1388 | amb | 680 | /* mode of transport must be allowed on the highway */ |
1389 | amb | 1078 | if(!(wayp->allow&profile->allow)) |
1390 | amb | 54 | goto endloop; |
1391 | |||
1392 | amb | 680 | /* must obey weight restriction (if exists) */ |
1393 | amb | 1078 | if(wayp->weight && wayp->weight<profile->weight) |
1394 | amb | 135 | goto endloop; |
1395 | |||
1396 | amb | 1066 | /* must obey height/width/length restriction (if exist) */ |
1397 | amb | 1078 | if((wayp->height && wayp->height<profile->height) || |
1398 | (wayp->width && wayp->width <profile->width ) || | ||
1399 | (wayp->length && wayp->length<profile->length)) | ||
1400 | amb | 135 | goto endloop; |
1401 | |||
1402 | amb | 1078 | segment_pref=profile->highway[HIGHWAY(wayp->type)]; |
1403 | amb | 298 | |
1404 | amb | 1066 | /* highway preferences must allow this highway */ |
1405 | if(segment_pref==0) | ||
1406 | goto endloop; | ||
1407 | |||
1408 | amb | 298 | for(i=1;i<Property_Count;i++) |
1409 | amb | 1550 | if(ways->file.props & PROPERTIES(i)) |
1410 | { | ||
1411 | if(wayp->props & PROPERTIES(i)) | ||
1412 | segment_pref*=profile->props_yes[i]; | ||
1413 | else | ||
1414 | segment_pref*=profile->props_no[i]; | ||
1415 | } | ||
1416 | amb | 298 | |
1417 | amb | 680 | /* profile preferences must allow this highway */ |
1418 | amb | 298 | if(segment_pref==0) |
1419 | goto endloop; | ||
1420 | |||
1421 | amb | 471 | if(!IsFakeNode(node2)) |
1422 | amb | 885 | node2p=LookupNode(nodes,node2,2); |
1423 | amb | 469 | |
1424 | amb | 885 | /* mode of transport must be allowed through node2 */ |
1425 | if(node2p && !(node2p->allow&profile->allow)) | ||
1426 | goto endloop; | ||
1427 | amb | 469 | |
1428 | amb | 1625 | /* calculate the score for the segment and cumulative */ |
1429 | amb | 166 | if(option_quickest==0) |
1430 | amb | 1168 | segment_score=(score_t)DISTANCE(segmentp->distance)/segment_pref; |
1431 | amb | 166 | else |
1432 | amb | 1078 | segment_score=(score_t)Duration(segmentp,wayp,profile)/segment_pref; |
1433 | amb | 59 | |
1434 | amb | 1626 | /* prefer not to follow two fake segments when one would do (special case) */ |
1435 | amb | 1625 | if(IsFakeSegment(seg1)) |
1436 | segment_score*=1.01; | ||
1437 | |||
1438 | amb | 170 | cumulative_score=result1->score+segment_score; |
1439 | amb | 166 | |
1440 | amb | 1625 | /* find whether the node/segment combination already exists */ |
1441 | amb | 605 | result2=FindResult(results,node2,seg2); |
1442 | amb | 34 | |
1443 | amb | 680 | if(!result2) /* New end node */ |
1444 | amb | 34 | { |
1445 | amb | 605 | result2=InsertResult(results,node2,seg2); |
1446 | result2->next=result1; /* working backwards */ | ||
1447 | amb | 170 | result2->score=cumulative_score; |
1448 | amb | 34 | } |
1449 | amb | 166 | else if(cumulative_score<result2->score) /* New end node is better */ |
1450 | amb | 34 | { |
1451 | amb | 605 | result2->next=result1; /* working backwards */ |
1452 | amb | 170 | result2->score=cumulative_score; |
1453 | amb | 1217 | } |
1454 | else | ||
1455 | goto endloop; | ||
1456 | amb | 34 | |
1457 | amb | 1217 | if(IsFakeNode(node1) || !IsSuperNode(node1p)) |
1458 | amb | 1289 | InsertInQueue(queue,result2,result2->score); |
1459 | amb | 34 | |
1460 | endloop: | ||
1461 | |||
1462 | amb | 303 | if(IsFakeNode(node1)) |
1463 | amb | 1078 | segmentp=NextFakeSegment(segmentp,node1); |
1464 | amb | 303 | else |
1465 | amb | 1078 | segmentp=NextSegment(segments,segmentp,node1); |
1466 | amb | 34 | } |
1467 | } | ||
1468 | |||
1469 | amb | 236 | FreeQueueList(queue); |
1470 | |||
1471 | amb | 112 | /* Check it worked */ |
1472 | |||
1473 | if(results->number==1) | ||
1474 | { | ||
1475 | amb | 1278 | #if DEBUG |
1476 | printf(" Failed\n"); | ||
1477 | #endif | ||
1478 | |||
1479 | amb | 1600 | #if !DEBUG |
1480 | if(!option_quiet) | ||
1481 | printf_last("Found Finish Route: Nodes checked = %d - Fail",results->number); | ||
1482 | #endif | ||
1483 | |||
1484 | amb | 112 | FreeResultsList(results); |
1485 | return(NULL); | ||
1486 | } | ||
1487 | |||
1488 | amb | 605 | /* Create a results structure with the node at the end of the segment opposite the start */ |
1489 | |||
1490 | amb | 1286 | results2=NewResultsList(8); |
1491 | amb | 605 | |
1492 | results2->finish_node=results->finish_node; | ||
1493 | |||
1494 | result3=FirstResult(results); | ||
1495 | |||
1496 | while(result3) | ||
1497 | { | ||
1498 | if(result3->next) | ||
1499 | { | ||
1500 | result2=InsertResult(results2,result3->next->node,result3->segment); | ||
1501 | |||
1502 | amb | 616 | result2->score=result3->next->score; |
1503 | amb | 605 | } |
1504 | |||
1505 | result3=NextResult(results,result3); | ||
1506 | } | ||
1507 | |||
1508 | /* Fix up the result->next pointers */ | ||
1509 | |||
1510 | result3=FirstResult(results); | ||
1511 | |||
1512 | while(result3) | ||
1513 | { | ||
1514 | if(result3->next && result3->next->next) | ||
1515 | { | ||
1516 | result1=FindResult(results2,result3->next->node,result3->segment); | ||
1517 | result2=FindResult(results2,result3->next->next->node,result3->next->segment); | ||
1518 | |||
1519 | result1->next=result2; | ||
1520 | } | ||
1521 | |||
1522 | result3=NextResult(results,result3); | ||
1523 | } | ||
1524 | |||
1525 | FreeResultsList(results); | ||
1526 | |||
1527 | amb | 1278 | #if DEBUG |
1528 | Result *s=FirstResult(results2); | ||
1529 | |||
1530 | while(s) | ||
1531 | { | ||
1532 | if(!IsFakeNode(s->node)) | ||
1533 | { | ||
1534 | Node *n=LookupNode(nodes,s->node,1); | ||
1535 | |||
1536 | if(IsSuperNode(n)) | ||
1537 | { | ||
1538 | Result *r=FindResult(results2,s->node,s->segment); | ||
1539 | |||
1540 | printf(" --------\n"); | ||
1541 | |||
1542 | while(r) | ||
1543 | { | ||
1544 | printf(" node=%"Pindex_t" segment=%"Pindex_t" score=%f\n",r->node,r->segment,r->score); | ||
1545 | |||
1546 | r=r->next; | ||
1547 | } | ||
1548 | } | ||
1549 | } | ||
1550 | |||
1551 | s=NextResult(results2,s); | ||
1552 | } | ||
1553 | #endif | ||
1554 | |||
1555 | amb | 1600 | #if !DEBUG |
1556 | if(!option_quiet) | ||
1557 | printf_last("Found Finish Route: Nodes checked = %d",results->number); | ||
1558 | #endif | ||
1559 | |||
1560 | amb | 605 | return(results2); |
1561 | amb | 34 | } |
1562 | |||
1563 | |||
1564 | /*++++++++++++++++++++++++++++++++++++++ | ||
1565 | amb | 95 | Create an optimum route given the set of super-nodes to follow. |
1566 | amb | 31 | |
1567 | amb | 58 | Results *CombineRoutes Returns the results from joining the super-nodes. |
1568 | amb | 55 | |
1569 | amb | 680 | Nodes *nodes The set of nodes to use. |
1570 | amb | 31 | |
1571 | Segments *segments The set of segments to use. | ||
1572 | |||
1573 | amb | 680 | Ways *ways The set of ways to use. |
1574 | amb | 31 | |
1575 | amb | 542 | Relations *relations The set of relations to use. |
1576 | |||
1577 | amb | 721 | Profile *profile The profile containing the transport type, speeds and allowed highways. |
1578 | |||
1579 | amb | 722 | Results *begin The set of results for the start of the route. |
1580 | |||
1581 | amb | 686 | Results *middle The set of results from the super-node route. |
1582 | amb | 1625 | |
1583 | Results *end The set of results for the end of the route. | ||
1584 | amb | 31 | ++++++++++++++++++++++++++++++++++++++*/ |
1585 | |||
1586 | amb | 1625 | Results *CombineRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,Results *begin,Results *middle,Results *end) |
1587 | amb | 31 | { |
1588 | amb | 1627 | Result *midres,*comres; |
1589 | amb | 31 | Results *combined; |
1590 | |||
1591 | amb | 1278 | #if DEBUG |
1592 | amb | 1625 | printf(" CombineRoutes(...,[begin has %d nodes],[middle has %d nodes],[end has %d nodes])\n",begin->number,middle->number,end->number); |
1593 | amb | 1278 | #endif |
1594 | |||
1595 | amb | 1600 | #if !DEBUG |
1596 | if(!option_quiet) | ||
1597 | printf_first("Finding Combined Route: Nodes = 0"); | ||
1598 | #endif | ||
1599 | |||
1600 | amb | 1286 | combined=NewResultsList(10); |
1601 | amb | 31 | |
1602 | amb | 735 | combined->start_node=begin->start_node; |
1603 | combined->prev_segment=begin->prev_segment; | ||
1604 | amb | 165 | |
1605 | amb | 722 | /* Insert the start point */ |
1606 | amb | 31 | |
1607 | amb | 686 | midres=FindResult(middle,middle->start_node,middle->prev_segment); |
1608 | amb | 31 | |
1609 | amb | 1627 | comres=InsertResult(combined,combined->start_node,combined->prev_segment); |
1610 | amb | 31 | |
1611 | amb | 722 | /* Insert the start of the route */ |
1612 | |||
1613 | if(begin->number>1 && midres->next) | ||
1614 | { | ||
1615 | Result *begres; | ||
1616 | |||
1617 | midres=FindResult(middle,midres->next->node,midres->next->segment); | ||
1618 | |||
1619 | begres=FindResult(begin,midres->node,midres->segment); | ||
1620 | |||
1621 | FixForwardRoute(begin,begres); | ||
1622 | |||
1623 | if(midres->next && midres->next->node==midres->node) | ||
1624 | midres=midres->next; | ||
1625 | |||
1626 | begres=FindResult(begin,begin->start_node,begin->prev_segment); | ||
1627 | |||
1628 | begres=begres->next; | ||
1629 | |||
1630 | do | ||
1631 | { | ||
1632 | Result *comres2; | ||
1633 | |||
1634 | comres2=InsertResult(combined,begres->node,begres->segment); | ||
1635 | |||
1636 | amb | 1276 | comres2->score=begres->score; |
1637 | amb | 1627 | comres2->prev=comres; |
1638 | amb | 722 | |
1639 | begres=begres->next; | ||
1640 | |||
1641 | amb | 1627 | comres=comres2; |
1642 | amb | 722 | } |
1643 | while(begres); | ||
1644 | } | ||
1645 | |||
1646 | /* Sort out the combined route */ | ||
1647 | |||
1648 | amb | 1625 | while(midres->next) |
1649 | amb | 58 | { |
1650 | amb | 1627 | Results *results=FindNormalRoute(nodes,segments,ways,relations,profile,comres->node,comres->segment,midres->next->node); |
1651 | amb | 686 | Result *result; |
1652 | amb | 594 | |
1653 | amb | 1625 | if(!results) |
1654 | amb | 31 | { |
1655 | amb | 1600 | #if !DEBUG |
1656 | amb | 1625 | if(!option_quiet) |
1657 | printf_last("Found Combined Route: Nodes = %d - Fail",combined->number); | ||
1658 | amb | 1600 | #endif |
1659 | |||
1660 | amb | 1625 | FreeResultsList(combined); |
1661 | return(NULL); | ||
1662 | } | ||
1663 | amb | 677 | |
1664 | amb | 1627 | result=FindResult(results,midres->node,comres->segment); |
1665 | amb | 31 | |
1666 | amb | 1625 | result=result->next; |
1667 | amb | 36 | |
1668 | amb | 1625 | /* |
1669 | * midres midres->next | ||
1670 | * = = | ||
1671 | * ---*----------------------------------* = middle | ||
1672 | * | ||
1673 | * ---*----.----.----.----.----.----.----* = results | ||
1674 | * = | ||
1675 | * result | ||
1676 | * | ||
1677 | * ---*----.----.----.----.----.----.----* = combined | ||
1678 | * = = | ||
1679 | amb | 1627 | * comres comres2 |
1680 | amb | 1625 | */ |
1681 | amb | 605 | |
1682 | amb | 1625 | do |
1683 | { | ||
1684 | Result *comres2; | ||
1685 | amb | 31 | |
1686 | amb | 1625 | comres2=InsertResult(combined,result->node,result->segment); |
1687 | amb | 605 | |
1688 | amb | 1625 | comres2->score=midres->score+result->score; |
1689 | amb | 1627 | comres2->prev=comres; |
1690 | amb | 605 | |
1691 | amb | 1625 | result=result->next; |
1692 | amb | 686 | |
1693 | amb | 1627 | comres=comres2; |
1694 | amb | 605 | } |
1695 | amb | 1625 | while(result); |
1696 | amb | 31 | |
1697 | amb | 1625 | FreeResultsList(results); |
1698 | |||
1699 | amb | 686 | midres=midres->next; |
1700 | amb | 31 | } |
1701 | |||
1702 | amb | 1625 | /* Insert the end of the route */ |
1703 | |||
1704 | if(end->number>1) | ||
1705 | { | ||
1706 | Result *endres=FindResult(end,midres->node,midres->segment); | ||
1707 | |||
1708 | while(endres->next) | ||
1709 | { | ||
1710 | Result *comres2; | ||
1711 | |||
1712 | comres2=InsertResult(combined,endres->next->node,endres->next->segment); | ||
1713 | |||
1714 | amb | 1627 | comres2->score=comres->score+(endres->score-endres->next->score); |
1715 | comres2->prev=comres; | ||
1716 | amb | 1625 | |
1717 | endres=endres->next; | ||
1718 | |||
1719 | amb | 1627 | comres=comres2; |
1720 | amb | 1625 | } |
1721 | } | ||
1722 | |||
1723 | /* Turn the route round */ | ||
1724 | |||
1725 | amb | 1627 | combined->finish_node=comres->node; |
1726 | combined->last_segment=comres->segment; | ||
1727 | amb | 605 | |
1728 | amb | 1627 | FixForwardRoute(combined,comres); |
1729 | |||
1730 | amb | 1278 | #if DEBUG |
1731 | Result *r=FindResult(combined,combined->start_node,combined->prev_segment); | ||
1732 | |||
1733 | amb | 1625 | printf(" CombinedRoute(...)\n"); |
1734 | |||
1735 | amb | 1278 | while(r) |
1736 | { | ||
1737 | printf(" node=%"Pindex_t" segment=%"Pindex_t" score=%f\n",r->node,r->segment,r->score); | ||
1738 | |||
1739 | r=r->next; | ||
1740 | } | ||
1741 | #endif | ||
1742 | |||
1743 | amb | 1600 | #if !DEBUG |
1744 | if(!option_quiet) | ||
1745 | printf_last("Found Combined Route: Nodes = %d",combined->number); | ||
1746 | #endif | ||
1747 | |||
1748 | amb | 55 | return(combined); |
1749 | amb | 31 | } |
1750 | amb | 290 | |
1751 | |||
1752 | /*++++++++++++++++++++++++++++++++++++++ | ||
1753 | amb | 605 | Fix the forward route (i.e. setup next pointers for forward path from prev nodes on reverse path). |
1754 | amb | 290 | |
1755 | Results *results The set of results to update. | ||
1756 | |||
1757 | amb | 680 | Result *finish_result The result for the finish point. |
1758 | amb | 290 | ++++++++++++++++++++++++++++++++++++++*/ |
1759 | |||
1760 | amb | 605 | void FixForwardRoute(Results *results,Result *finish_result) |
1761 | amb | 290 | { |
1762 | amb | 605 | Result *result2=finish_result; |
1763 | amb | 290 | |
1764 | amb | 828 | /* Erase the old route if there is one */ |
1765 | |||
1766 | if(results->finish_node!=NO_NODE) | ||
1767 | { | ||
1768 | Result *result1=FirstResult(results); | ||
1769 | |||
1770 | while(result1) | ||
1771 | { | ||
1772 | result1->next=NULL; | ||
1773 | |||
1774 | result1=NextResult(results,result1); | ||
1775 | } | ||
1776 | } | ||
1777 | |||
1778 | amb | 290 | /* Create the forward links for the optimum path */ |
1779 | |||
1780 | do | ||
1781 | { | ||
1782 | amb | 594 | Result *result1; |
1783 | |||
1784 | amb | 605 | if(result2->prev) |
1785 | amb | 290 | { |
1786 | amb | 605 | index_t node1=result2->prev->node; |
1787 | index_t seg1=result2->prev->segment; | ||
1788 | amb | 290 | |
1789 | amb | 605 | result1=FindResult(results,node1,seg1); |
1790 | amb | 290 | |
1791 | amb | 1166 | logassert(!result1->next,"Unable to reverse route through results (report a bug)"); /* Bugs elsewhere can lead to infinite loop here. */ |
1792 | amb | 712 | |
1793 | amb | 605 | result1->next=result2; |
1794 | amb | 290 | |
1795 | result2=result1; | ||
1796 | } | ||
1797 | else | ||
1798 | result2=NULL; | ||
1799 | } | ||
1800 | while(result2); | ||
1801 | |||
1802 | amb | 605 | results->finish_node=finish_result->node; |
1803 | results->last_segment=finish_result->segment; | ||
1804 | amb | 290 | } |
Properties
Name | Value |
---|---|
cvs:description | Route optimiser. |