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 *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); }