introduce roundabout-turns into instruction set
This commit is contained in:
		
							parent
							
								
									8d68d4c050
								
							
						
					
					
						commit
						1544a08ea2
					
				| @ -1,3 +1,11 @@ | |||||||
|  | # 5.1.0 | ||||||
|  |    - API: | ||||||
|  |      - added roundabout-turn instruction. The instruction indicates a small roundabout that is treated as an intersection | ||||||
|  |         (turn right at the roundabout for first exit, go straight at the roundabout...) | ||||||
|  | 
 | ||||||
|  |    - Infrastructure | ||||||
|  |     - BREAKING: reordered internal instruction types. This breaks the data format | ||||||
|  | 
 | ||||||
| # 5.0.0 | # 5.0.0 | ||||||
|    Changes with regard 5.0.0 RC2: |    Changes with regard 5.0.0 RC2: | ||||||
|    - API: |    - API: | ||||||
|  | |||||||
							
								
								
									
										369
									
								
								features/guidance/roundabout-turn.feature
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										369
									
								
								features/guidance/roundabout-turn.feature
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,369 @@ | |||||||
|  | @routing  @guidance | ||||||
|  | Feature: Basic Roundabout | ||||||
|  | 
 | ||||||
|  |     Background: | ||||||
|  |         Given the profile "car" | ||||||
|  |         Given a grid size of 3 meters | ||||||
|  | 
 | ||||||
|  |     Scenario: Enter and Exit | ||||||
|  |         Given the node map | ||||||
|  |             |   |   | a |   |   | | ||||||
|  |             |   |   | b |   |   | | ||||||
|  |             | h | g |   | c | d | | ||||||
|  |             |   |   | e |   |   | | ||||||
|  |             |   |   | f |   |   | | ||||||
|  | 
 | ||||||
|  |        And the ways | ||||||
|  |             | nodes  | junction   | | ||||||
|  |             | ab     |            | | ||||||
|  |             | cd     |            | | ||||||
|  |             | ef     |            | | ||||||
|  |             | gh     |            | | ||||||
|  |             | bgecb  | roundabout | | ||||||
|  | 
 | ||||||
|  |        When I route I should get | ||||||
|  |            | waypoints | route    | turns                                         | | ||||||
|  |            | a,d       | ab,cd,cd | depart,roundabout_turn left exit-3,arrive     | | ||||||
|  |            | a,f       | ab,ef,ef | depart,roundabout_turn straight exit-2,arrive | | ||||||
|  |            | a,h       | ab,gh,gh | depart,roundabout_turn right exit-1,arrive    | | ||||||
|  |            | d,f       | cd,ef,ef | depart,roundabout_turn left exit-3,arrive     | | ||||||
|  |            | d,h       | cd,gh,gh | depart,roundabout_turn straight exit-2,arrive | | ||||||
|  |            | d,a       | cd,ab,ab | depart,roundabout_turn right exit-1,arrive    | | ||||||
|  |            | f,h       | ef,gh,gh | depart,roundabout_turn left exit-3,arrive     | | ||||||
|  |            | f,a       | ef,ab,ab | depart,roundabout_turn straight exit-2,arrive | | ||||||
|  |            | f,d       | ef,cd,cd | depart,roundabout_turn right exit-1,arrive    | | ||||||
|  |            | h,a       | gh,ab,ab | depart,roundabout_turn left exit-3,arrive     | | ||||||
|  |            | h,d       | gh,cd,cd | depart,roundabout_turn straight exit-2,arrive | | ||||||
|  |            | h,f       | gh,ef,ef | depart,roundabout_turn right exit-1,arrive    | | ||||||
|  | 
 | ||||||
|  |     Scenario: Enter and Exit - Rotated | ||||||
|  |         Given the node map | ||||||
|  |             | a |   |   | d | | ||||||
|  |             |   | b | c |   | | ||||||
|  |             |   | g | e |   | | ||||||
|  |             | h |   |   | f | | ||||||
|  | 
 | ||||||
|  |        And the ways | ||||||
|  |             | nodes  | junction   | | ||||||
|  |             | ab     |            | | ||||||
|  |             | cd     |            | | ||||||
|  |             | ef     |            | | ||||||
|  |             | gh     |            | | ||||||
|  |             | bgecb  | roundabout | | ||||||
|  | 
 | ||||||
|  |        When I route I should get | ||||||
|  |            | waypoints | route    | turns                                         | | ||||||
|  |            | a,d       | ab,cd,cd | depart,roundabout_turn left exit-3,arrive     | | ||||||
|  |            | a,f       | ab,ef,ef | depart,roundabout_turn straight exit-2,arrive | | ||||||
|  |            | a,h       | ab,gh,gh | depart,roundabout_turn right exit-1,arrive    | | ||||||
|  |            | d,f       | cd,ef,ef | depart,roundabout_turn left exit-3,arrive     | | ||||||
|  |            | d,h       | cd,gh,gh | depart,roundabout_turn straight exit-2,arrive | | ||||||
|  |            | d,a       | cd,ab,ab | depart,roundabout_turn right exit-1,arrive    | | ||||||
|  |            | f,h       | ef,gh,gh | depart,roundabout_turn left exit-3,arrive     | | ||||||
|  |            | f,a       | ef,ab,ab | depart,roundabout_turn straight exit-2,arrive | | ||||||
|  |            | f,d       | ef,cd,cd | depart,roundabout_turn right exit-1,arrive    | | ||||||
|  |            | h,a       | gh,ab,ab | depart,roundabout_turn left exit-3,arrive     | | ||||||
|  |            | h,d       | gh,cd,cd | depart,roundabout_turn straight exit-2,arrive | | ||||||
|  |            | h,f       | gh,ef,ef | depart,roundabout_turn right exit-1,arrive    | | ||||||
|  | 
 | ||||||
|  |     Scenario: Only Enter | ||||||
|  |         Given the node map | ||||||
|  |             |   |   | a |   |   | | ||||||
|  |             |   |   | b |   |   | | ||||||
|  |             | d | c |   | g | h | | ||||||
|  |             |   |   | e |   |   | | ||||||
|  |             |   |   | f |   |   | | ||||||
|  | 
 | ||||||
|  |        And the ways | ||||||
|  |             | nodes  | junction   | | ||||||
|  |             | ab     |            | | ||||||
|  |             | cd     |            | | ||||||
|  |             | ef     |            | | ||||||
|  |             | gh     |            | | ||||||
|  |             | bcegb  | roundabout | | ||||||
|  | 
 | ||||||
|  |        When I route I should get | ||||||
|  |            | waypoints | route          | turns                                   | | ||||||
|  |            | a,c       | ab,bcegb,bcegb | depart,roundabout-exit-undefined,arrive | | ||||||
|  |            | a,e       | ab,bcegb,bcegb | depart,roundabout-exit-undefined,arrive | | ||||||
|  |            | a,g       | ab,bcegb,bcegb | depart,roundabout-exit-undefined,arrive | | ||||||
|  |            | d,e       | cd,bcegb,bcegb | depart,roundabout-exit-undefined,arrive | | ||||||
|  |            | d,g       | cd,bcegb,bcegb | depart,roundabout-exit-undefined,arrive | | ||||||
|  |            | d,b       | cd,bcegb,bcegb | depart,roundabout-exit-undefined,arrive | | ||||||
|  |            | f,g       | ef,bcegb,bcegb | depart,roundabout-exit-undefined,arrive | | ||||||
|  |            | f,b       | ef,bcegb,bcegb | depart,roundabout-exit-undefined,arrive | | ||||||
|  |            | f,c       | ef,bcegb,bcegb | depart,roundabout-exit-undefined,arrive | | ||||||
|  |            | h,b       | gh,bcegb,bcegb | depart,roundabout-exit-undefined,arrive | | ||||||
|  |            | h,c       | gh,bcegb,bcegb | depart,roundabout-exit-undefined,arrive | | ||||||
|  |            | h,e       | gh,bcegb,bcegb | depart,roundabout-exit-undefined,arrive | | ||||||
|  | 
 | ||||||
|  |     Scenario: Only Exit | ||||||
|  |         Given the node map | ||||||
|  |             |   |   | a |   |   | | ||||||
|  |             |   |   | b |   |   | | ||||||
|  |             | d | c |   | g | h | | ||||||
|  |             |   |   | e |   |   | | ||||||
|  |             |   |   | f |   |   | | ||||||
|  | 
 | ||||||
|  |        And the ways | ||||||
|  |             | nodes  | junction   | | ||||||
|  |             | ab     |            | | ||||||
|  |             | cd     |            | | ||||||
|  |             | ef     |            | | ||||||
|  |             | gh     |            | | ||||||
|  |             | bcegb  | roundabout | | ||||||
|  | 
 | ||||||
|  |        When I route I should get | ||||||
|  |            | waypoints | route       | turns                           | | ||||||
|  |            | b,d       | bcegb,cd,cd | depart,roundabout-exit-1,arrive | | ||||||
|  |            | b,f       | bcegb,ef,ef | depart,roundabout-exit-2,arrive | | ||||||
|  |            | b,h       | bcegb,gh,gh | depart,roundabout-exit-3,arrive | | ||||||
|  |            | c,f       | bcegb,ef,ef | depart,roundabout-exit-1,arrive | | ||||||
|  |            | c,h       | bcegb,gh,gh | depart,roundabout-exit-2,arrive | | ||||||
|  |            | c,a       | bcegb,ab,ab | depart,roundabout-exit-3,arrive | | ||||||
|  |            | e,h       | bcegb,gh,gh | depart,roundabout-exit-1,arrive | | ||||||
|  |            | e,a       | bcegb,ab,ab | depart,roundabout-exit-2,arrive | | ||||||
|  |            | e,d       | bcegb,cd,cd | depart,roundabout-exit-3,arrive | | ||||||
|  |            | g,a       | bcegb,ab,ab | depart,roundabout-exit-1,arrive | | ||||||
|  |            | g,d       | bcegb,cd,cd | depart,roundabout-exit-2,arrive | | ||||||
|  |            | g,f       | bcegb,ef,ef | depart,roundabout-exit-3,arrive | | ||||||
|  |       #phantom node snapping can result in a full round-trip here, therefore we cannot test b->a and the other direct exits | ||||||
|  | 
 | ||||||
|  |     Scenario: Drive Around | ||||||
|  |         Given the node map | ||||||
|  |             |   |   | a |   |   | | ||||||
|  |             |   |   | b |   |   | | ||||||
|  |             | d | c |   | g | h | | ||||||
|  |             |   |   | e |   |   | | ||||||
|  |             |   |   | f |   |   | | ||||||
|  | 
 | ||||||
|  |        And the ways | ||||||
|  |             | nodes  | junction   | | ||||||
|  |             | ab     |            | | ||||||
|  |             | cd     |            | | ||||||
|  |             | ef     |            | | ||||||
|  |             | gh     |            | | ||||||
|  |             | bcegb  | roundabout | | ||||||
|  | 
 | ||||||
|  |        When I route I should get | ||||||
|  |            | waypoints | route       | turns         | | ||||||
|  |            | b,c       | bcegb,bcegb | depart,arrive | | ||||||
|  |            | b,e       | bcegb,bcegb | depart,arrive | | ||||||
|  |            | b,g       | bcegb,bcegb | depart,arrive | | ||||||
|  |            | c,e       | bcegb,bcegb | depart,arrive | | ||||||
|  |            | c,g       | bcegb,bcegb | depart,arrive | | ||||||
|  |            | c,b       | bcegb,bcegb | depart,arrive | | ||||||
|  |            | e,g       | bcegb,bcegb | depart,arrive | | ||||||
|  |            | e,b       | bcegb,bcegb | depart,arrive | | ||||||
|  |            | e,c       | bcegb,bcegb | depart,arrive | | ||||||
|  |            | g,b       | bcegb,bcegb | depart,arrive | | ||||||
|  |            | g,c       | bcegb,bcegb | depart,arrive | | ||||||
|  |            | g,e       | bcegb,bcegb | depart,arrive | | ||||||
|  | 
 | ||||||
|  |      Scenario: Mixed Entry and Exit - Not an Intersection | ||||||
|  |         Given the node map | ||||||
|  |            |   | c |   | a |   | | ||||||
|  |            | j |   | b |   | f | | ||||||
|  |            |   | k |   | e |   | | ||||||
|  |            | l |   | h |   | d | | ||||||
|  |            |   | g |   | i |   | | ||||||
|  | 
 | ||||||
|  |         And the ways | ||||||
|  |            | nodes | junction   | oneway | | ||||||
|  |            | abc   |            | yes    | | ||||||
|  |            | def   |            | yes    | | ||||||
|  |            | ghi   |            | yes    | | ||||||
|  |            | jkl   |            | yes    | | ||||||
|  |            | bkheb | roundabout | yes    | | ||||||
|  | 
 | ||||||
|  |         When I route I should get | ||||||
|  |            | waypoints | route       | turns                           | | ||||||
|  |            | a,c       | abc,abc,abc | depart,roundabout-exit-1,arrive | | ||||||
|  |            | a,l       | abc,jkl,jkl | depart,roundabout-exit-2,arrive | | ||||||
|  |            | a,i       | abc,ghi,ghi | depart,roundabout-exit-3,arrive | | ||||||
|  |            | a,f       | abc,def,def | depart,roundabout-exit-4,arrive | | ||||||
|  |            | d,f       | def,def,def | depart,roundabout-exit-1,arrive | | ||||||
|  |            | d,c       | def,abc,abc | depart,roundabout-exit-2,arrive | | ||||||
|  |            | d,l       | def,jkl,jkl | depart,roundabout-exit-3,arrive | | ||||||
|  |            | d,i       | def,ghi,ghi | depart,roundabout-exit-4,arrive | | ||||||
|  |            | g,i       | ghi,ghi,ghi | depart,roundabout-exit-1,arrive | | ||||||
|  |            | g,f       | ghi,def,def | depart,roundabout-exit-2,arrive | | ||||||
|  |            | g,c       | ghi,abc,abc | depart,roundabout-exit-3,arrive | | ||||||
|  |            | g,l       | ghi,jkl,jkl | depart,roundabout-exit-4,arrive | | ||||||
|  |            | j,l       | jkl,jkl,jkl | depart,roundabout-exit-1,arrive | | ||||||
|  |            | j,i       | jkl,ghi,ghi | depart,roundabout-exit-2,arrive | | ||||||
|  |            | j,f       | jkl,def,def | depart,roundabout-exit-3,arrive | | ||||||
|  |            | j,c       | jkl,abc,abc | depart,roundabout-exit-4,arrive | | ||||||
|  | 
 | ||||||
|  |     Scenario: Segregated roads - Not an intersection | ||||||
|  |         Given the node map | ||||||
|  |            |   | a |   | c |   | | ||||||
|  |            | l |   | b |   | d | | ||||||
|  |            |   | k |   | e |   | | ||||||
|  |            | j |   | h |   | f | | ||||||
|  |            |   | i |   | g |   | | ||||||
|  | 
 | ||||||
|  |         And the ways | ||||||
|  |            | nodes | junction   | oneway | | ||||||
|  |            | abc   |            | yes    | | ||||||
|  |            | def   |            | yes    | | ||||||
|  |            | ghi   |            | yes    | | ||||||
|  |            | jkl   |            | yes    | | ||||||
|  |            | bkheb | roundabout | yes    | | ||||||
|  | 
 | ||||||
|  |         When I route I should get | ||||||
|  |            | waypoints | route       | turns                           | | ||||||
|  |            | a,c       | abc,abc,abc | depart,roundabout-exit-4,arrive | | ||||||
|  |            | a,l       | abc,jkl,jkl | depart,roundabout-exit-1,arrive | | ||||||
|  |            | a,i       | abc,ghi,ghi | depart,roundabout-exit-2,arrive | | ||||||
|  |            | a,f       | abc,def,def | depart,roundabout-exit-3,arrive | | ||||||
|  |            | d,f       | def,def,def | depart,roundabout-exit-4,arrive | | ||||||
|  |            | d,c       | def,abc,abc | depart,roundabout-exit-1,arrive | | ||||||
|  |            | d,l       | def,jkl,jkl | depart,roundabout-exit-2,arrive | | ||||||
|  |            | d,i       | def,ghi,ghi | depart,roundabout-exit-3,arrive | | ||||||
|  |            | g,i       | ghi,ghi,ghi | depart,roundabout-exit-4,arrive | | ||||||
|  |            | g,f       | ghi,def,def | depart,roundabout-exit-1,arrive | | ||||||
|  |            | g,c       | ghi,abc,abc | depart,roundabout-exit-2,arrive | | ||||||
|  |            | g,l       | ghi,jkl,jkl | depart,roundabout-exit-3,arrive | | ||||||
|  |            | j,l       | jkl,jkl,jkl | depart,roundabout-exit-4,arrive | | ||||||
|  |            | j,i       | jkl,ghi,ghi | depart,roundabout-exit-1,arrive | | ||||||
|  |            | j,f       | jkl,def,def | depart,roundabout-exit-2,arrive | | ||||||
|  |            | j,c       | jkl,abc,abc | depart,roundabout-exit-3,arrive | | ||||||
|  | 
 | ||||||
|  |        Scenario: Collinear in X | ||||||
|  |         Given the node map | ||||||
|  |             | a | b | c | d | f | | ||||||
|  |             |   |   | e |   |   | | ||||||
|  | 
 | ||||||
|  |         And the ways | ||||||
|  |             | nodes | junction   | | ||||||
|  |             | ab    |            | | ||||||
|  |             | bcdb  | roundabout | | ||||||
|  |             | ce    |            | | ||||||
|  |             | df    |            | | ||||||
|  | 
 | ||||||
|  |         When I route I should get | ||||||
|  |             | waypoints | route    | turns                           | | ||||||
|  |             | a,e       | ab,ce,ce | depart,roundabout-exit-1,arrive | | ||||||
|  |             | a,f       | ab,df,df | depart,roundabout-exit-2,arrive | | ||||||
|  | 
 | ||||||
|  |        Scenario: Collinear in X,Y | ||||||
|  |         Given the node map | ||||||
|  |             | a |   |   | | ||||||
|  |             | b |   |   | | ||||||
|  |             | c | d | f | | ||||||
|  |             | e |   |   | | ||||||
|  | 
 | ||||||
|  |         And the ways | ||||||
|  |             | nodes | junction   | | ||||||
|  |             | ab    |            | | ||||||
|  |             | bcdb  | roundabout | | ||||||
|  |             | ce    |            | | ||||||
|  |             | df    |            | | ||||||
|  | 
 | ||||||
|  |         When I route I should get | ||||||
|  |             | waypoints | route    | turns                                         | | ||||||
|  |             | a,e       | ab,ce,ce | depart,roundabout_turn straight exit-1,arrive | | ||||||
|  |             | a,f       | ab,df,df | depart,roundabout_turn left exit-2,arrive     | | ||||||
|  | 
 | ||||||
|  |        Scenario: Collinear in X,Y | ||||||
|  |         Given the node map | ||||||
|  |             | a |   |   | | ||||||
|  |             | d |   |   | | ||||||
|  |             | b | c | f | | ||||||
|  |             | e |   |   | | ||||||
|  | 
 | ||||||
|  |         And the ways | ||||||
|  |             | nodes | junction   | | ||||||
|  |             | ad    |            | | ||||||
|  |             | bcdb  | roundabout | | ||||||
|  |             | be    |            | | ||||||
|  |             | cf    |            | | ||||||
|  | 
 | ||||||
|  |         When I route I should get | ||||||
|  |             | waypoints | route    | turns                                         | | ||||||
|  |             | a,e       | ad,be,be | depart,roundabout_turn straight exit-1,arrive | | ||||||
|  |             | a,f       | ad,cf,cf | depart,roundabout_turn left exit-2,arrive     | | ||||||
|  | 
 | ||||||
|  |        Scenario: Collinear in X,Y | ||||||
|  |         Given the node map | ||||||
|  |             | a |   |   | | ||||||
|  |             | c |   |   | | ||||||
|  |             | d | b | f | | ||||||
|  |             | e |   |   | | ||||||
|  | 
 | ||||||
|  |         And the ways | ||||||
|  |             | nodes | junction   | | ||||||
|  |             | ac    |            | | ||||||
|  |             | bcdb  | roundabout | | ||||||
|  |             | de    |            | | ||||||
|  |             | bf    |            | | ||||||
|  | 
 | ||||||
|  |         When I route I should get | ||||||
|  |             | waypoints | route    | turns                                         | | ||||||
|  |             | a,e       | ac,de,de | depart,roundabout_turn straight exit-1,arrive | | ||||||
|  |             | a,f       | ac,bf,bf | depart,roundabout_turn left exit-2,arrive     | | ||||||
|  | 
 | ||||||
|  |     Scenario: Enter and Exit -- too complex | ||||||
|  |         Given the node map | ||||||
|  |             | j |   | a |   |   | | ||||||
|  |             |   | i | b |   |   | | ||||||
|  |             |   | g |   | c | d | | ||||||
|  |             | h |   | e |   |   | | ||||||
|  |             |   |   | f |   |   | | ||||||
|  | 
 | ||||||
|  |        And the ways | ||||||
|  |             | nodes  | junction   | | ||||||
|  |             | ab     |            | | ||||||
|  |             | ij     |            | | ||||||
|  |             | cd     |            | | ||||||
|  |             | ef     |            | | ||||||
|  |             | gh     |            | | ||||||
|  |             | bigecb | roundabout | | ||||||
|  | 
 | ||||||
|  |        When I route I should get | ||||||
|  |            | waypoints | route    | turns                           | | ||||||
|  |            | a,d       | ab,cd,cd | depart,roundabout-exit-4,arrive | | ||||||
|  |            | a,f       | ab,ef,ef | depart,roundabout-exit-3,arrive | | ||||||
|  |            | a,h       | ab,gh,gh | depart,roundabout-exit-2,arrive | | ||||||
|  |            | d,f       | cd,ef,ef | depart,roundabout-exit-4,arrive | | ||||||
|  |            | d,h       | cd,gh,gh | depart,roundabout-exit-3,arrive | | ||||||
|  |            | d,a       | cd,ab,ab | depart,roundabout-exit-1,arrive | | ||||||
|  |            | f,h       | ef,gh,gh | depart,roundabout-exit-4,arrive | | ||||||
|  |            | f,a       | ef,ab,ab | depart,roundabout-exit-2,arrive | | ||||||
|  |            | f,d       | ef,cd,cd | depart,roundabout-exit-1,arrive | | ||||||
|  |            | h,a       | gh,ab,ab | depart,roundabout-exit-3,arrive | | ||||||
|  |            | h,d       | gh,cd,cd | depart,roundabout-exit-2,arrive | | ||||||
|  |            | h,f       | gh,ef,ef | depart,roundabout-exit-1,arrive | | ||||||
|  | 
 | ||||||
|  |     Scenario: Enter and Exit -- Non-Distinct | ||||||
|  |         Given the node map | ||||||
|  |            |   |   | a |   |   | | ||||||
|  |            |   |   | b |   |   | | ||||||
|  |            |   | g |   | c | d | | ||||||
|  |            |   |   | e |   |   | | ||||||
|  |            | h |   | f |   |   | | ||||||
|  | 
 | ||||||
|  |        And the ways | ||||||
|  |             | nodes | junction   | | ||||||
|  |             | ab    |            | | ||||||
|  |             | cd    |            | | ||||||
|  |             | ef    |            | | ||||||
|  |             | gh    |            | | ||||||
|  |             | bgecb | roundabout | | ||||||
|  | 
 | ||||||
|  |        When I route I should get | ||||||
|  |            | waypoints | route    | turns                           | | ||||||
|  |            | a,d       | ab,cd,cd | depart,roundabout-exit-3,arrive | | ||||||
|  |            | a,f       | ab,ef,ef | depart,roundabout-exit-2,arrive | | ||||||
|  |            | a,h       | ab,gh,gh | depart,roundabout-exit-1,arrive | | ||||||
|  |            | d,f       | cd,ef,ef | depart,roundabout-exit-3,arrive | | ||||||
|  |            | d,h       | cd,gh,gh | depart,roundabout-exit-2,arrive | | ||||||
|  |            | d,a       | cd,ab,ab | depart,roundabout-exit-1,arrive | | ||||||
|  |            | f,h       | ef,gh,gh | depart,roundabout-exit-3,arrive | | ||||||
|  |            | f,a       | ef,ab,ab | depart,roundabout-exit-2,arrive | | ||||||
|  |            | f,d       | ef,cd,cd | depart,roundabout-exit-1,arrive | | ||||||
|  |            | h,a       | gh,ab,ab | depart,roundabout-exit-3,arrive | | ||||||
|  |            | h,d       | gh,cd,cd | depart,roundabout-exit-2,arrive | | ||||||
|  |            | h,f       | gh,ef,ef | depart,roundabout-exit-1,arrive | | ||||||
|  | 
 | ||||||
| @ -149,6 +149,8 @@ module.exports = function () { | |||||||
|                         return v.rotary_name + '-exit-' + v.maneuver.exit; |                         return v.rotary_name + '-exit-' + v.maneuver.exit; | ||||||
|                     else |                     else | ||||||
|                         return 'rotary-exit-' + v.maneuver.exit; |                         return 'rotary-exit-' + v.maneuver.exit; | ||||||
|  |                 case 'roundabout_turn': | ||||||
|  |                     return v.maneuver.type + ' ' + v.maneuver.modifier + ' exit-' + v.maneuver.exit; | ||||||
|                 // FIXME this is a little bit over-simplistic for merge/fork instructions
 |                 // FIXME this is a little bit over-simplistic for merge/fork instructions
 | ||||||
|                 default: |                 default: | ||||||
|                     return v.maneuver.type + ' ' + v.maneuver.modifier; |                     return v.maneuver.type + ' ' + v.maneuver.modifier; | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| #ifndef OSRM_UTIL_GUIDANCE_TOOLKIT_HPP_ | #ifndef OSRM_ENGINE_GUIDANCE_TOOLKIT_HPP_ | ||||||
| #define OSRM_UTIL_GUIDANCE_TOOLKIT_HPP_ | #define OSRM_ENGINE_GUIDANCE_TOOLKIT_HPP_ | ||||||
| 
 | 
 | ||||||
| #include "extractor/guidance/turn_instruction.hpp" | #include "extractor/guidance/turn_instruction.hpp" | ||||||
| #include "util/bearing.hpp" | #include "util/bearing.hpp" | ||||||
| @ -25,9 +25,12 @@ inline bool entersRoundabout(const extractor::guidance::TurnInstruction instruct | |||||||
| { | { | ||||||
|     return (instruction.type == extractor::guidance::TurnType::EnterRoundabout || |     return (instruction.type == extractor::guidance::TurnType::EnterRoundabout || | ||||||
|             instruction.type == extractor::guidance::TurnType::EnterRotary || |             instruction.type == extractor::guidance::TurnType::EnterRotary || | ||||||
|  |             instruction.type == extractor::guidance::TurnType::EnterRoundaboutIntersection || | ||||||
|             instruction.type == extractor::guidance::TurnType::EnterRoundaboutAtExit || |             instruction.type == extractor::guidance::TurnType::EnterRoundaboutAtExit || | ||||||
|             instruction.type == extractor::guidance::TurnType::EnterRotaryAtExit || |             instruction.type == extractor::guidance::TurnType::EnterRotaryAtExit || | ||||||
|  |             instruction.type == extractor::guidance::TurnType::EnterRoundaboutIntersectionAtExit || | ||||||
|             instruction.type == extractor::guidance::TurnType::EnterAndExitRoundabout || |             instruction.type == extractor::guidance::TurnType::EnterAndExitRoundabout || | ||||||
|  |             instruction.type == extractor::guidance::TurnType::EnterAndExitRotary || | ||||||
|             instruction.type == extractor::guidance::TurnType::EnterAndExitRotary); |             instruction.type == extractor::guidance::TurnType::EnterAndExitRotary); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -35,8 +38,10 @@ inline bool leavesRoundabout(const extractor::guidance::TurnInstruction instruct | |||||||
| { | { | ||||||
|     return (instruction.type == extractor::guidance::TurnType::ExitRoundabout || |     return (instruction.type == extractor::guidance::TurnType::ExitRoundabout || | ||||||
|             instruction.type == extractor::guidance::TurnType::ExitRotary || |             instruction.type == extractor::guidance::TurnType::ExitRotary || | ||||||
|  |             instruction.type == extractor::guidance::TurnType::ExitRoundaboutIntersection || | ||||||
|             instruction.type == extractor::guidance::TurnType::EnterAndExitRoundabout || |             instruction.type == extractor::guidance::TurnType::EnterAndExitRoundabout || | ||||||
|             instruction.type == extractor::guidance::TurnType::EnterAndExitRotary); |             instruction.type == extractor::guidance::TurnType::EnterAndExitRotary || | ||||||
|  |             instruction.type == extractor::guidance::TurnType::EnterAndExitRoundaboutIntersection); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| inline bool staysOnRoundabout(const extractor::guidance::TurnInstruction instruction) | inline bool staysOnRoundabout(const extractor::guidance::TurnInstruction instruction) | ||||||
| @ -68,4 +73,4 @@ inline double angularDeviation(const double angle, const double from) | |||||||
| } // namespace engine
 | } // namespace engine
 | ||||||
| } // namespace osrm
 | } // namespace osrm
 | ||||||
| 
 | 
 | ||||||
| #endif /* OSRM_UTIL_GUIDANCE_TOOLKIT_HPP_ */ | #endif /* OSRM_ENGINE_GUIDANCE_TOOLKIT_HPP_ */ | ||||||
|  | |||||||
| @ -22,6 +22,7 @@ const double constexpr FUZZY_ANGLE_DIFFERENCE = 20.; | |||||||
| const double constexpr DISTINCTION_RATIO = 2; | const double constexpr DISTINCTION_RATIO = 2; | ||||||
| const unsigned constexpr INVALID_NAME_ID = 0; | const unsigned constexpr INVALID_NAME_ID = 0; | ||||||
| 
 | 
 | ||||||
|  | const double constexpr MAX_ROUNDABOUT_INTERSECTION_RADIUS =  5; | ||||||
| const double constexpr MAX_ROUNDABOUT_RADIUS = 15; // 30 m diameter as final distinction
 | const double constexpr MAX_ROUNDABOUT_RADIUS = 15; // 30 m diameter as final distinction
 | ||||||
| const double constexpr INCREASES_BY_FOURTY_PERCENT = 1.4; | const double constexpr INCREASES_BY_FOURTY_PERCENT = 1.4; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,14 +1,17 @@ | |||||||
| #ifndef OSRM_EXTRACTOR_GUIDANCE_ROUNDABOUT_HANDLER_HPP_ | #ifndef OSRM_EXTRACTOR_GUIDANCE_ROUNDABOUT_HANDLER_HPP_ | ||||||
| #define OSRM_EXTRACTOR_GUIDANCE_ROUNDABOUT_HANDLER_HPP_ | #define OSRM_EXTRACTOR_GUIDANCE_ROUNDABOUT_HANDLER_HPP_ | ||||||
| 
 | 
 | ||||||
|  | #include "extractor/compressed_edge_container.hpp" | ||||||
| #include "extractor/guidance/intersection.hpp" | #include "extractor/guidance/intersection.hpp" | ||||||
| #include "extractor/guidance/intersection_handler.hpp" | #include "extractor/guidance/intersection_handler.hpp" | ||||||
|  | #include "extractor/guidance/roundabout_type.hpp" | ||||||
| #include "extractor/query_node.hpp" | #include "extractor/query_node.hpp" | ||||||
| 
 | 
 | ||||||
| #include "util/name_table.hpp" | #include "util/name_table.hpp" | ||||||
| #include "util/node_based_graph.hpp" | #include "util/node_based_graph.hpp" | ||||||
| #include "util/typedefs.hpp" | #include "util/typedefs.hpp" | ||||||
| 
 | 
 | ||||||
|  | #include <set> | ||||||
| #include <utility> | #include <utility> | ||||||
| #include <vector> | #include <vector> | ||||||
| 
 | 
 | ||||||
| @ -37,7 +40,8 @@ class RoundaboutHandler : public IntersectionHandler | |||||||
|   public: |   public: | ||||||
|     RoundaboutHandler(const util::NodeBasedDynamicGraph &node_based_graph, |     RoundaboutHandler(const util::NodeBasedDynamicGraph &node_based_graph, | ||||||
|                       const std::vector<QueryNode> &node_info_list, |                       const std::vector<QueryNode> &node_info_list, | ||||||
|                       const util::NameTable &name_table); |                       const util::NameTable &name_table, | ||||||
|  |                       const CompressedEdgeContainer &compressed_edge_container); | ||||||
| 
 | 
 | ||||||
|     ~RoundaboutHandler() override final; |     ~RoundaboutHandler() override final; | ||||||
| 
 | 
 | ||||||
| @ -61,17 +65,21 @@ class RoundaboutHandler : public IntersectionHandler | |||||||
|                                         Intersection &intersection) const; |                                         Intersection &intersection) const; | ||||||
| 
 | 
 | ||||||
|     // decide whether we lookk at a roundabout or a rotary
 |     // decide whether we lookk at a roundabout or a rotary
 | ||||||
|     bool isRotary(const NodeID nid) const; |     RoundaboutType getRoundaboutType(const NodeID nid) const; | ||||||
| 
 | 
 | ||||||
|     // TODO handle bike/walk cases that allow crossing a roundabout!
 |     // TODO handle bike/walk cases that allow crossing a roundabout!
 | ||||||
|     // Processing of roundabouts
 |     // Processing of roundabouts
 | ||||||
|     // Produces instructions to enter/exit a roundabout or to stay on it.
 |     // Produces instructions to enter/exit a roundabout or to stay on it.
 | ||||||
|     // Performs the distinction between roundabout and rotaries.
 |     // Performs the distinction between roundabout and rotaries.
 | ||||||
|     Intersection handleRoundabouts(const bool is_rotary, |     Intersection handleRoundabouts(const RoundaboutType roundabout_type, | ||||||
|                                    const EdgeID via_edge, |                                    const EdgeID via_edge, | ||||||
|                                    const bool on_roundabout, |                                    const bool on_roundabout, | ||||||
|                                    const bool can_exit_roundabout, |                                    const bool can_exit_roundabout, | ||||||
|                                    Intersection intersection) const; |                                    Intersection intersection) const; | ||||||
|  | 
 | ||||||
|  |     bool qualifiesAsRoundaboutIntersection(const std::set<NodeID> &roundabout_nodes) const; | ||||||
|  | 
 | ||||||
|  |     const CompressedEdgeContainer &compressed_edge_container; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } // namespace guidance
 | } // namespace guidance
 | ||||||
|  | |||||||
							
								
								
									
										21
									
								
								include/extractor/guidance/roundabout_type.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								include/extractor/guidance/roundabout_type.hpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | |||||||
|  | #ifndef OSRM_EXTRACTOR_GUIDANCE_ROUNDABOUT_TYPES_HPP_ | ||||||
|  | #define OSRM_EXTRACTOR_GUIDANCE_ROUNDABOUT_TYPES_HPP_ | ||||||
|  | 
 | ||||||
|  | namespace osrm | ||||||
|  | { | ||||||
|  | namespace extractor | ||||||
|  | { | ||||||
|  | namespace guidance | ||||||
|  | { | ||||||
|  | enum class RoundaboutType | ||||||
|  | { | ||||||
|  |     None,                   // not a roundabout
 | ||||||
|  |     Roundabout,             // standard roundabout
 | ||||||
|  |     Rotary,                 // traffic circle (large roundabout) with dedicated name
 | ||||||
|  |     RoundaboutIntersection  // small roundabout with distinct turns, handled as intersection
 | ||||||
|  | }; | ||||||
|  | } /* namespace guidance */ | ||||||
|  | } /* namespace extractor */ | ||||||
|  | } /* namespace osrm */ | ||||||
|  | 
 | ||||||
|  | #endif /* OSRM_EXTRACTOR_GUIDANCE_ROUNDABOUT_TYPES_HPP_ */ | ||||||
| @ -4,6 +4,7 @@ | |||||||
| #include "util/bearing.hpp" | #include "util/bearing.hpp" | ||||||
| #include "util/coordinate.hpp" | #include "util/coordinate.hpp" | ||||||
| #include "util/coordinate_calculation.hpp" | #include "util/coordinate_calculation.hpp" | ||||||
|  | #include "util/guidance/toolkit.hpp" | ||||||
| 
 | 
 | ||||||
| #include "extractor/compressed_edge_container.hpp" | #include "extractor/compressed_edge_container.hpp" | ||||||
| #include "extractor/query_node.hpp" | #include "extractor/query_node.hpp" | ||||||
| @ -26,6 +27,8 @@ namespace extractor | |||||||
| namespace guidance | namespace guidance | ||||||
| { | { | ||||||
| 
 | 
 | ||||||
|  | using util::guidance::angularDeviation; | ||||||
|  | 
 | ||||||
| namespace detail | namespace detail | ||||||
| { | { | ||||||
| const constexpr double DESIRED_SEGMENT_LENGTH = 10.0; | const constexpr double DESIRED_SEGMENT_LENGTH = 10.0; | ||||||
| @ -246,12 +249,6 @@ inline double angleFromDiscreteAngle(const DiscreteAngle angle) | |||||||
|     return static_cast<double>(angle) * detail::discrete_angle_step_size; |     return static_cast<double>(angle) * detail::discrete_angle_step_size; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| inline double angularDeviation(const double angle, const double from) |  | ||||||
| { |  | ||||||
|     const double deviation = std::abs(angle - from); |  | ||||||
|     return std::min(360 - deviation, deviation); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| inline double getAngularPenalty(const double angle, DirectionModifier modifier) | inline double getAngularPenalty(const double angle, DirectionModifier modifier) | ||||||
| { | { | ||||||
|     // these are not aligned with getTurnDirection but represent an ideal center
 |     // these are not aligned with getTurnDirection but represent an ideal center
 | ||||||
| @ -272,30 +269,6 @@ inline double getTurnConfidence(const double angle, TurnInstruction instruction) | |||||||
|     return 1.0 - (difference / max_deviation) * (difference / max_deviation); |     return 1.0 - (difference / max_deviation) * (difference / max_deviation); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Translates between angles and their human-friendly directional representation
 |  | ||||||
| inline DirectionModifier getTurnDirection(const double angle) |  | ||||||
| { |  | ||||||
|     // An angle of zero is a u-turn
 |  | ||||||
|     // 180 goes perfectly straight
 |  | ||||||
|     // 0-180 are right turns
 |  | ||||||
|     // 180-360 are left turns
 |  | ||||||
|     if (angle > 0 && angle < 60) |  | ||||||
|         return DirectionModifier::SharpRight; |  | ||||||
|     if (angle >= 60 && angle < 140) |  | ||||||
|         return DirectionModifier::Right; |  | ||||||
|     if (angle >= 140 && angle < 170) |  | ||||||
|         return DirectionModifier::SlightRight; |  | ||||||
|     if (angle >= 165 && angle <= 195) |  | ||||||
|         return DirectionModifier::Straight; |  | ||||||
|     if (angle > 190 && angle <= 220) |  | ||||||
|         return DirectionModifier::SlightLeft; |  | ||||||
|     if (angle > 220 && angle <= 300) |  | ||||||
|         return DirectionModifier::Left; |  | ||||||
|     if (angle > 300 && angle < 360) |  | ||||||
|         return DirectionModifier::SharpLeft; |  | ||||||
|     return DirectionModifier::UTurn; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // swaps left <-> right modifier types
 | // swaps left <-> right modifier types
 | ||||||
| inline DirectionModifier mirrorDirectionModifier(const DirectionModifier modifier) | inline DirectionModifier mirrorDirectionModifier(const DirectionModifier modifier) | ||||||
| { | { | ||||||
|  | |||||||
| @ -5,6 +5,8 @@ | |||||||
| 
 | 
 | ||||||
| #include <boost/assert.hpp> | #include <boost/assert.hpp> | ||||||
| 
 | 
 | ||||||
|  | #include "extractor/guidance/roundabout_type.hpp" | ||||||
|  | 
 | ||||||
| namespace osrm | namespace osrm | ||||||
| { | { | ||||||
| namespace extractor | namespace extractor | ||||||
| @ -36,26 +38,30 @@ enum DirectionModifier | |||||||
| // enum class TurnType : unsigned char
 | // enum class TurnType : unsigned char
 | ||||||
| enum TurnType // at the moment we can support 32 turn types, without increasing memory consumption
 | enum TurnType // at the moment we can support 32 turn types, without increasing memory consumption
 | ||||||
| { | { | ||||||
|     Invalid,                // no valid turn instruction
 |     Invalid,                            // no valid turn instruction
 | ||||||
|     NoTurn,                 // end of segment without turn/middle of a segment
 |     NewName,                            // no turn, but name changes
 | ||||||
|     Suppressed,             // location that suppresses a turn
 |     Continue,                           // remain on a street
 | ||||||
|     NewName,                // no turn, but name changes
 |     Turn,                               // basic turn
 | ||||||
|     Continue,               // remain on a street
 |     Merge,                              // merge onto a street
 | ||||||
|     Turn,                   // basic turn
 |     Ramp,                               // special turn (highway ramp exits)
 | ||||||
|     Merge,                  // merge onto a street
 |     Fork,                               // fork road splitting up
 | ||||||
|     Ramp,                   // special turn (highway ramp exits)
 |     EndOfRoad,                          // T intersection
 | ||||||
|     Fork,                   // fork road splitting up
 |     Notification,                       // Travel Mode Changes, Restrictions apply...
 | ||||||
|     EndOfRoad,              // T intersection
 |     EnterRoundabout,                    // Entering a small Roundabout
 | ||||||
|     EnterRoundabout,        // Entering a small Roundabout
 |     EnterAndExitRoundabout,             // Touching a roundabout
 | ||||||
|     EnterRoundaboutAtExit,  // Entering a small Roundabout at a countable exit
 |     EnterRotary,                        // Enter a rotary
 | ||||||
|     EnterAndExitRoundabout, // Touching a roundabout
 |     EnterAndExitRotary,                 // Touching a rotary
 | ||||||
|     ExitRoundabout,         // Exiting a small Roundabout
 |     EnterRoundaboutIntersection,        // Entering a small Roundabout
 | ||||||
|     EnterRotary,            // Enter a rotary
 |     EnterAndExitRoundaboutIntersection, // Touching a roundabout
 | ||||||
|     EnterRotaryAtExit,      // Enter A Rotary at a countable exit
 |     NoTurn,                             // end of segment without turn/middle of a segment
 | ||||||
|     EnterAndExitRotary,     // Touching a rotary
 |     Suppressed,                         // location that suppresses a turn
 | ||||||
|     ExitRotary,             // Exit a rotary
 |     EnterRoundaboutAtExit,              // Entering a small Roundabout at a countable exit
 | ||||||
|     StayOnRoundabout,       // Continue on Either a small or a large Roundabout
 |     ExitRoundabout,                     // Exiting a small Roundabout
 | ||||||
|     Notification            // Travel Mode Changes`
 |     EnterRotaryAtExit,                  // Enter A Rotary at a countable exit
 | ||||||
|  |     ExitRotary,                         // Exit a rotary
 | ||||||
|  |     EnterRoundaboutIntersectionAtExit,  // Entering a small Roundabout at a countable exit
 | ||||||
|  |     ExitRoundaboutIntersection,         // Exiting a small Roundabout
 | ||||||
|  |     StayOnRoundabout                    // Continue on Either a small or a large Roundabout
 | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| // turn angle in 1.40625 degree -> 128 == 180 degree
 | // turn angle in 1.40625 degree -> 128 == 180 degree
 | ||||||
| @ -80,27 +86,45 @@ struct TurnInstruction | |||||||
|         return TurnInstruction(TurnType::NoTurn, DirectionModifier::UTurn); |         return TurnInstruction(TurnType::NoTurn, DirectionModifier::UTurn); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     static TurnInstruction REMAIN_ROUNDABOUT(bool is_rotary, const DirectionModifier modifier) |     static TurnInstruction REMAIN_ROUNDABOUT(const RoundaboutType, const DirectionModifier modifier) | ||||||
|     { |     { | ||||||
|         (void)is_rotary; // staying does not require a different instruction at the moment
 |  | ||||||
|         return TurnInstruction(TurnType::StayOnRoundabout, modifier); |         return TurnInstruction(TurnType::StayOnRoundabout, modifier); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     static TurnInstruction ENTER_ROUNDABOUT(bool is_rotary, const DirectionModifier modifier) |     static TurnInstruction ENTER_ROUNDABOUT(const RoundaboutType roundabout_type, | ||||||
|  |                                             const DirectionModifier modifier) | ||||||
|     { |     { | ||||||
|         return {is_rotary ? TurnType::EnterRotary : TurnType::EnterRoundabout, modifier}; |         const constexpr TurnType enter_instruction[] = { | ||||||
|  |             TurnType::Invalid, TurnType::EnterRoundabout, TurnType::EnterRotary, | ||||||
|  |             TurnType::EnterRoundaboutIntersection}; | ||||||
|  |         return {enter_instruction[static_cast<int>(roundabout_type)], modifier}; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     static TurnInstruction EXIT_ROUNDABOUT(bool is_rotary, const DirectionModifier modifier) |     static TurnInstruction EXIT_ROUNDABOUT(const RoundaboutType roundabout_type, | ||||||
|  |                                            const DirectionModifier modifier) | ||||||
|     { |     { | ||||||
|         return {is_rotary ? TurnType::ExitRotary : TurnType::ExitRoundabout, modifier}; |         const constexpr TurnType exit_instruction[] = {TurnType::Invalid, TurnType::ExitRoundabout, | ||||||
|  |                                                        TurnType::ExitRotary, | ||||||
|  |                                                        TurnType::ExitRoundaboutIntersection}; | ||||||
|  |         return {exit_instruction[static_cast<int>(roundabout_type)], modifier}; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     static TurnInstruction ENTER_AND_EXIT_ROUNDABOUT(bool is_rotary, |     static TurnInstruction ENTER_AND_EXIT_ROUNDABOUT(const RoundaboutType roundabout_type, | ||||||
|                                                      const DirectionModifier modifier) |                                                      const DirectionModifier modifier) | ||||||
|     { |     { | ||||||
|         return {is_rotary ? TurnType::EnterAndExitRotary : TurnType::EnterAndExitRoundabout, |         const constexpr TurnType exit_instruction[] = { | ||||||
|                 modifier}; |             TurnType::Invalid, TurnType::EnterAndExitRoundabout, TurnType::EnterAndExitRotary, | ||||||
|  |             TurnType::EnterAndExitRoundaboutIntersection}; | ||||||
|  |         return {exit_instruction[static_cast<int>(roundabout_type)], modifier}; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     static TurnInstruction ENTER_ROUNDABOUT_AT_EXIT(const RoundaboutType roundabout_type, | ||||||
|  |                                                     const DirectionModifier modifier) | ||||||
|  |     { | ||||||
|  |         const constexpr TurnType enter_instruction[] = { | ||||||
|  |             TurnType::Invalid, TurnType::EnterRoundaboutAtExit, TurnType::EnterRotaryAtExit, | ||||||
|  |             TurnType::EnterRoundaboutIntersectionAtExit}; | ||||||
|  |         return {enter_instruction[static_cast<int>(roundabout_type)], modifier}; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     static TurnInstruction SUPPRESSED(const DirectionModifier modifier) |     static TurnInstruction SUPPRESSED(const DirectionModifier modifier) | ||||||
|  | |||||||
							
								
								
									
										48
									
								
								include/util/guidance/toolkit.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								include/util/guidance/toolkit.hpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,48 @@ | |||||||
|  | #ifndef OSRM_UTIL_GUIDANCE_TOOLKIT_HPP_ | ||||||
|  | #define OSRM_UTIL_GUIDANCE_TOOLKIT_HPP_ | ||||||
|  | 
 | ||||||
|  | /* A set of tools required for guidance in both pre and post-processing */ | ||||||
|  | 
 | ||||||
|  | #include "extractor/guidance/turn_instruction.hpp" | ||||||
|  | 
 | ||||||
|  | namespace osrm | ||||||
|  | { | ||||||
|  | namespace util | ||||||
|  | { | ||||||
|  | namespace guidance | ||||||
|  | { | ||||||
|  | 
 | ||||||
|  | inline double angularDeviation(const double angle, const double from) | ||||||
|  | { | ||||||
|  |     const double deviation = std::abs(angle - from); | ||||||
|  |     return std::min(360 - deviation, deviation); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inline extractor::guidance::DirectionModifier getTurnDirection(const double angle) | ||||||
|  | { | ||||||
|  |     // An angle of zero is a u-turn
 | ||||||
|  |     // 180 goes perfectly straight
 | ||||||
|  |     // 0-180 are right turns
 | ||||||
|  |     // 180-360 are left turns
 | ||||||
|  |     if (angle > 0 && angle < 60) | ||||||
|  |         return extractor::guidance::DirectionModifier::SharpRight; | ||||||
|  |     if (angle >= 60 && angle < 140) | ||||||
|  |         return extractor::guidance::DirectionModifier::Right; | ||||||
|  |     if (angle >= 140 && angle < 170) | ||||||
|  |         return extractor::guidance::DirectionModifier::SlightRight; | ||||||
|  |     if (angle >= 165 && angle <= 195) | ||||||
|  |         return extractor::guidance::DirectionModifier::Straight; | ||||||
|  |     if (angle > 190 && angle <= 220) | ||||||
|  |         return extractor::guidance::DirectionModifier::SlightLeft; | ||||||
|  |     if (angle > 220 && angle <= 300) | ||||||
|  |         return extractor::guidance::DirectionModifier::Left; | ||||||
|  |     if (angle > 300 && angle < 360) | ||||||
|  |         return extractor::guidance::DirectionModifier::SharpLeft; | ||||||
|  |     return extractor::guidance::DirectionModifier::UTurn; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } /* namespace guidance */ | ||||||
|  | } /* namespace util */ | ||||||
|  | } /* namespace osrm */ | ||||||
|  | 
 | ||||||
|  | #endif /* OSRM_UTIL_GUIDANCE_TOOLKIT_HPP_ */ | ||||||
| @ -34,9 +34,11 @@ const constexpr char *modifier_names[] = {"uturn",    "sharp right", "right", "s | |||||||
| // translations of TurnTypes. Not all types are exposed to the outside world.
 | // translations of TurnTypes. Not all types are exposed to the outside world.
 | ||||||
| // invalid types should never be returned as part of the API
 | // invalid types should never be returned as part of the API
 | ||||||
| const constexpr char *turn_type_names[] = { | const constexpr char *turn_type_names[] = { | ||||||
|     "invalid", "no turn", "invalid",     "new name",   "continue", "turn",        "merge", |     "invalid", "new name",        "continue",        "turn",       "merge",      "ramp", | ||||||
|     "ramp",    "fork",    "end of road", "roundabout", "invalid",  "roundabout",  "invalid", |     "fork",    "end of road",     "notification",    "roundabout", "roundabout", "rotary", | ||||||
|     "rotary",  "invalid", "rotary",      "invalid",    "invalid",  "notification"}; |     "rotary",  "roundabout_turn", "roundabout_turn", "invalid",    "invalid",    "invalid", | ||||||
|  |     "invalid", "invalid",         "invalid",         "invalid",    "invalid",    "invalid"}; | ||||||
|  | 
 | ||||||
| const constexpr char *waypoint_type_names[] = {"invalid", "arrive", "depart"}; | const constexpr char *waypoint_type_names[] = {"invalid", "arrive", "depart"}; | ||||||
| 
 | 
 | ||||||
| // Check whether to include a modifier in the result of the API
 | // Check whether to include a modifier in the result of the API
 | ||||||
|  | |||||||
| @ -4,6 +4,8 @@ | |||||||
| #include "engine/guidance/assemble_steps.hpp" | #include "engine/guidance/assemble_steps.hpp" | ||||||
| #include "engine/guidance/toolkit.hpp" | #include "engine/guidance/toolkit.hpp" | ||||||
| 
 | 
 | ||||||
|  | #include "util/guidance/toolkit.hpp" | ||||||
|  | 
 | ||||||
| #include <boost/assert.hpp> | #include <boost/assert.hpp> | ||||||
| #include <boost/range/algorithm_ext/erase.hpp> | #include <boost/range/algorithm_ext/erase.hpp> | ||||||
| 
 | 
 | ||||||
| @ -17,6 +19,8 @@ | |||||||
| using TurnInstruction = osrm::extractor::guidance::TurnInstruction; | using TurnInstruction = osrm::extractor::guidance::TurnInstruction; | ||||||
| using TurnType = osrm::extractor::guidance::TurnType; | using TurnType = osrm::extractor::guidance::TurnType; | ||||||
| using DirectionModifier = osrm::extractor::guidance::DirectionModifier; | using DirectionModifier = osrm::extractor::guidance::DirectionModifier; | ||||||
|  | using osrm::util::guidance::angularDeviation; | ||||||
|  | using osrm::util::guidance::getTurnDirection; | ||||||
| 
 | 
 | ||||||
| namespace osrm | namespace osrm | ||||||
| { | { | ||||||
| @ -43,7 +47,9 @@ void print(const std::vector<RouteStep> &steps) | |||||||
|         for (const auto &intersection : step.maneuver.intersections) |         for (const auto &intersection : step.maneuver.intersections) | ||||||
|             std::cout << "(" << intersection.duration << " " << intersection.distance << ")"; |             std::cout << "(" << intersection.duration << " " << intersection.distance << ")"; | ||||||
| 
 | 
 | ||||||
|         std::cout << "] name[" << step.name_id << "]: " << step.name << std::endl; |         std::cout << "] name[" << step.name_id << "]: " << step.name | ||||||
|  |                   << " Bearings: " << step.maneuver.bearing_before << " " | ||||||
|  |                   << step.maneuver.bearing_after << std::endl; | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -79,17 +85,25 @@ void fixFinalRoundabout(std::vector<RouteStep> &steps) | |||||||
|          --propagation_index) |          --propagation_index) | ||||||
|     { |     { | ||||||
|         auto &propagation_step = steps[propagation_index]; |         auto &propagation_step = steps[propagation_index]; | ||||||
|         if (propagation_index == 0 || entersRoundabout(propagation_step.maneuver.instruction)) |         if (entersRoundabout(propagation_step.maneuver.instruction)) | ||||||
|         { |         { | ||||||
|             propagation_step.maneuver.exit = 0; |             propagation_step.maneuver.exit = 0; | ||||||
|             propagation_step.geometry_end = steps.back().geometry_begin; |             propagation_step.geometry_end = steps.back().geometry_begin; | ||||||
| 
 | 
 | ||||||
|  |             // remember the current name as rotary name in tha case we end in a rotary
 | ||||||
|             if (propagation_step.maneuver.instruction.type == TurnType::EnterRotary || |             if (propagation_step.maneuver.instruction.type == TurnType::EnterRotary || | ||||||
|                 propagation_step.maneuver.instruction.type == TurnType::EnterRotaryAtExit) |                 propagation_step.maneuver.instruction.type == TurnType::EnterRotaryAtExit) | ||||||
|                 propagation_step.rotary_name = propagation_step.name; |                 propagation_step.rotary_name = propagation_step.name; | ||||||
| 
 | 
 | ||||||
|             break; |             else if (propagation_step.maneuver.instruction.type == | ||||||
|  |                          TurnType::EnterRoundaboutIntersection || | ||||||
|  |                      propagation_step.maneuver.instruction.type == | ||||||
|  |                          TurnType::EnterRoundaboutIntersectionAtExit) | ||||||
|  |                 propagation_step.maneuver.instruction.type = TurnType::EnterRoundabout; | ||||||
|  | 
 | ||||||
|  |             return; | ||||||
|         } |         } | ||||||
|  |         // accumulate turn data into the enter instructions
 | ||||||
|         else if (propagation_step.maneuver.instruction.type == TurnType::StayOnRoundabout) |         else if (propagation_step.maneuver.instruction.type == TurnType::StayOnRoundabout) | ||||||
|         { |         { | ||||||
|             // TODO this operates on the data that is in the instructions.
 |             // TODO this operates on the data that is in the instructions.
 | ||||||
| @ -109,14 +123,17 @@ bool setUpRoundabout(RouteStep &step) | |||||||
|     // Special case handling, if an entry is directly tied to an exit
 |     // Special case handling, if an entry is directly tied to an exit
 | ||||||
|     const auto instruction = step.maneuver.instruction; |     const auto instruction = step.maneuver.instruction; | ||||||
|     if (instruction.type == TurnType::EnterRotaryAtExit || |     if (instruction.type == TurnType::EnterRotaryAtExit || | ||||||
|         instruction.type == TurnType::EnterRoundaboutAtExit) |         instruction.type == TurnType::EnterRoundaboutAtExit || | ||||||
|  |         instruction.type == TurnType::EnterRoundaboutIntersectionAtExit) | ||||||
|     { |     { | ||||||
|         step.maneuver.exit = 1; |         step.maneuver.exit = 1; | ||||||
|         // prevent futher special case handling of these two.
 |         // prevent futher special case handling of these two.
 | ||||||
|         if (instruction.type == TurnType::EnterRotaryAtExit) |         if (instruction.type == TurnType::EnterRotaryAtExit) | ||||||
|             step.maneuver.instruction.type = TurnType::EnterRotary; |             step.maneuver.instruction.type = TurnType::EnterRotary; | ||||||
|         else |         else if (instruction.type == TurnType::EnterRoundaboutAtExit) | ||||||
|             step.maneuver.instruction.type = TurnType::EnterRoundabout; |             step.maneuver.instruction.type = TurnType::EnterRoundabout; | ||||||
|  |         else | ||||||
|  |             step.maneuver.instruction.type = TurnType::EnterRoundaboutIntersection; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (leavesRoundabout(instruction)) |     if (leavesRoundabout(instruction)) | ||||||
| @ -126,8 +143,10 @@ bool setUpRoundabout(RouteStep &step) | |||||||
|         // prevent futher special case handling of these two.
 |         // prevent futher special case handling of these two.
 | ||||||
|         if (instruction.type == TurnType::EnterAndExitRotary) |         if (instruction.type == TurnType::EnterAndExitRotary) | ||||||
|             step.maneuver.instruction.type = TurnType::EnterRotary; |             step.maneuver.instruction.type = TurnType::EnterRotary; | ||||||
|         else |         else if (instruction.type == TurnType::EnterAndExitRoundabout) | ||||||
|             step.maneuver.instruction.type = TurnType::EnterRoundabout; |             step.maneuver.instruction.type = TurnType::EnterRoundabout; | ||||||
|  |         else | ||||||
|  |             step.maneuver.instruction.type = TurnType::EnterRoundaboutIntersection; | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|     else |     else | ||||||
| @ -145,28 +164,35 @@ void closeOffRoundabout(const bool on_roundabout, | |||||||
|     if (!on_roundabout) |     if (!on_roundabout) | ||||||
|     { |     { | ||||||
| 
 | 
 | ||||||
|         // We reached a special case that requires the addition of a special route step in
 |         // We reached a special case that requires the addition of a special route step in the
 | ||||||
|         // the beginning.
 |         // beginning. We started in a roundabout, so to announce the exit, we move use the exit
 | ||||||
|         // We started in a roundabout, so to announce the exit, we move use the exit
 |         // instruction and move it right to the beginning to make sure to immediately announce the
 | ||||||
|         // instruction and
 |         // exit.
 | ||||||
|         // move it right to the beginning to make sure to immediately announce the exit.
 |  | ||||||
|         BOOST_ASSERT(leavesRoundabout(steps[1].maneuver.instruction) || |         BOOST_ASSERT(leavesRoundabout(steps[1].maneuver.instruction) || | ||||||
|                      steps[1].maneuver.instruction.type == TurnType::StayOnRoundabout); |                      steps[1].maneuver.instruction.type == TurnType::StayOnRoundabout); | ||||||
|         steps[0].geometry_end = 1; |         steps[0].geometry_end = 1; | ||||||
|         steps[1] = detail::forwardInto(steps[1], steps[0]); |         steps[1] = detail::forwardInto(steps[1], steps[0]); | ||||||
|         steps[0].duration = 0; |         steps[0].duration = 0; | ||||||
|         steps[0].distance = 0; |         steps[0].distance = 0; | ||||||
|         steps[1].maneuver.instruction.type = step.maneuver.instruction.type == TurnType::ExitRotary |         const auto exitToEnter = [](const TurnType type) { | ||||||
|                                                  ? TurnType::EnterRotary |             if (TurnType::ExitRotary == type) | ||||||
|                                                  : TurnType::EnterRoundabout; |                 return TurnType::EnterRotary; | ||||||
|  |             // if we do not enter the roundabout Intersection, we cannot treat the full traversal as
 | ||||||
|  |             // a turn. So we switch it up to the roundabout type
 | ||||||
|  |             else if (type == TurnType::ExitRoundaboutIntersection) | ||||||
|  |                 return TurnType::EnterRoundabout; | ||||||
|  |             else | ||||||
|  |                 return TurnType::EnterRoundabout; | ||||||
|  |         }; | ||||||
|  |         steps[1].maneuver.instruction.type = exitToEnter(step.maneuver.instruction.type); | ||||||
|         if (steps[1].maneuver.instruction.type == TurnType::EnterRotary) |         if (steps[1].maneuver.instruction.type == TurnType::EnterRotary) | ||||||
|             steps[1].rotary_name = steps[0].name; |             steps[1].rotary_name = steps[0].name; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Normal exit from the roundabout, or exit from a previously fixed roundabout.
 |     // Normal exit from the roundabout, or exit from a previously fixed roundabout. Propagate the
 | ||||||
|     // Propagate the index back to the entering
 |     // index back to the entering location and prepare the current silent set of instructions for
 | ||||||
|     // location and
 |     // removal.
 | ||||||
|     // prepare the current silent set of instructions for removal.
 |     const auto exit_bearing = steps[step_index].maneuver.bearing_after; | ||||||
|     if (step_index > 1) |     if (step_index > 1) | ||||||
|     { |     { | ||||||
|         // The very first route-step is head, so we cannot iterate past that one
 |         // The very first route-step is head, so we cannot iterate past that one
 | ||||||
| @ -177,15 +203,55 @@ void closeOffRoundabout(const bool on_roundabout, | |||||||
|             propagation_step = detail::forwardInto(propagation_step, steps[propagation_index + 1]); |             propagation_step = detail::forwardInto(propagation_step, steps[propagation_index + 1]); | ||||||
|             if (entersRoundabout(propagation_step.maneuver.instruction)) |             if (entersRoundabout(propagation_step.maneuver.instruction)) | ||||||
|             { |             { | ||||||
|                 // TODO at this point, we can remember the additional name for a rotary
 |  | ||||||
|                 // This requires some initial thought on the data format, though
 |  | ||||||
| 
 |  | ||||||
|                 propagation_step.maneuver.exit = step.maneuver.exit; |                 propagation_step.maneuver.exit = step.maneuver.exit; | ||||||
|                 propagation_step.geometry_end = step.geometry_end; |                 propagation_step.geometry_end = step.geometry_end; | ||||||
|                 // remember rotary name
 |                 // remember rotary name
 | ||||||
|                 if (propagation_step.maneuver.instruction.type == TurnType::EnterRotary || |                 if (propagation_step.maneuver.instruction.type == TurnType::EnterRotary || | ||||||
|                     propagation_step.maneuver.instruction.type == TurnType::EnterRotaryAtExit) |                     propagation_step.maneuver.instruction.type == TurnType::EnterRotaryAtExit) | ||||||
|  |                 { | ||||||
|                     propagation_step.rotary_name = propagation_step.name; |                     propagation_step.rotary_name = propagation_step.name; | ||||||
|  |                 } | ||||||
|  |                 else if (propagation_step.maneuver.instruction.type == | ||||||
|  |                              TurnType::EnterRoundaboutIntersection || | ||||||
|  |                          propagation_step.maneuver.instruction.type == | ||||||
|  |                              TurnType::EnterRoundaboutIntersectionAtExit) | ||||||
|  |                 { | ||||||
|  |                     // Compute the angle between two bearings on a normal turn circle
 | ||||||
|  |                     //
 | ||||||
|  |                     //      Bearings                      Angles
 | ||||||
|  |                     //
 | ||||||
|  |                     //         0                           180
 | ||||||
|  |                     //   315         45               225       135
 | ||||||
|  |                     //
 | ||||||
|  |                     // 270     x       90           270     x      90
 | ||||||
|  |                     //
 | ||||||
|  |                     //   225        135               315        45
 | ||||||
|  |                     //        180                           0
 | ||||||
|  |                     //
 | ||||||
|  |                     // A turn from north to north-east offerst bearing 0 and 45 has to be translated
 | ||||||
|  |                     // into a turn of 135 degrees. The same holdes for 90 - 135 (east to south
 | ||||||
|  |                     // east).
 | ||||||
|  |                     // For north, the transformation works by angle = 540 (360 + 180) - exit_bearing
 | ||||||
|  |                     // % 360;
 | ||||||
|  |                     // All other cases are handled by first rotating both bearings to an
 | ||||||
|  |                     // entry_bearing of 0.
 | ||||||
|  |                     const double angle = [](const double entry_bearing, const double exit_bearing) { | ||||||
|  |                         const double offset = 360 - entry_bearing; | ||||||
|  |                         const double rotated_exit = [](double bearing, const double offset) { | ||||||
|  |                             bearing += offset; | ||||||
|  |                             return bearing > 360 ? bearing - 360 : bearing; | ||||||
|  |                         }(exit_bearing, offset); | ||||||
|  | 
 | ||||||
|  |                         const auto angle = 540 - rotated_exit; | ||||||
|  |                         return angle > 360 ? angle - 360 : angle; | ||||||
|  |                     }(propagation_step.maneuver.bearing_before, exit_bearing); | ||||||
|  | 
 | ||||||
|  |                     std::cout << "Step: " << propagation_step.maneuver.bearing_before << " " | ||||||
|  |                               << exit_bearing << " result: " << angle << std::endl; | ||||||
|  | 
 | ||||||
|  |                     propagation_step.maneuver.instruction.direction_modifier = | ||||||
|  |                         ::osrm::util::guidance::getTurnDirection(angle); | ||||||
|  |                 } | ||||||
| 
 | 
 | ||||||
|                 propagation_step.name = step.name; |                 propagation_step.name = step.name; | ||||||
|                 propagation_step.name_id = step.name_id; |                 propagation_step.name_id = step.name_id; | ||||||
| @ -508,8 +574,8 @@ void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry) | |||||||
| { | { | ||||||
|     // Doing this step in post-processing provides a few challenges we cannot overcome.
 |     // Doing this step in post-processing provides a few challenges we cannot overcome.
 | ||||||
|     // The removal of an initial step imposes some copy overhead in the steps, moving all later
 |     // The removal of an initial step imposes some copy overhead in the steps, moving all later
 | ||||||
|     // steps to the front.
 |     // steps to the front. In addition, we cannot reduce the travel time that is accumulated at a
 | ||||||
|     // In addition, we cannot reduce the travel time that is accumulated at a different location.
 |     // different location.
 | ||||||
|     // As a direct implication, we have to keep the time of the initial/final turns (which adds a
 |     // As a direct implication, we have to keep the time of the initial/final turns (which adds a
 | ||||||
|     // few seconds of inaccuracy at both ends. This is acceptable, however, since the turn should
 |     // few seconds of inaccuracy at both ends. This is acceptable, however, since the turn should
 | ||||||
|     // usually not be as relevant.
 |     // usually not be as relevant.
 | ||||||
| @ -517,14 +583,16 @@ void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry) | |||||||
|     if (steps.size() < 2 || geometry.locations.size() <= 2) |     if (steps.size() < 2 || geometry.locations.size() <= 2) | ||||||
|         return; |         return; | ||||||
| 
 | 
 | ||||||
|     // if phantom node is located at the connection of two segments, either one can be selected as
 |     // if phantom node is located at the connection of two segments, either one can be selected
 | ||||||
|  |     // as
 | ||||||
|     // turn
 |     // turn
 | ||||||
|     //
 |     //
 | ||||||
|     // a --- b
 |     // a --- b
 | ||||||
|     //       |
 |     //       |
 | ||||||
|     //       c
 |     //       c
 | ||||||
|     //
 |     //
 | ||||||
|     // If a route from b to c is requested, both a--b and b--c could be selected as start segment.
 |     // If a route from b to c is requested, both a--b and b--c could be selected as start
 | ||||||
|  |     // segment.
 | ||||||
|     // In case of a--b, we end up with an unwanted turn saying turn-right onto b-c.
 |     // In case of a--b, we end up with an unwanted turn saying turn-right onto b-c.
 | ||||||
|     // These cases start off with an initial segment which is of zero length.
 |     // These cases start off with an initial segment which is of zero length.
 | ||||||
|     // We have to be careful though, since routing that starts in a roundabout has a valid.
 |     // We have to be careful though, since routing that starts in a roundabout has a valid.
 | ||||||
| @ -558,12 +626,12 @@ void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry) | |||||||
|             const auto ¤t_depart = steps.front(); |             const auto ¤t_depart = steps.front(); | ||||||
|             auto &designated_depart = *(steps.begin() + 1); |             auto &designated_depart = *(steps.begin() + 1); | ||||||
| 
 | 
 | ||||||
|             // FIXME this is required to be consistent with the route durations. The initial turn is
 |             // FIXME this is required to be consistent with the route durations. The initial
 | ||||||
|             // not actually part of the route, though
 |             // turn is not actually part of the route, though
 | ||||||
|             designated_depart.duration += current_depart.duration; |             designated_depart.duration += current_depart.duration; | ||||||
| 
 | 
 | ||||||
|             // update initial turn direction/bearings. Due to the duplicated first coordinate, the
 |             // update initial turn direction/bearings. Due to the duplicated first coordinate,
 | ||||||
|             // initial bearing is invalid
 |             // the initial bearing is invalid
 | ||||||
|             designated_depart.maneuver = detail::stepManeuverFromGeometry( |             designated_depart.maneuver = detail::stepManeuverFromGeometry( | ||||||
|                 TurnInstruction::NO_TURN(), WaypointType::Depart, geometry); |                 TurnInstruction::NO_TURN(), WaypointType::Depart, geometry); | ||||||
| 
 | 
 | ||||||
| @ -595,8 +663,8 @@ void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry) | |||||||
| 
 | 
 | ||||||
|     BOOST_ASSERT(geometry.locations.size() >= steps.size()); |     BOOST_ASSERT(geometry.locations.size() >= steps.size()); | ||||||
|     auto &next_to_last_step = *(steps.end() - 2); |     auto &next_to_last_step = *(steps.end() - 2); | ||||||
|     // in the end, the situation with the roundabout cannot occur. As a result, we can remove all
 |     // in the end, the situation with the roundabout cannot occur. As a result, we can remove
 | ||||||
|     // zero-length instructions
 |     // all zero-length instructions
 | ||||||
|     if (next_to_last_step.distance <= 1) |     if (next_to_last_step.distance <= 1) | ||||||
|     { |     { | ||||||
|         geometry.locations.pop_back(); |         geometry.locations.pop_back(); | ||||||
|  | |||||||
| @ -205,7 +205,7 @@ Intersection IntersectionGenerator::mergeSegregatedRoads(Intersection intersecti | |||||||
|             return result; |             return result; | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
|     if (intersection.size() == 1) |     if (intersection.size() <= 1) | ||||||
|         return intersection; |         return intersection; | ||||||
| 
 | 
 | ||||||
|     const bool is_connected_to_roundabout = [this,&intersection]() { |     const bool is_connected_to_roundabout = [this,&intersection]() { | ||||||
| @ -245,7 +245,6 @@ Intersection IntersectionGenerator::mergeSegregatedRoads(Intersection intersecti | |||||||
| 
 | 
 | ||||||
|         intersection.pop_back(); |         intersection.pop_back(); | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     else if (mergable(0, 1)) |     else if (mergable(0, 1)) | ||||||
|     { |     { | ||||||
|         const double correction_factor = (intersection[1].turn.angle) / 2; |         const double correction_factor = (intersection[1].turn.angle) / 2; | ||||||
|  | |||||||
| @ -2,11 +2,13 @@ | |||||||
| #include "extractor/guidance/intersection_handler.hpp" | #include "extractor/guidance/intersection_handler.hpp" | ||||||
| #include "extractor/guidance/toolkit.hpp" | #include "extractor/guidance/toolkit.hpp" | ||||||
| 
 | 
 | ||||||
|  | #include "util/guidance/toolkit.hpp" | ||||||
| #include "util/simple_logger.hpp" | #include "util/simple_logger.hpp" | ||||||
| 
 | 
 | ||||||
| #include <algorithm> | #include <algorithm> | ||||||
| 
 | 
 | ||||||
| using EdgeData = osrm::util::NodeBasedDynamicGraph::EdgeData; | using EdgeData = osrm::util::NodeBasedDynamicGraph::EdgeData; | ||||||
|  | using osrm::util::guidance::getTurnDirection; | ||||||
| 
 | 
 | ||||||
| namespace osrm | namespace osrm | ||||||
| { | { | ||||||
|  | |||||||
| @ -2,6 +2,10 @@ | |||||||
| #include "extractor/guidance/intersection_scenario_three_way.hpp" | #include "extractor/guidance/intersection_scenario_three_way.hpp" | ||||||
| #include "extractor/guidance/toolkit.hpp" | #include "extractor/guidance/toolkit.hpp" | ||||||
| 
 | 
 | ||||||
|  | #include "util/guidance/toolkit.hpp" | ||||||
|  | 
 | ||||||
|  | using osrm::util::guidance::angularDeviation; | ||||||
|  | 
 | ||||||
| namespace osrm | namespace osrm | ||||||
| { | { | ||||||
| namespace extractor | namespace extractor | ||||||
|  | |||||||
| @ -3,12 +3,16 @@ | |||||||
| #include "extractor/guidance/toolkit.hpp" | #include "extractor/guidance/toolkit.hpp" | ||||||
| 
 | 
 | ||||||
| #include "util/simple_logger.hpp" | #include "util/simple_logger.hpp" | ||||||
|  | #include "util/guidance/toolkit.hpp" | ||||||
| 
 | 
 | ||||||
| #include <limits> | #include <limits> | ||||||
| #include <utility> | #include <utility> | ||||||
| 
 | 
 | ||||||
| #include <boost/assert.hpp> | #include <boost/assert.hpp> | ||||||
| 
 | 
 | ||||||
|  | using osrm::util::guidance::angularDeviation; | ||||||
|  | using osrm::util::guidance::getTurnDirection; | ||||||
|  | 
 | ||||||
| namespace osrm | namespace osrm | ||||||
| { | { | ||||||
| namespace extractor | namespace extractor | ||||||
|  | |||||||
| @ -2,14 +2,18 @@ | |||||||
| #include "extractor/guidance/roundabout_handler.hpp" | #include "extractor/guidance/roundabout_handler.hpp" | ||||||
| #include "extractor/guidance/toolkit.hpp" | #include "extractor/guidance/toolkit.hpp" | ||||||
| 
 | 
 | ||||||
|  | #include "util/coordinate_calculation.hpp" | ||||||
|  | #include "util/guidance/toolkit.hpp" | ||||||
| #include "util/simple_logger.hpp" | #include "util/simple_logger.hpp" | ||||||
| 
 | 
 | ||||||
|  | #include <algorithm> | ||||||
| #include <cmath> | #include <cmath> | ||||||
| #include <set> |  | ||||||
| #include <unordered_set> | #include <unordered_set> | ||||||
| 
 | 
 | ||||||
| #include <boost/assert.hpp> | #include <boost/assert.hpp> | ||||||
| 
 | 
 | ||||||
|  | using osrm::util::guidance::getTurnDirection; | ||||||
|  | 
 | ||||||
| namespace osrm | namespace osrm | ||||||
| { | { | ||||||
| namespace extractor | namespace extractor | ||||||
| @ -19,8 +23,10 @@ namespace guidance | |||||||
| 
 | 
 | ||||||
| RoundaboutHandler::RoundaboutHandler(const util::NodeBasedDynamicGraph &node_based_graph, | RoundaboutHandler::RoundaboutHandler(const util::NodeBasedDynamicGraph &node_based_graph, | ||||||
|                                      const std::vector<QueryNode> &node_info_list, |                                      const std::vector<QueryNode> &node_info_list, | ||||||
|                                      const util::NameTable &name_table) |                                      const util::NameTable &name_table, | ||||||
|     : IntersectionHandler(node_based_graph, node_info_list, name_table) |                                      const CompressedEdgeContainer &compressed_edge_container) | ||||||
|  |     : IntersectionHandler(node_based_graph, node_info_list, name_table), | ||||||
|  |       compressed_edge_container(compressed_edge_container) | ||||||
| { | { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -31,7 +37,11 @@ bool RoundaboutHandler::canProcess(const NodeID from_nid, | |||||||
|                                    const Intersection &intersection) const |                                    const Intersection &intersection) const | ||||||
| { | { | ||||||
|     const auto flags = getRoundaboutFlags(from_nid, via_eid, intersection); |     const auto flags = getRoundaboutFlags(from_nid, via_eid, intersection); | ||||||
|     return flags.on_roundabout || flags.can_enter; |     if (!flags.on_roundabout && !flags.can_enter) | ||||||
|  |         return false; | ||||||
|  | 
 | ||||||
|  |     const auto roundabout_type = getRoundaboutType(node_based_graph.GetTarget(via_eid)); | ||||||
|  |     return roundabout_type != RoundaboutType::None; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Intersection RoundaboutHandler:: | Intersection RoundaboutHandler:: | ||||||
| @ -39,10 +49,10 @@ operator()(const NodeID from_nid, const EdgeID via_eid, Intersection intersectio | |||||||
| { | { | ||||||
|     invalidateExitAgainstDirection(from_nid, via_eid, intersection); |     invalidateExitAgainstDirection(from_nid, via_eid, intersection); | ||||||
|     const auto flags = getRoundaboutFlags(from_nid, via_eid, intersection); |     const auto flags = getRoundaboutFlags(from_nid, via_eid, intersection); | ||||||
|     const bool is_rotary = isRotary(node_based_graph.GetTarget(via_eid)); |     const auto roundabout_type = getRoundaboutType(node_based_graph.GetTarget(via_eid)); | ||||||
|     // find the radius of the roundabout
 |     // find the radius of the roundabout
 | ||||||
|     return handleRoundabouts(is_rotary, via_eid, flags.on_roundabout, flags.can_exit_separately, |     return handleRoundabouts(roundabout_type, via_eid, flags.on_roundabout, | ||||||
|                              std::move(intersection)); |                              flags.can_exit_separately, std::move(intersection)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| detail::RoundaboutFlags RoundaboutHandler::getRoundaboutFlags( | detail::RoundaboutFlags RoundaboutHandler::getRoundaboutFlags( | ||||||
| @ -56,7 +66,7 @@ detail::RoundaboutFlags RoundaboutHandler::getRoundaboutFlags( | |||||||
|     { |     { | ||||||
|         const auto &edge_data = node_based_graph.GetEdgeData(road.turn.eid); |         const auto &edge_data = node_based_graph.GetEdgeData(road.turn.eid); | ||||||
|         // only check actual outgoing edges
 |         // only check actual outgoing edges
 | ||||||
|         if (edge_data.reversed || !road.entry_allowed ) |         if (edge_data.reversed || !road.entry_allowed) | ||||||
|             continue; |             continue; | ||||||
| 
 | 
 | ||||||
|         if (edge_data.roundabout) |         if (edge_data.roundabout) | ||||||
| @ -85,7 +95,7 @@ void RoundaboutHandler::invalidateExitAgainstDirection(const NodeID from_nid, | |||||||
|                                                        Intersection &intersection) const |                                                        Intersection &intersection) const | ||||||
| { | { | ||||||
|     const auto &in_edge_data = node_based_graph.GetEdgeData(via_eid); |     const auto &in_edge_data = node_based_graph.GetEdgeData(via_eid); | ||||||
|     if( in_edge_data.roundabout ) |     if (in_edge_data.roundabout) | ||||||
|         return; |         return; | ||||||
| 
 | 
 | ||||||
|     bool past_roundabout_angle = false; |     bool past_roundabout_angle = false; | ||||||
| @ -116,7 +126,74 @@ void RoundaboutHandler::invalidateExitAgainstDirection(const NodeID from_nid, | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool RoundaboutHandler::isRotary(const NodeID nid) const | // If we want to see a roundabout as a turn, the exits have to be distinct enough to be seen a
 | ||||||
|  | // dedicated turns. We are limiting it to four-way intersections with well distinct bearings.
 | ||||||
|  | // All entry/roads and exit roads have to be simple. Not segregated roads.
 | ||||||
|  | // Processing segregated roads would technically require an angle of the turn to be available
 | ||||||
|  | // in postprocessing since we correct the turn-angle in turn-generaion.
 | ||||||
|  | bool RoundaboutHandler::qualifiesAsRoundaboutIntersection( | ||||||
|  |     const std::set<NodeID> &roundabout_nodes) const | ||||||
|  | { | ||||||
|  |     // translate a node ID into its respective coordinate stored in the node_info_list
 | ||||||
|  |     const auto getCoordinate = [this](const NodeID node) { | ||||||
|  |         return util::Coordinate(node_info_list[node].lon, node_info_list[node].lat); | ||||||
|  |     }; | ||||||
|  |     const bool has_limited_size = roundabout_nodes.size() <= 4; | ||||||
|  |     if (!has_limited_size) | ||||||
|  |         return false; | ||||||
|  | 
 | ||||||
|  |     const bool simple_exits = !std::find_if( roundabout_nodes.begin(), roundabout_nodes.end(), [this]( const NodeID node ){ | ||||||
|  |         return (node_based_graph.GetOutDegree(node) > 3); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     if (!simple_exits) | ||||||
|  |         return false; | ||||||
|  | 
 | ||||||
|  |     // Find all exit bearings. Only if they are well distinct (at least 60 degrees between
 | ||||||
|  |     // them), we allow a roundabout turn
 | ||||||
|  | 
 | ||||||
|  |     const auto exit_bearings = [this, &roundabout_nodes, getCoordinate]() { | ||||||
|  |         std::vector<double> result; | ||||||
|  |         for (const auto node : roundabout_nodes) | ||||||
|  |         { | ||||||
|  |             // given the reverse edge and the forward edge on a roundabout, a simple entry/exit
 | ||||||
|  |             // can only contain a single further road
 | ||||||
|  |             for (const auto edge : node_based_graph.GetAdjacentEdgeRange(node)) | ||||||
|  |             { | ||||||
|  |                 const auto edge_data = node_based_graph.GetEdgeData(edge); | ||||||
|  |                 if (edge_data.roundabout) | ||||||
|  |                     continue; | ||||||
|  | 
 | ||||||
|  |                 // there is a single non-roundabout edge
 | ||||||
|  |                 const auto src_coordinate = getCoordinate(node); | ||||||
|  |                 const auto next_coordinate = getRepresentativeCoordinate( | ||||||
|  |                     node, node_based_graph.GetTarget(edge), edge, edge_data.reversed, | ||||||
|  |                     compressed_edge_container, node_info_list); | ||||||
|  |                 result.push_back( | ||||||
|  |                     util::coordinate_calculation::bearing(src_coordinate, next_coordinate)); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         std::sort(result.begin(), result.end()); | ||||||
|  |         return result; | ||||||
|  |     }(); | ||||||
|  | 
 | ||||||
|  |     const bool well_distinct_bearings = [](const std::vector<double> &bearings) { | ||||||
|  |         for (std::size_t bearing_index = 0; bearing_index < bearings.size(); ++bearing_index) | ||||||
|  |         { | ||||||
|  |             const double difference = | ||||||
|  |                 std::abs(bearings[(bearing_index + 1) % bearings.size()] - bearings[bearing_index]); | ||||||
|  |             // we assume non-narrow turns as well distinct
 | ||||||
|  |             if (difference <= NARROW_TURN_ANGLE) | ||||||
|  |                 return false; | ||||||
|  |         } | ||||||
|  |         return true; | ||||||
|  |     }(exit_bearings); | ||||||
|  | 
 | ||||||
|  |     return well_distinct_bearings; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | RoundaboutType RoundaboutHandler::getRoundaboutType(const NodeID nid) const | ||||||
| { | { | ||||||
|     // translate a node ID into its respective coordinate stored in the node_info_list
 |     // translate a node ID into its respective coordinate stored in the node_info_list
 | ||||||
|     const auto getCoordinate = [this](const NodeID node) { |     const auto getCoordinate = [this](const NodeID node) { | ||||||
| @ -168,31 +245,33 @@ bool RoundaboutHandler::isRotary(const NodeID nid) const | |||||||
|     NodeID last_node = nid; |     NodeID last_node = nid; | ||||||
|     while (0 == roundabout_nodes.count(last_node)) |     while (0 == roundabout_nodes.count(last_node)) | ||||||
|     { |     { | ||||||
|         roundabout_nodes.insert(last_node); |         // only count exits/entry locations
 | ||||||
|  |         if (node_based_graph.GetOutDegree(last_node) > 2) | ||||||
|  |             roundabout_nodes.insert(last_node); | ||||||
|  | 
 | ||||||
|         const auto eid = getNextOnRoundabout(last_node); |         const auto eid = getNextOnRoundabout(last_node); | ||||||
| 
 | 
 | ||||||
|         if (eid == SPECIAL_EDGEID) |         if (eid == SPECIAL_EDGEID) | ||||||
|         { |         { | ||||||
|             util::SimpleLogger().Write(logDEBUG) << "Non-Loop Roundabout found."; |             return RoundaboutType::None; | ||||||
|             return false; |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         last_node = node_based_graph.GetTarget(eid); |         last_node = node_based_graph.GetTarget(eid); | ||||||
|  | 
 | ||||||
|  |         if (last_node == nid) | ||||||
|  |             break; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // do we have a dedicated name for the rotary, if not its a roundabout
 |     // a roundabout that cannot be entered or exited should not get here
 | ||||||
|     // This function can theoretically fail if the roundabout name is partly
 |     if (roundabout_nodes.size() == 0) | ||||||
|     // used with a reference and without. This will be fixed automatically
 |         return RoundaboutType::None; | ||||||
|     // when we handle references separately or if the useage is more consistent
 | 
 | ||||||
|     if (roundabout_name_id == 0 || connected_names.count(roundabout_name_id)) |     // More a traffic loop than anything else, currently treated as roundabout turn
 | ||||||
|  |     if (roundabout_nodes.size() == 1) | ||||||
|     { |     { | ||||||
|         return false; |         return RoundaboutType::RoundaboutIntersection; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (roundabout_nodes.size() <= 1) |  | ||||||
|     { |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|     // calculate the radius of the roundabout/rotary. For two coordinates, we assume a minimal
 |     // calculate the radius of the roundabout/rotary. For two coordinates, we assume a minimal
 | ||||||
|     // circle
 |     // circle
 | ||||||
|     // with both vertices right at the other side (so half their distance in meters).
 |     // with both vertices right at the other side (so half their distance in meters).
 | ||||||
| @ -217,12 +296,42 @@ bool RoundaboutHandler::isRotary(const NodeID nid) const | |||||||
|     // The radius computation can result in infinity, if the three coordinates are non-distinct.
 |     // The radius computation can result in infinity, if the three coordinates are non-distinct.
 | ||||||
|     // To stay on the safe side, we say its not a rotary
 |     // To stay on the safe side, we say its not a rotary
 | ||||||
|     if (std::isinf(radius)) |     if (std::isinf(radius)) | ||||||
|         return false; |         return RoundaboutType::Roundabout; | ||||||
| 
 | 
 | ||||||
|     return radius > MAX_ROUNDABOUT_RADIUS; |     // not within the dedicated radii for special roundabouts
 | ||||||
|  |     if (radius > MAX_ROUNDABOUT_INTERSECTION_RADIUS && radius <= MAX_ROUNDABOUT_RADIUS) | ||||||
|  |         return RoundaboutType::Roundabout; | ||||||
|  | 
 | ||||||
|  |     if (radius > MAX_ROUNDABOUT_RADIUS) | ||||||
|  |     { | ||||||
|  |         // do we have a dedicated name for the rotary, if not its a roundabout
 | ||||||
|  |         // This function can theoretically fail if the roundabout name is partly
 | ||||||
|  |         // used with a reference and without. This will be fixed automatically
 | ||||||
|  |         // when we handle references separately or if the useage is more consistent
 | ||||||
|  | 
 | ||||||
|  |         if (0 != roundabout_name_id && 0 == connected_names.count(roundabout_name_id)) | ||||||
|  |             return RoundaboutType::Rotary; | ||||||
|  |         else | ||||||
|  |             return RoundaboutType::Roundabout; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (radius <= MAX_ROUNDABOUT_INTERSECTION_RADIUS) | ||||||
|  |     { | ||||||
|  |         const bool qualifies_as_roundabout_nitersection = | ||||||
|  |             qualifiesAsRoundaboutIntersection(roundabout_nodes); | ||||||
|  |         if (qualifies_as_roundabout_nitersection) | ||||||
|  |         { | ||||||
|  |             return RoundaboutType::RoundaboutIntersection; | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             return RoundaboutType::Roundabout; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return RoundaboutType::Roundabout; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Intersection RoundaboutHandler::handleRoundabouts(const bool is_rotary, | Intersection RoundaboutHandler::handleRoundabouts(const RoundaboutType roundabout_type, | ||||||
|                                                   const EdgeID via_eid, |                                                   const EdgeID via_eid, | ||||||
|                                                   const bool on_roundabout, |                                                   const bool on_roundabout, | ||||||
|                                                   const bool can_exit_roundabout_separately, |                                                   const bool can_exit_roundabout_separately, | ||||||
| @ -248,14 +357,14 @@ Intersection RoundaboutHandler::handleRoundabouts(const bool is_rotary, | |||||||
|                 } |                 } | ||||||
|                 else |                 else | ||||||
|                 { |                 { | ||||||
|                     turn.instruction = |                     turn.instruction = TurnInstruction::REMAIN_ROUNDABOUT( | ||||||
|                         TurnInstruction::REMAIN_ROUNDABOUT(is_rotary, getTurnDirection(turn.angle)); |                         roundabout_type, getTurnDirection(turn.angle)); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             else |             else | ||||||
|             { |             { | ||||||
|                 turn.instruction = |                 turn.instruction = | ||||||
|                     TurnInstruction::EXIT_ROUNDABOUT(is_rotary, getTurnDirection(turn.angle)); |                     TurnInstruction::EXIT_ROUNDABOUT(roundabout_type, getTurnDirection(turn.angle)); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         return intersection; |         return intersection; | ||||||
| @ -269,20 +378,17 @@ Intersection RoundaboutHandler::handleRoundabouts(const bool is_rotary, | |||||||
|             const auto &out_data = node_based_graph.GetEdgeData(turn.eid); |             const auto &out_data = node_based_graph.GetEdgeData(turn.eid); | ||||||
|             if (out_data.roundabout) |             if (out_data.roundabout) | ||||||
|             { |             { | ||||||
|                 turn.instruction = |  | ||||||
|                     TurnInstruction::ENTER_ROUNDABOUT(is_rotary, getTurnDirection(turn.angle)); |  | ||||||
|                 if (can_exit_roundabout_separately) |                 if (can_exit_roundabout_separately) | ||||||
|                 { |                     turn.instruction = TurnInstruction::ENTER_ROUNDABOUT_AT_EXIT( | ||||||
|                     if (turn.instruction.type == TurnType::EnterRotary) |                         roundabout_type, getTurnDirection(turn.angle)); | ||||||
|                         turn.instruction.type = TurnType::EnterRotaryAtExit; |                 else | ||||||
|                     if (turn.instruction.type == TurnType::EnterRoundabout) |                     turn.instruction = TurnInstruction::ENTER_ROUNDABOUT( | ||||||
|                         turn.instruction.type = TurnType::EnterRoundaboutAtExit; |                         roundabout_type, getTurnDirection(turn.angle)); | ||||||
|                 } |  | ||||||
|             } |             } | ||||||
|             else |             else | ||||||
|             { |             { | ||||||
|                 turn.instruction = TurnInstruction::ENTER_AND_EXIT_ROUNDABOUT( |                 turn.instruction = TurnInstruction::ENTER_AND_EXIT_ROUNDABOUT( | ||||||
|                     is_rotary, getTurnDirection(turn.angle)); |                     roundabout_type, getTurnDirection(turn.angle)); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     return intersection; |     return intersection; | ||||||
|  | |||||||
| @ -3,6 +3,7 @@ | |||||||
| 
 | 
 | ||||||
| #include "util/coordinate.hpp" | #include "util/coordinate.hpp" | ||||||
| #include "util/coordinate_calculation.hpp" | #include "util/coordinate_calculation.hpp" | ||||||
|  | #include "util/guidance/toolkit.hpp" | ||||||
| #include "util/simple_logger.hpp" | #include "util/simple_logger.hpp" | ||||||
| 
 | 
 | ||||||
| #include <cstddef> | #include <cstddef> | ||||||
| @ -11,6 +12,8 @@ | |||||||
| #include <set> | #include <set> | ||||||
| #include <unordered_set> | #include <unordered_set> | ||||||
| 
 | 
 | ||||||
|  | using osrm::util::guidance::getTurnDirection; | ||||||
|  | 
 | ||||||
| namespace osrm | namespace osrm | ||||||
| { | { | ||||||
| namespace extractor | namespace extractor | ||||||
| @ -36,7 +39,7 @@ TurnAnalysis::TurnAnalysis(const util::NodeBasedDynamicGraph &node_based_graph, | |||||||
|                                                                  barrier_nodes, |                                                                  barrier_nodes, | ||||||
|                                                                  node_info_list, |                                                                  node_info_list, | ||||||
|                                                                  compressed_edge_container), |                                                                  compressed_edge_container), | ||||||
|       roundabout_handler(node_based_graph, node_info_list, name_table), |       roundabout_handler(node_based_graph, node_info_list, name_table, compressed_edge_container), | ||||||
|       motorway_handler(node_based_graph, node_info_list, name_table), |       motorway_handler(node_based_graph, node_info_list, name_table), | ||||||
|       turn_handler(node_based_graph, node_info_list, name_table) |       turn_handler(node_based_graph, node_info_list, name_table) | ||||||
| { | { | ||||||
|  | |||||||
| @ -4,6 +4,7 @@ | |||||||
| #include "extractor/guidance/turn_handler.hpp" | #include "extractor/guidance/turn_handler.hpp" | ||||||
| 
 | 
 | ||||||
| #include "util/simple_logger.hpp" | #include "util/simple_logger.hpp" | ||||||
|  | #include "util/guidance/toolkit.hpp" | ||||||
| 
 | 
 | ||||||
| #include <limits> | #include <limits> | ||||||
| #include <utility> | #include <utility> | ||||||
| @ -11,6 +12,8 @@ | |||||||
| #include <boost/assert.hpp> | #include <boost/assert.hpp> | ||||||
| 
 | 
 | ||||||
| using EdgeData = osrm::util::NodeBasedDynamicGraph::EdgeData; | using EdgeData = osrm::util::NodeBasedDynamicGraph::EdgeData; | ||||||
|  | using osrm::util::guidance::getTurnDirection; | ||||||
|  | using osrm::util::guidance::angularDeviation; | ||||||
| 
 | 
 | ||||||
| namespace osrm | namespace osrm | ||||||
| { | { | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user