Results *FindNormalRoute(Nodes *nodes,Segments *segments,Ways *ways,index_t start,index_t finish,Profile *profile) { Results *results; Queue *queue; index_t node1,node2; score_t finish_score; double finish_lat,finish_lon; Result *result1,*result2; Segment *segment; Way *way; /* Set up the finish conditions */ finish_score=INF_SCORE; if(IsFakeNode(finish)) GetFakeLatLong(finish,&finish_lat,&finish_lon); else GetLatLong(nodes,finish,&finish_lat,&finish_lon); /* Create the list of results and insert the first node into the queue */ results=NewResultsList(8); results->start=start; results->finish=finish; result1=InsertResult(results,start); ZeroResult(result1); queue=NewQueueList(); InsertInQueue(queue,result1); /* Loop across all nodes in the queue */ while((result1=PopFromQueue(queue))) { if(result1->score>finish_score) continue; node1=result1->node; if(IsFakeNode(node1)) segment=FirstFakeSegment(node1); else segment=FirstSegment(segments,nodes,node1); while(segment) { score_t segment_pref,segment_score,cumulative_score; int i; node2=OtherNode(segment,node1); /* need this here because we use node2 later */ if(!IsNormalSegment(segment)) goto endloop; if(profile->oneway && IsOnewayTo(segment,node1)) goto endloop; if(result1->prev==node2) goto endloop; if(node2!=finish && !IsFakeNode(node2) && IsSuperNode(nodes,node2)) goto endloop; way=LookupWay(ways,segment->way); if(!(way->allow&profile->allow)) goto endloop; if(!profile->highway[HIGHWAY(way->type)]) goto endloop; if(way->weight && way->weight<profile->weight) goto endloop; if((way->height && way->height<profile->height) || (way->width && way->width <profile->width ) || (way->length && way->length<profile->length)) goto endloop; segment_pref=profile->highway[HIGHWAY(way->type)]; for(i=1;i<Property_Count;i++) if(ways->props & PROPERTIES(i)) { if(way->props & PROPERTIES(i)) segment_pref*=profile->props_yes[i]; else segment_pref*=profile->props_no[i]; } if(segment_pref==0) goto endloop; if(option_quickest==0) segment_score=(score_t)DISTANCE(segment->distance)/segment_pref; else segment_score=(score_t)Duration(segment,way,profile)/segment_pref; cumulative_score=result1->score+segment_score; if(cumulative_score>finish_score) goto endloop; result2=FindResult(results,node2); if(!result2) /* New end node */ { result2=InsertResult(results,node2); result2->prev=node1; result2->next=NO_NODE; result2->score=cumulative_score; result2->segment=segment; if(node2==finish) { finish_score=cumulative_score; } else { result2->sortby=result2->score; InsertInQueue(queue,result2); } } else if(cumulative_score<result2->score) /* New end node is better */ { result2->prev=node1; result2->score=cumulative_score; result2->segment=segment; if(node2==finish) { finish_score=cumulative_score; } else { result2->sortby=result2->score; if(result2->score<finish_score) InsertInQueue(queue,result2); } } endloop: if(IsFakeNode(node1)) segment=NextFakeSegment(segment,node1); else if(IsFakeNode(node2)) segment=NULL; /* cannot call NextSegment() with a fake segment */ else { segment=NextSegment(segments,segment,node1); if(!segment && IsFakeNode(finish)) segment=ExtraFakeSegment(node1,finish); } } } FreeQueueList(queue); /* Check it worked */ if(!FindResult(results,finish)) { FreeResultsList(results); return(NULL); } FixForwardRoute(results,finish); return(results); }
Results *FindMiddleRoute(Nodes *nodes,Segments *segments,Ways *ways,Results *begin,Results *end,Profile *profile) { Results *results; Queue *queue; index_t node1,node2; index_t end_prev; score_t finish_score; double finish_lat,finish_lon; Result *result1,*result2,*result3; Segment *segment; Way *way; if(!option_quiet) { printf("Routing: Super-Nodes checked = 0"); fflush(stdout); } /* Set up the finish conditions */ finish_score=INF_DISTANCE; end_prev=NO_NODE; if(IsFakeNode(end->finish)) GetFakeLatLong(end->finish,&finish_lat,&finish_lon); else GetLatLong(nodes,end->finish,&finish_lat,&finish_lon); /* Create the list of results and insert the first node into the queue */ results=NewResultsList(2048); results->start=begin->start; results->finish=end->finish; result1=InsertResult(results,begin->start); result3=FindResult(begin,begin->start); *result1=*result3; queue=NewQueueList(); /* Insert the finish points of the beginning part of the path into the queue */ result3=FirstResult(begin); while(result3) { if(result3->node!=begin->start && !IsFakeNode(result3->node) && IsSuperNode(nodes,result3->node)) { result2=InsertResult(results,result3->node); *result2=*result3; result2->prev=begin->start; result2->sortby=result2->score; InsertInQueue(queue,result2); } result3=NextResult(begin,result3); } if(begin->number==1) InsertInQueue(queue,result1); /* Loop across all nodes in the queue */ while((result1=PopFromQueue(queue))) { if(result1->score>finish_score) continue; node1=result1->node; segment=FirstSegment(segments,nodes,node1); while(segment) { score_t segment_pref,segment_score,cumulative_score; int i; if(!IsSuperSegment(segment)) goto endloop; if(profile->oneway && IsOnewayTo(segment,node1)) goto endloop; node2=OtherNode(segment,node1); if(result1->prev==node2) goto endloop; way=LookupWay(ways,segment->way); if(!(way->allow&profile->allow)) goto endloop; if(!profile->highway[HIGHWAY(way->type)]) goto endloop; if(way->weight && way->weight<profile->weight) goto endloop; if((way->height && way->height<profile->height) || (way->width && way->width <profile->width ) || (way->length && way->length<profile->length)) goto endloop; segment_pref=profile->highway[HIGHWAY(way->type)]; for(i=1;i<Property_Count;i++) if(ways->props & PROPERTIES(i)) { if(way->props & PROPERTIES(i)) segment_pref*=profile->props_yes[i]; else segment_pref*=profile->props_no[i]; } if(segment_pref==0) goto endloop; if(option_quickest==0) segment_score=(score_t)DISTANCE(segment->distance)/segment_pref; else segment_score=(score_t)Duration(segment,way,profile)/segment_pref; cumulative_score=result1->score+segment_score; if(cumulative_score>finish_score) goto endloop; result2=FindResult(results,node2); if(!result2) /* New end node */ { result2=InsertResult(results,node2); result2->prev=node1; result2->next=NO_NODE; result2->score=cumulative_score; result2->segment=segment; if((result3=FindResult(end,node2))) { if((result2->score+result3->score)<finish_score) { finish_score=result2->score+result3->score; end_prev=node2; } } else { double lat,lon; distance_t direct; GetLatLong(nodes,node2,&lat,&lon); direct=Distance(lat,lon,finish_lat,finish_lon); if(option_quickest==0) result2->sortby=result2->score+(score_t)direct/profile->max_pref; else result2->sortby=result2->score+(score_t)distance_speed_to_duration(direct,profile->max_speed)/profile->max_pref; InsertInQueue(queue,result2); } } else if(cumulative_score<result2->score) /* New end node is better */ { result2->prev=node1; result2->score=cumulative_score; result2->segment=segment; if((result3=FindResult(end,node2))) { if((result2->score+result3->score)<finish_score) { finish_score=result2->score+result3->score; end_prev=node2; } } else if(result2->score<finish_score) { double lat,lon; distance_t direct; GetLatLong(nodes,node2,&lat,&lon); direct=Distance(lat,lon,finish_lat,finish_lon); if(option_quickest==0) result2->sortby=result2->score+(score_t)direct/profile->max_pref; else result2->sortby=result2->score+(score_t)distance_speed_to_duration(direct,profile->max_speed)/profile->max_pref; InsertInQueue(queue,result2); } } endloop: if(!option_quiet && !(results->number%10000)) { printf("\rRouting: Super-Nodes checked = %d",results->number); fflush(stdout); } segment=NextSegment(segments,segment,node1); } } if(!option_quiet) { printf("\rRouting: Super-Nodes checked = %d\n",results->number); fflush(stdout); } /* Finish off the end part of the route. */ if(!FindResult(results,end->finish) && end_prev!=NO_NODE) { result2=InsertResult(results,end->finish); result3=FindResult(end,end->finish); *result2=*result3; result2->prev=end_prev; result2->score=finish_score; } FreeQueueList(queue); /* Check it worked */ if(end_prev==NO_NODE) { FreeResultsList(results); return(NULL); } FixForwardRoute(results,end->finish); return(results); }
Results *FindMiddleRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,Results *begin,Results *end) { Results *results; Queue *queue; Result *finish_result; score_t finish_score; double finish_lat,finish_lon; Result *result1,*result2,*result3,*result4; if(!option_quiet) printf_first("Routing: Super-Nodes checked = 0"); /* Set up the finish conditions */ finish_score=INF_DISTANCE; finish_result=NULL; if(IsFakeNode(end->finish_node)) GetFakeLatLong(end->finish_node,&finish_lat,&finish_lon); else GetLatLong(nodes,end->finish_node,&finish_lat,&finish_lon); /* Create the list of results and insert the first node into the queue */ results=NewResultsList(65536); results->start_node=begin->start_node; results->prev_segment=begin->prev_segment; if(begin->number==1) { if(begin->prev_segment==NO_SEGMENT) results->prev_segment=NO_SEGMENT; else { index_t superseg=FindSuperSegment(nodes,segments,ways,relations,profile,begin->start_node,begin->prev_segment); results->prev_segment=superseg; } } result1=InsertResult(results,results->start_node,results->prev_segment); queue=NewQueueList(); /* Insert the finish points of the beginning part of the path into the queue, translating the segments into super-segments. */ result3=FirstResult(begin); while(result3) { if((results->start_node!=result3->node || results->prev_segment!=result3->segment) && !IsFakeNode(result3->node) && IsSuperNode(LookupNode(nodes,result3->node,1))) { Result *result5=result1; index_t superseg=FindSuperSegment(nodes,segments,ways,relations,profile,result3->node,result3->segment); if(superseg!=result3->segment) { result5=InsertResult(results,result3->node,result3->segment); result5->prev=result1; } if(!FindResult(results,result3->node,superseg)) { result2=InsertResult(results,result3->node,superseg); result2->prev=result5; result2->score=result3->score; result2->sortby=result3->score; InsertInQueue(queue,result2); if((result4=FindResult(end,result2->node,result2->segment))) { if((result2->score+result4->score)<finish_score) { finish_score=result2->score+result4->score; finish_result=result2; } } } } result3=NextResult(begin,result3); } if(begin->number==1) InsertInQueue(queue,result1); /* Loop across all nodes in the queue */ while((result1=PopFromQueue(queue))) { index_t node1,seg1; Segment *segment; index_t turnrelation=NO_RELATION; /* score must be better than current best score */ if(result1->score>finish_score) continue; node1=result1->node; seg1=result1->segment; /* lookup if a turn restriction applies */ if(profile->turns && IsTurnRestrictedNode(LookupNode(nodes,node1,1))) /* node1 cannot be a fake node (must be a super-node) */ turnrelation=FindFirstTurnRelation2(relations,node1,seg1); /* Loop across all segments */ segment=FirstSegment(segments,nodes,node1,1); /* node1 cannot be a fake node (must be a super-node) */ while(segment) { Way *way; Node *node; index_t node2,seg2; score_t segment_pref,segment_score,cumulative_score; int i; /* must be a super segment */ if(!IsSuperSegment(segment)) goto endloop; /* must obey one-way restrictions (unless profile allows) */ if(profile->oneway && IsOnewayTo(segment,node1)) goto endloop; node2=OtherNode(segment,node1); seg2=IndexSegment(segments,segment); /* node2 cannot be a fake node (must be a super-node) */ /* must not perform U-turn */ if(seg1==seg2) /* No fake segments, applies to all profiles */ goto endloop; /* must obey turn relations */ if(turnrelation!=NO_RELATION && !IsTurnAllowed(relations,turnrelation,node1,seg1,seg2,profile->allow)) goto endloop; way=LookupWay(ways,segment->way,1); /* transport must be allowed on the highway */ if(!(way->allow&profile->allow)) goto endloop; /* must obey weight restriction (if exists) */ if(way->weight && way->weight<profile->weight) goto endloop; /* must obey height/width/length restriction (if exists) */ if((way->height && way->height<profile->height) || (way->width && way->width <profile->width ) || (way->length && way->length<profile->length)) goto endloop; segment_pref=profile->highway[HIGHWAY(way->type)]; for(i=1;i<Property_Count;i++) if(ways->file.props & PROPERTIES(i)) { if(way->props & PROPERTIES(i)) segment_pref*=profile->props_yes[i]; else segment_pref*=profile->props_no[i]; } /* profile preferences must allow this highway */ if(segment_pref==0) goto endloop; node=LookupNode(nodes,node2,2); /* node2 cannot be a fake node (must be a super-node) */ /* mode of transport must be allowed through node2 */ if(!(node->allow&profile->allow)) goto endloop; if(option_quickest==0) segment_score=(score_t)DISTANCE(segment->distance)/segment_pref; else segment_score=(score_t)Duration(segment,way,profile)/segment_pref; cumulative_score=result1->score+segment_score; /* score must be better than current best score */ if(cumulative_score>finish_score) goto endloop; result2=FindResult(results,node2,seg2); if(!result2) /* New end node/segment pair */ { result2=InsertResult(results,node2,seg2); result2->prev=result1; result2->score=cumulative_score; if((result3=FindResult(end,node2,seg2))) { if((result2->score+result3->score)<finish_score) { finish_score=result2->score+result3->score; finish_result=result2; } } else { double lat,lon; distance_t direct; GetLatLong(nodes,node2,&lat,&lon); /* node2 cannot be a fake node (must be a super-node) */ direct=Distance(lat,lon,finish_lat,finish_lon); if(option_quickest==0) result2->sortby=result2->score+(score_t)direct/profile->max_pref; else result2->sortby=result2->score+(score_t)distance_speed_to_duration(direct,profile->max_speed)/profile->max_pref; InsertInQueue(queue,result2); } } else if(cumulative_score<result2->score) /* New end node/segment pair is better */ { result2->prev=result1; result2->score=cumulative_score; if((result3=FindResult(end,node2,seg2))) { if((result2->score+result3->score)<finish_score) { finish_score=result2->score+result3->score; finish_result=result2; } } else if(result2->score<finish_score) { double lat,lon; distance_t direct; GetLatLong(nodes,node2,&lat,&lon); /* node2 cannot be a fake node (must be a super-node) */ direct=Distance(lat,lon,finish_lat,finish_lon); if(option_quickest==0) result2->sortby=result2->score+(score_t)direct/profile->max_pref; else result2->sortby=result2->score+(score_t)distance_speed_to_duration(direct,profile->max_speed)/profile->max_pref; InsertInQueue(queue,result2); } } if(!option_quiet && !(results->number%1000)) printf_middle("Routing: Super-Nodes checked = %d",results->number); endloop: segment=NextSegment(segments,segment,node1); /* node1 cannot be a fake node (must be a super-node) */ } } if(!option_quiet) printf_last("Routing: Super-Nodes checked = %d",results->number); FreeQueueList(queue); /* Check it worked */ if(!finish_result) { FreeResultsList(results); return(NULL); } /* Finish off the end part of the route */ if(finish_result->node!=end->finish_node) { result3=InsertResult(results,end->finish_node,NO_SEGMENT); result3->prev=finish_result; result3->score=finish_score; finish_result=result3; } FixForwardRoute(results,finish_result); return(results); }
Results *FindNormalRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,index_t start_node,index_t prev_segment,index_t finish_node) { Results *results; Queue *queue; score_t finish_score; double finish_lat,finish_lon; Result *finish_result; Result *result1,*result2; /* Set up the finish conditions */ finish_score=INF_SCORE; finish_result=NULL; if(IsFakeNode(finish_node)) GetFakeLatLong(finish_node,&finish_lat,&finish_lon); else GetLatLong(nodes,finish_node,&finish_lat,&finish_lon); /* Create the list of results and insert the first node into the queue */ results=NewResultsList(64); results->start_node=start_node; results->prev_segment=prev_segment; result1=InsertResult(results,results->start_node,results->prev_segment); queue=NewQueueList(); InsertInQueue(queue,result1); /* Loop across all nodes in the queue */ while((result1=PopFromQueue(queue))) { Segment *segment; index_t node1,seg1,seg1r; index_t turnrelation=NO_RELATION; /* score must be better than current best score */ if(result1->score>finish_score) continue; node1=result1->node; seg1=result1->segment; if(IsFakeSegment(seg1)) seg1r=IndexRealSegment(seg1); else seg1r=seg1; /* lookup if a turn restriction applies */ if(profile->turns && !IsFakeNode(node1) && IsTurnRestrictedNode(LookupNode(nodes,node1,1))) turnrelation=FindFirstTurnRelation2(relations,node1,seg1r); /* Loop across all segments */ if(IsFakeNode(node1)) segment=FirstFakeSegment(node1); else segment=FirstSegment(segments,nodes,node1,1); while(segment) { Way *way; index_t node2,seg2,seg2r; score_t segment_pref,segment_score,cumulative_score; int i; node2=OtherNode(segment,node1); /* need this here because we use node2 at the end of the loop */ /* must be a normal segment */ if(!IsNormalSegment(segment)) goto endloop; /* must obey one-way restrictions (unless profile allows) */ if(profile->oneway && IsOnewayTo(segment,node1)) goto endloop; if(IsFakeNode(node1) || IsFakeNode(node2)) { seg2 =IndexFakeSegment(segment); seg2r=IndexRealSegment(seg2); } else { seg2 =IndexSegment(segments,segment); seg2r=seg2; } /* must not perform U-turn (unless profile allows) */ if(profile->turns && (seg1==seg2 || seg1==seg2r || seg1r==seg2 || (seg1r==seg2r && IsFakeUTurn(seg1,seg2)))) goto endloop; /* must obey turn relations */ if(turnrelation!=NO_RELATION && !IsTurnAllowed(relations,turnrelation,node1,seg1r,seg2r,profile->allow)) goto endloop; /* must not pass over super-node */ if(node2!=finish_node && !IsFakeNode(node2) && IsSuperNode(LookupNode(nodes,node2,2))) goto endloop; way=LookupWay(ways,segment->way,1); /* mode of transport must be allowed on the highway */ if(!(way->allow&profile->allow)) goto endloop; /* must obey weight restriction (if exists) */ if(way->weight && way->weight<profile->weight) goto endloop; /* must obey height/width/length restriction (if exists) */ if((way->height && way->height<profile->height) || (way->width && way->width <profile->width ) || (way->length && way->length<profile->length)) goto endloop; segment_pref=profile->highway[HIGHWAY(way->type)]; for(i=1;i<Property_Count;i++) if(ways->file.props & PROPERTIES(i)) { if(way->props & PROPERTIES(i)) segment_pref*=profile->props_yes[i]; else segment_pref*=profile->props_no[i]; } /* profile preferences must allow this highway */ if(segment_pref==0) goto endloop; /* mode of transport must be allowed through node2 */ if(!IsFakeNode(node2)) { Node *node=LookupNode(nodes,node2,2); if(!(node->allow&profile->allow)) goto endloop; } if(option_quickest==0) segment_score=(score_t)DISTANCE(segment->distance)/segment_pref; else segment_score=(score_t)Duration(segment,way,profile)/segment_pref; cumulative_score=result1->score+segment_score; /* score must be better than current best score */ if(cumulative_score>finish_score) goto endloop; result2=FindResult(results,node2,seg2); if(!result2) /* New end node/segment combination */ { result2=InsertResult(results,node2,seg2); result2->prev=result1; result2->score=cumulative_score; if(node2==finish_node) { if(cumulative_score<finish_score) { finish_score=cumulative_score; finish_result=result2; } } else { result2->sortby=result2->score; InsertInQueue(queue,result2); } } else if(cumulative_score<result2->score) /* New score for end node/segment combination is better */ { result2->prev=result1; result2->score=cumulative_score; result2->segment=seg2; if(node2==finish_node) { if(cumulative_score<finish_score) { finish_score=cumulative_score; finish_result=result2; } } else { result2->sortby=result2->score; if(result2->score<finish_score) InsertInQueue(queue,result2); } } endloop: if(IsFakeNode(node1)) segment=NextFakeSegment(segment,node1); else if(IsFakeNode(node2)) segment=NULL; /* cannot call NextSegment() with a fake segment */ else { segment=NextSegment(segments,segment,node1); if(!segment && IsFakeNode(finish_node)) segment=ExtraFakeSegment(node1,finish_node); } } } FreeQueueList(queue); /* Check it worked */ if(!finish_result) { FreeResultsList(results); return(NULL); } FixForwardRoute(results,finish_result); return(results); }
Results *CombineRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,Results *begin,Results *middle) { Result *midres,*comres1; Results *combined; combined=NewResultsList(256); combined->start_node=begin->start_node; combined->prev_segment=begin->prev_segment; /* Insert the start point */ midres=FindResult(middle,middle->start_node,middle->prev_segment); comres1=InsertResult(combined,combined->start_node,combined->prev_segment); /* Insert the start of the route */ if(begin->number>1 && midres->next) { Result *begres; midres=FindResult(middle,midres->next->node,midres->next->segment); begres=FindResult(begin,midres->node,midres->segment); FixForwardRoute(begin,begres); if(midres->next && midres->next->node==midres->node) midres=midres->next; begres=FindResult(begin,begin->start_node,begin->prev_segment); begres=begres->next; do { Result *comres2; comres2=InsertResult(combined,begres->node,begres->segment); comres2->score=begres->score+comres1->score; comres2->prev=comres1; begres=begres->next; comres1=comres2; } while(begres); } /* Sort out the combined route */ do { Result *result; if(midres->next) { Results *results=FindNormalRoute(nodes,segments,ways,relations,profile,comres1->node,comres1->segment,midres->next->node); if(!results) return(NULL); result=FindResult(results,midres->node,comres1->segment); result=result->next; /* * midres midres->next * = = * ---*----------------------------------* = middle * * ---*----.----.----.----.----.----.----* = results * = * result * * ---*----.----.----.----.----.----.----* = combined * = = * comres1 comres2 */ do { Result *comres2; comres2=InsertResult(combined,result->node,result->segment); comres2->score=result->score+comres1->score; comres2->prev=comres1; result=result->next; comres1=comres2; } while(result); FreeResultsList(results); } midres=midres->next; } while(midres); FixForwardRoute(combined,comres1); return(combined); }