Anticipate Lane Changes
This commit is contained in:
		
							parent
							
								
									efa29edf09
								
							
						
					
					
						commit
						ec0a1a4ab1
					
				
							
								
								
									
										314
									
								
								features/guidance/anticipate-lanes.feature
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										314
									
								
								features/guidance/anticipate-lanes.feature
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,314 @@ | |||||||
|  | @routing @guidance @turn-lanes | ||||||
|  | Feature: Turn Lane Guidance | ||||||
|  | 
 | ||||||
|  |     Background: | ||||||
|  |         Given the profile "car" | ||||||
|  |         Given a grid size of 20 meters | ||||||
|  | 
 | ||||||
|  |     @anticipate | ||||||
|  |     Scenario: Anticipate Lane Change for subsequent multi-lane intersections | ||||||
|  |         Given the node map | ||||||
|  |             | a |   | b |   | x |   |   | | ||||||
|  |             |   |   |   |   |   |   |   | | ||||||
|  |             |   |   | c |   | d |   | z | | ||||||
|  |             |   |   |   |   |   |   |   | | ||||||
|  |             |   |   | y |   | e |   |   | | ||||||
|  | 
 | ||||||
|  |         And the ways | ||||||
|  |             | nodes | turn:lanes:forward         | | ||||||
|  |             | ab    | through\|right&right&right | | ||||||
|  |             | bx    |                            | | ||||||
|  |             | bc    | left\|left&through         | | ||||||
|  |             | cd    | through\|right             | | ||||||
|  |             | cy    |                            | | ||||||
|  |             | dz    |                            | | ||||||
|  |             | de    |                            | | ||||||
|  | 
 | ||||||
|  |        When I route I should get | ||||||
|  |             | waypoints | route          | turns                                         | lanes     | #      | | ||||||
|  |             | a,d       | ab,bc,cd,cd    | depart,turn right,turn left,arrive            | ,1 2,1 2, | 2 hops | | ||||||
|  |             | a,e       | ab,bc,cd,de,de | depart,turn right,turn left,turn right,arrive | ,1,1,0,   | 3 hops | | ||||||
|  | 
 | ||||||
|  |     @anticipate | ||||||
|  |     Scenario: Anticipate Lane Change for quick same direction turns, staying on the same street | ||||||
|  |         Given the node map | ||||||
|  |             | a |   | b | x | | ||||||
|  |             |   |   |   |   | | ||||||
|  |             |   |   | c |   | | ||||||
|  |             |   |   |   |   | | ||||||
|  |             | e |   | d | y | | ||||||
|  | 
 | ||||||
|  |         And the ways | ||||||
|  |             | nodes | turn:lanes:forward   | turn:lanes:backward | name | | ||||||
|  |             | ab    | through\|right&right |                     | MySt | | ||||||
|  |             | bx    |                      |                     | XSt  | | ||||||
|  |             | bc    |                      | left\|right         | MySt | | ||||||
|  |             | cd    | left\|right          | through\|through    | MySt | | ||||||
|  |             | de    |                      | left\|left&through  | MySt | | ||||||
|  |             | dy    |                      |                     | YSt  | | ||||||
|  | 
 | ||||||
|  |        When I route I should get | ||||||
|  |             | waypoints | route               | turns                                          | lanes  | | ||||||
|  |             | a,e       | MySt,MySt,MySt,MySt | depart,continue right,end of road right,arrive | ,0,0,  | | ||||||
|  |             | e,a       | MySt,MySt,MySt,MySt | depart,continue left,end of road left,arrive   | ,2,1,  | | ||||||
|  | 
 | ||||||
|  |     @anticipate | ||||||
|  |     Scenario: Anticipate Lane Change for quick same direction turns, changing between streets | ||||||
|  |         Given the node map | ||||||
|  |             | a |   | b | x | | ||||||
|  |             |   |   |   |   | | ||||||
|  |             |   |   | c |   | | ||||||
|  |             |   |   |   |   | | ||||||
|  |             | e |   | d | y | | ||||||
|  | 
 | ||||||
|  |         And the ways | ||||||
|  |             | nodes | turn:lanes:forward   | turn:lanes:backward | name | | ||||||
|  |             | ab    | through\|right&right |                     | AXSt | | ||||||
|  |             | bx    |                      |                     | AXSt | | ||||||
|  |             | bc    |                      | left\|right         | BDSt | | ||||||
|  |             | cd    | left\|right          | through\|through    | BDSt | | ||||||
|  |             | de    |                      | left\|left&through  | EYSt | | ||||||
|  |             | dy    |                      |                     | EYSt | | ||||||
|  | 
 | ||||||
|  |        When I route I should get | ||||||
|  |             | waypoints | route               | turns                                      | lanes  | | ||||||
|  |             | a,e       | AXSt,BDSt,EYSt,EYSt | depart,turn right,end of road right,arrive | ,0,0,  | | ||||||
|  |             | e,a       | EYSt,BDSt,AXSt,AXSt | depart,turn left,end of road left,arrive   | ,2,1,  | | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     @anticipate | ||||||
|  |     Scenario: Anticipate Lane Change for quick turns during a merge | ||||||
|  |         Given the node map | ||||||
|  |             | a |   |   |   |   | | ||||||
|  |             | x | b |   | c | y | | ||||||
|  |             |   |   |   |   | d | | ||||||
|  | 
 | ||||||
|  |         And the ways | ||||||
|  |             | nodes | turn:lanes:forward       | name | highway       | oneway | | ||||||
|  |             | ab    | slight_left\|slight_left | On   | motorway_link | yes    | | ||||||
|  |             | xb    |                          | Hwy  | motorway      |        | | ||||||
|  |             | bc    | through\|slight_right    | Hwy  | motorway      |        | | ||||||
|  |             | cd    |                          | Off  | motorway_link | yes    | | ||||||
|  |             | cy    |                          | Hwy  | motorway      |        | | ||||||
|  | 
 | ||||||
|  |        When I route I should get | ||||||
|  |             | waypoints | route          | turns                                           | lanes | | ||||||
|  |             | a,d       | On,Hwy,Off,Off | depart,merge slight right,off ramp right,arrive | ,0,0, | | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     @anticipate | ||||||
|  |     Scenario: Schoenefelder Kreuz | ||||||
|  |     # https://www.openstreetmap.org/way/264306388#map=16/52.3202/13.5568 | ||||||
|  |         Given the node map | ||||||
|  |             | a | b | x |   |   | i | | ||||||
|  |             |   |   | c | d |   |   | | ||||||
|  |             |   |   |   |   |   | j | | ||||||
|  | 
 | ||||||
|  |         And the ways | ||||||
|  |             | nodes | turn:lanes:forward                                 | lanes | highway       | oneway | name | | ||||||
|  |             | ab    | none\|none&none&slight_right&slight_right          |   5   | motorway      |        | abx  | | ||||||
|  |             | bx    |                                                    |   3   | motorway      |        | abx  | | ||||||
|  |             | bc    |                                                    |   2   | motorway_link | yes    | bcd  | | ||||||
|  |             | cd    | slight_left\|slight_left;slight_right&slight_right |   3   | motorway_link | yes    | bcd  | | ||||||
|  |             | di    | slight_left\|slight_right                          |   2   | motorway_link | yes    | di   | | ||||||
|  |             | dj    |                                                    |   2   | motorway_link | yes    | dj   | | ||||||
|  | 
 | ||||||
|  |        When I route I should get | ||||||
|  |             | waypoints | route         | turns                                          | lanes     | | ||||||
|  |             | a,i       | abx,bcd,di,di | depart,off ramp right,fork slight left,arrive  | ,0 1,1 2, | | ||||||
|  |             | a,j       | abx,bcd,dj,dj | depart,off ramp right,fork slight right,arrive | ,0 1,0 1, | | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     @anticipate | ||||||
|  |     Scenario: Kreuz Oranienburg | ||||||
|  |     # https://www.openstreetmap.org/way/4484007#map=18/52.70439/13.20269 | ||||||
|  |         Given the node map | ||||||
|  |             | i |   |   |   |   | a | | ||||||
|  |             | j |   | c | b |   | x | | ||||||
|  | 
 | ||||||
|  |         And the ways | ||||||
|  |             | nodes | turn:lanes:forward | lanes | highway       | oneway | name | | ||||||
|  |             | ab    |                    | 1     | motorway_link | yes    | ab   | | ||||||
|  |             | xb    |                    | 1     | motorway_link | yes    | xbcj | | ||||||
|  |             | bc    | none\|slight_right | 2     | motorway_link | yes    | xbcj | | ||||||
|  |             | ci    |                    | 1     | motorway_link | yes    | ci   | | ||||||
|  |             | cj    |                    | 1     | motorway_link | yes    | xbcj | | ||||||
|  | 
 | ||||||
|  |        When I route I should get | ||||||
|  |             | waypoints | route             | turns                                             | lanes | | ||||||
|  |             | a,i       | ab,xbcj,ci,ci     | depart,merge slight left,turn slight right,arrive | ,,0,  | | ||||||
|  |             | a,j       | ab,xbcj,xbcj,xbcj | depart,merge slight left,use lane straight,arrive | ,,1,  | | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     @anticipate | ||||||
|  |     Scenario: Lane anticipation for fan-in | ||||||
|  |         Given the node map | ||||||
|  |             | a |   | b |   | x |   |   | | ||||||
|  |             |   |   |   |   |   |   |   | | ||||||
|  |             |   |   | c |   | d |   | z | | ||||||
|  |             |   |   |   |   |   |   |   | | ||||||
|  |             |   |   | y |   | e |   |   | | ||||||
|  | 
 | ||||||
|  |         And the ways | ||||||
|  |             | nodes | turn:lanes:forward         | name | | ||||||
|  |             | ab    | through\|right&right&right | abx  | | ||||||
|  |             | bx    |                            | abx  | | ||||||
|  |             | bc    | left\|left&through         | bcy  | | ||||||
|  |             | cy    |                            | bcy  | | ||||||
|  |             | cd    | through\|right             | cdz  | | ||||||
|  |             | dz    |                            | cdz  | | ||||||
|  |             | de    |                            | de   | | ||||||
|  | 
 | ||||||
|  |        When I route I should get | ||||||
|  |             | waypoints | route             | turns                                         | lanes   | | ||||||
|  |             | a,e       | abx,bcy,cdz,de,de | depart,turn right,turn left,turn right,arrive | ,1,1,0, | | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     @anticipate | ||||||
|  |     Scenario: Lane anticipation for fan-out | ||||||
|  |         Given the node map | ||||||
|  |             | a |   | b |   | x |   |   | | ||||||
|  |             |   |   |   |   |   |   |   | | ||||||
|  |             |   |   | c |   | d |   | z | | ||||||
|  |             |   |   |   |   |   |   |   | | ||||||
|  |             |   |   | y |   | e |   |   | | ||||||
|  | 
 | ||||||
|  |         And the ways | ||||||
|  |             | nodes | turn:lanes:forward         | name | | ||||||
|  |             | ab    | through\|right             | abx  | | ||||||
|  |             | bx    |                            | abx  | | ||||||
|  |             | bc    | left\|left&through         | bcy  | | ||||||
|  |             | cy    |                            | bcy  | | ||||||
|  |             | cd    | through\|right&right&right | cdz  | | ||||||
|  |             | dz    |                            | cdz  | | ||||||
|  |             | de    |                            | de   | | ||||||
|  | 
 | ||||||
|  |        When I route I should get | ||||||
|  |             | waypoints | route             | turns                                         | lanes         | | ||||||
|  |             | a,e       | abx,bcy,cdz,de,de | depart,turn right,turn left,turn right,arrive | ,0,1 2,0 1 2, | | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     @anticipate | ||||||
|  |     Scenario: Lane anticipation for fan-in followed by fan-out | ||||||
|  |         Given the node map | ||||||
|  |             | a |   | b |   | x |   |   | | ||||||
|  |             |   |   |   |   |   |   |   | | ||||||
|  |             |   |   | c |   | d |   | z | | ||||||
|  |             |   |   |   |   |   |   |   | | ||||||
|  |             |   |   | y |   | e |   |   | | ||||||
|  | 
 | ||||||
|  |         And the ways | ||||||
|  |             | nodes | turn:lanes:forward         | name | | ||||||
|  |             | ab    | through\|right&right&right | abx  | | ||||||
|  |             | bx    |                            | abx  | | ||||||
|  |             | bc    | left\|left&through         | bcy  | | ||||||
|  |             | cy    |                            | bcy  | | ||||||
|  |             | cd    | through\|right&right&right | cdz  | | ||||||
|  |             | dz    |                            | cdz  | | ||||||
|  |             | de    |                            | de   | | ||||||
|  | 
 | ||||||
|  |        When I route I should get | ||||||
|  |             | waypoints | route             | turns                                         | lanes           | | ||||||
|  |             | a,e       | abx,bcy,cdz,de,de | depart,turn right,turn left,turn right,arrive | ,1 2,1 2,0 1 2, | | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     @anticipate | ||||||
|  |     Scenario: Lane anticipation for fan-out followed by fan-in | ||||||
|  |         Given the node map | ||||||
|  |             | a |   | b |   | x |   |   | | ||||||
|  |             |   |   |   |   |   |   |   | | ||||||
|  |             |   |   | c |   | d |   | z | | ||||||
|  |             |   |   |   |   |   |   |   | | ||||||
|  |             |   |   | y |   | e |   |   | | ||||||
|  | 
 | ||||||
|  |         And the ways | ||||||
|  |             | nodes | turn:lanes:forward         | name | | ||||||
|  |             | ab    | through\|right             | abx  | | ||||||
|  |             | bx    |                            | abx  | | ||||||
|  |             | bc    | left\|left&through         | bcy  | | ||||||
|  |             | cy    |                            | bcy  | | ||||||
|  |             | cd    | through\|right             | cdz  | | ||||||
|  |             | dz    |                            | cdz  | | ||||||
|  |             | de    |                            | de   | | ||||||
|  | 
 | ||||||
|  |        When I route I should get | ||||||
|  |             | waypoints | route             | turns                                         | lanes   | | ||||||
|  |             | a,e       | abx,bcy,cdz,de,de | depart,turn right,turn left,turn right,arrive | ,0,1,0, | | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     @anticipate | ||||||
|  |     Scenario: Lane anticipation for multiple hops with same number of lanes | ||||||
|  |         Given the node map | ||||||
|  |             | a |   | b |   | x |   |   | | ||||||
|  |             |   |   |   |   |   |   |   | | ||||||
|  |             |   |   | c |   | d |   | z | | ||||||
|  |             |   |   |   |   |   |   |   | | ||||||
|  |             |   |   | y |   | e |   | f | | ||||||
|  |             |   |   |   |   |   |   |   | | ||||||
|  |             |   |   |   |   | w |   |   | | ||||||
|  | 
 | ||||||
|  |         And the ways | ||||||
|  |             | nodes | turn:lanes:forward         | name | | ||||||
|  |             | ab    | through\|right&right&right | abx  | | ||||||
|  |             | bx    |                            | abx  | | ||||||
|  |             | bc    | left\|left&through         | bcy  | | ||||||
|  |             | cy    |                            | bcy  | | ||||||
|  |             | cd    | through\|right&right       | cdz  | | ||||||
|  |             | dz    |                            | cdz  | | ||||||
|  |             | de    | left\|through              | dew  | | ||||||
|  |             | ew    |                            | dew  | | ||||||
|  |             | ef    |                            | ef   | | ||||||
|  | 
 | ||||||
|  |        When I route I should get | ||||||
|  |             | waypoints | route                 | turns                                                   | lanes     | | ||||||
|  |             | a,f       | abx,bcy,cdz,dew,ef,ef | depart,turn right,turn left,turn right,turn left,arrive | ,1,1,1,1, | | ||||||
|  | 
 | ||||||
|  |     @anticipate | ||||||
|  |     Scenario: Tripple Right keeping Left | ||||||
|  |         Given the node map | ||||||
|  |             | a |   |   |   | b |   | i | | ||||||
|  |             |   |   |   |   |   |   |   | | ||||||
|  |             |   |   |   |   |   |   |   | | ||||||
|  |             | f |   | e |   |   |   | g | | ||||||
|  |             |   |   |   |   |   |   |   | | ||||||
|  |             |   |   |   |   |   |   |   | | ||||||
|  |             |   | j | d |   | c |   |   | | ||||||
|  |             |   |   |   |   | h |   |   | | ||||||
|  | 
 | ||||||
|  |         And the ways | ||||||
|  |             | nodes | turn:lanes:forward | highway   | name   | | ||||||
|  |             | abi   | \|&right&right     | primary   | start  | | ||||||
|  |             | bch   | \|&right&right     | primary   | first  | | ||||||
|  |             | cdj   | \|&right&right     | primary   | second | | ||||||
|  |             | de    | left\|right&right  | secondary | third  | | ||||||
|  |             | feg   |                    | tertiary  | fourth | | ||||||
|  | 
 | ||||||
|  |         When I route I should get | ||||||
|  |             | waypoints | route                                  | turns                                                            | lanes             | | ||||||
|  |             | a,f       | start,first,second,third,fourth,fourth | depart,turn right,turn right,turn right,end of road left,arrive  | ,2,2,2,2,         | | ||||||
|  |             | a,g       | start,first,second,third,fourth,fourth | depart,turn right,turn right,turn right,end of road right,arrive | ,0 1,0 1,0 1,0 1, | | ||||||
|  | 
 | ||||||
|  |     @anticipate | ||||||
|  |     Scenario: Tripple Left keeping Right | ||||||
|  |         Given the node map | ||||||
|  |             | i |   | b |   |   |   | a | | ||||||
|  |             |   |   |   |   |   |   |   | | ||||||
|  |             |   |   |   |   |   |   |   | | ||||||
|  |             | g |   |   |   | e |   | f | | ||||||
|  |             |   |   |   |   |   |   |   | | ||||||
|  |             |   |   |   |   |   |   |   | | ||||||
|  |             |   |   | c |   | d | j |   | | ||||||
|  |             |   |   | h |   |   |   |   | | ||||||
|  | 
 | ||||||
|  |         And the ways | ||||||
|  |             | nodes | turn:lanes:forward | highway   | name   | | ||||||
|  |             | abi   | left\|left&&       | primary   | start  | | ||||||
|  |             | bch   | left\|left&&       | primary   | first  | | ||||||
|  |             | cdj   | left\|left&&       | primary   | second | | ||||||
|  |             | de    | left\|left&right   | secondary | third  | | ||||||
|  |             | feg   |                    | tertiary  | fourth | | ||||||
|  | 
 | ||||||
|  |         When I route I should get | ||||||
|  |             | waypoints | route                                  | turns                                                         | lanes             | | ||||||
|  |             | a,f       | start,first,second,third,fourth,fourth | depart,turn left,turn left,turn left,end of road right,arrive | ,2,2,2,2,         | | ||||||
|  |             | a,g       | start,first,second,third,fourth,fourth | depart,turn left,turn left,turn left,end of road left,arrive  | ,0 1,0 1,0 1,0 1, | | ||||||
| @ -290,26 +290,6 @@ Feature: Turn Lane Guidance | |||||||
|             | a,e       | road,through,through | depart,new name straight,arrive | ,1,   | |             | a,e       | road,through,through | depart,new name straight,arrive | ,1,   | | ||||||
|             | a,f       | road,right,right     | depart,turn right,arrive        | ,0,   | |             | a,f       | road,right,right     | depart,turn right,arrive        | ,0,   | | ||||||
| 
 | 
 | ||||||
|     Scenario: Anticipate Lane Change |  | ||||||
|         Given the node map |  | ||||||
|             | a |   | b |   | x | |  | ||||||
|             |   |   |   |   |   | |  | ||||||
|             |   |   | c |   | d | |  | ||||||
|             |   |   |   |   |   | |  | ||||||
|             |   |   | y |   |   | |  | ||||||
| 
 |  | ||||||
|         And the ways |  | ||||||
|             | nodes | turn:lanes:forward   | turn:lanes:backward | |  | ||||||
|             | ab    | through\|right&right |                     | |  | ||||||
|             | bx    |                      | left\|left&through  | |  | ||||||
|             | bc    | left\|through        | left\|right         | |  | ||||||
|             | cd    |                      | left\|right         | |  | ||||||
|             | cy    |                      |                     | |  | ||||||
| 
 |  | ||||||
|        When I route I should get |  | ||||||
|             | waypoints | route       | turns                                            | lanes | |  | ||||||
|             | d,a       | cd,bc,ab,ab | depart,end of road right,end of road left,arrive | ,0,1, | |  | ||||||
| 
 |  | ||||||
|      Scenario: Turn at a traffic light |      Scenario: Turn at a traffic light | ||||||
|         Given the node map |         Given the node map | ||||||
|             | a | b | c | d | |             | a | b | c | d | | ||||||
|  | |||||||
| @ -149,6 +149,7 @@ class RouteAPI : public BaseAPI | |||||||
|                                                               leg_geometry, |                                                               leg_geometry, | ||||||
|                                                               phantoms.source_phantom, |                                                               phantoms.source_phantom, | ||||||
|                                                               phantoms.target_phantom); |                                                               phantoms.target_phantom); | ||||||
|  |                 leg.steps = guidance::anticipateLaneChange(std::move(leg.steps)); | ||||||
|                 leg_geometry = guidance::resyncGeometry(std::move(leg_geometry), leg.steps); |                 leg_geometry = guidance::resyncGeometry(std::move(leg_geometry), leg.steps); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -43,6 +43,11 @@ std::vector<RouteStep> buildIntersections(std::vector<RouteStep> steps); | |||||||
| // remove steps invalidated by post-processing
 | // remove steps invalidated by post-processing
 | ||||||
| std::vector<RouteStep> removeNoTurnInstructions(std::vector<RouteStep> steps); | std::vector<RouteStep> removeNoTurnInstructions(std::vector<RouteStep> steps); | ||||||
| 
 | 
 | ||||||
|  | // Constrains lanes for multi-hop situations where lane changes depend on earlier ones.
 | ||||||
|  | // Instead of forcing users to change lanes rapidly in a short amount of time,
 | ||||||
|  | // we anticipate lane changes emitting only matching lanes early on.
 | ||||||
|  | std::vector<RouteStep> anticipateLaneChange(std::vector<RouteStep> steps); | ||||||
|  | 
 | ||||||
| // postProcess will break the connection between the leg geometry
 | // postProcess will break the connection between the leg geometry
 | ||||||
| // for which a segment is supposed to represent exactly the coordinates
 | // for which a segment is supposed to represent exactly the coordinates
 | ||||||
| // between routing maneuvers and the route steps itself.
 | // between routing maneuvers and the route steps itself.
 | ||||||
|  | |||||||
							
								
								
									
										40
									
								
								include/util/group_by.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								include/util/group_by.hpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,40 @@ | |||||||
|  | #ifndef OSRM_GROUP_BY | ||||||
|  | #define OSRM_GROUP_BY | ||||||
|  | 
 | ||||||
|  | #include <algorithm> | ||||||
|  | #include <utility> | ||||||
|  | 
 | ||||||
|  | namespace osrm | ||||||
|  | { | ||||||
|  | namespace util | ||||||
|  | { | ||||||
|  | 
 | ||||||
|  | // Runs fn on consecutive items in sub-ranges determined by pred.
 | ||||||
|  | //
 | ||||||
|  | // Example:
 | ||||||
|  | //   vector<int> v{1,2,2,2,3,4,4};
 | ||||||
|  | //   group_by(first, last, even, print);
 | ||||||
|  | //   >>> 2,2,2
 | ||||||
|  | //   >>> 4,4
 | ||||||
|  | //
 | ||||||
|  | // Note: this mimics Python's itertools.groupby
 | ||||||
|  | template <typename Iter, typename Pred, typename Fn> | ||||||
|  | Fn group_by(Iter first, Iter last, Pred pred, Fn fn) | ||||||
|  | { | ||||||
|  |     while (first != last) | ||||||
|  |     { | ||||||
|  |         first = std::find_if(first, last, pred); | ||||||
|  |         auto next = std::find_if_not(first, last, pred); | ||||||
|  | 
 | ||||||
|  |         (void)fn(std::make_pair(first, next)); | ||||||
|  | 
 | ||||||
|  |         first = next; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return fn; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // ns util
 | ||||||
|  | } // ns osrm
 | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
| @ -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/for_each_pair.hpp" | ||||||
|  | #include "util/group_by.hpp" | ||||||
| #include "util/guidance/toolkit.hpp" | #include "util/guidance/toolkit.hpp" | ||||||
| 
 | 
 | ||||||
| #include <boost/assert.hpp> | #include <boost/assert.hpp> | ||||||
| @ -13,6 +15,7 @@ | |||||||
| #include <cmath> | #include <cmath> | ||||||
| #include <cstddef> | #include <cstddef> | ||||||
| #include <iostream> | #include <iostream> | ||||||
|  | #include <iterator> | ||||||
| #include <limits> | #include <limits> | ||||||
| #include <utility> | #include <utility> | ||||||
| 
 | 
 | ||||||
| @ -306,7 +309,6 @@ void closeOffRoundabout(const bool on_roundabout, | |||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 propagation_step.name = destination_name; |                 propagation_step.name = destination_name; | ||||||
|                 ; |  | ||||||
|                 propagation_step.name_id = destinatino_name_id; |                 propagation_step.name_id = destinatino_name_id; | ||||||
|                 invalidateStep(steps[propagation_index + 1]); |                 invalidateStep(steps[propagation_index + 1]); | ||||||
|                 break; |                 break; | ||||||
| @ -1036,6 +1038,94 @@ std::vector<RouteStep> assignRelativeLocations(std::vector<RouteStep> steps, | |||||||
|     return steps; |     return steps; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | std::vector<RouteStep> anticipateLaneChange(std::vector<RouteStep> steps) | ||||||
|  | { | ||||||
|  |     const constexpr auto MIN_DURATION_NEEDED_FOR_LANE_CHANGE = 15.; | ||||||
|  | 
 | ||||||
|  |     // Postprocessing does not strictly guarantee for only turns
 | ||||||
|  |     const auto is_turn = [](const RouteStep &step) { | ||||||
|  |         return step.maneuver.instruction.type != TurnType::NewName && | ||||||
|  |                step.maneuver.instruction.type != TurnType::Notification; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     const auto is_quick = [](const RouteStep &step) { | ||||||
|  |         return step.duration < MIN_DURATION_NEEDED_FOR_LANE_CHANGE; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     const auto is_quick_turn = [&](const RouteStep &step) { | ||||||
|  |         return is_turn(step) && is_quick(step); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     // Determine range of subsequent quick turns, candidates for possible lane anticipation
 | ||||||
|  |     using StepIter = decltype(steps)::iterator; | ||||||
|  |     using StepIterRange = std::pair<StepIter, StepIter>; | ||||||
|  | 
 | ||||||
|  |     std::vector<StepIterRange> subsequent_quick_turns; | ||||||
|  | 
 | ||||||
|  |     const auto keep_turn_range = [&](StepIterRange range) { | ||||||
|  |         if (std::distance(range.first, range.second) > 1) | ||||||
|  |             subsequent_quick_turns.push_back(std::move(range)); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     util::group_by(begin(steps), end(steps), is_quick_turn, keep_turn_range); | ||||||
|  | 
 | ||||||
|  |     // Walk backwards over all turns, constraining possible turn lanes.
 | ||||||
|  |     // Later turn lanes constrain earlier ones: we have to anticipate lane changes.
 | ||||||
|  |     const auto constrain_lanes = [](const StepIterRange &turns) { | ||||||
|  |         const std::reverse_iterator<StepIter> rev_first{turns.second}; | ||||||
|  |         const std::reverse_iterator<StepIter> rev_last{turns.first}; | ||||||
|  | 
 | ||||||
|  |         // We're walking backwards over all adjacent turns:
 | ||||||
|  |         // the current turn lanes constrain the lanes we have to take in the previous turn.
 | ||||||
|  |         util::for_each_pair(rev_first, rev_last, [](RouteStep ¤t, RouteStep &previous) { | ||||||
|  |             const auto current_inst = current.maneuver.instruction; | ||||||
|  |             const auto current_lanes = current_inst.lane_tupel; | ||||||
|  | 
 | ||||||
|  |             // Constrain the previous turn's lanes
 | ||||||
|  |             auto &previous_inst = previous.maneuver.instruction; | ||||||
|  |             auto &previous_lanes = previous_inst.lane_tupel; | ||||||
|  | 
 | ||||||
|  |             // Lane mapping (N:M) from previous lanes (N) to current lanes (M), with:
 | ||||||
|  |             //  N > M, N > 1   fan-in situation, constrain N lanes to min(N,M) shared lanes
 | ||||||
|  |             //  otherwise      nothing to constrain
 | ||||||
|  |             const bool lanes_to_constrain = previous_lanes.lanes_in_turn > 1; | ||||||
|  |             const bool lanes_fan_in = previous_lanes.lanes_in_turn > current_lanes.lanes_in_turn; | ||||||
|  | 
 | ||||||
|  |             if (!lanes_to_constrain || !lanes_fan_in) | ||||||
|  |                 return; | ||||||
|  | 
 | ||||||
|  |             // In case there is no lane information we work with one artificial lane
 | ||||||
|  |             const auto current_adjusted_lanes = std::max(current_lanes.lanes_in_turn, LaneID{1}); | ||||||
|  | 
 | ||||||
|  |             const auto num_shared_lanes = std::min(current_adjusted_lanes, //
 | ||||||
|  |                                                    previous_lanes.lanes_in_turn); | ||||||
|  | 
 | ||||||
|  |             if (isRightTurn(current_inst)) | ||||||
|  |             { | ||||||
|  |                 // Current turn is right turn, already keep right during the previous turn.
 | ||||||
|  |                 // This implies constraining the leftmost lanes in the previous turn step.
 | ||||||
|  |                 previous_lanes = {num_shared_lanes, previous_lanes.first_lane_from_the_right}; | ||||||
|  |             } | ||||||
|  |             else if (isLeftTurn(current_inst)) | ||||||
|  |             { | ||||||
|  |                 // Current turn is left turn, already keep left during previous turn.
 | ||||||
|  |                 // This implies constraining the rightmost lanes in the previous turn step.
 | ||||||
|  |                 const LaneID shared_lane_delta = previous_lanes.lanes_in_turn - num_shared_lanes; | ||||||
|  |                 const LaneID previous_adjusted_lanes = | ||||||
|  |                     std::min(current_adjusted_lanes, shared_lane_delta); | ||||||
|  |                 const LaneID constraint_first_lane_from_the_right = | ||||||
|  |                     previous_lanes.first_lane_from_the_right + previous_adjusted_lanes; | ||||||
|  | 
 | ||||||
|  |                 previous_lanes = {num_shared_lanes, constraint_first_lane_from_the_right}; | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     std::for_each(begin(subsequent_quick_turns), end(subsequent_quick_turns), constrain_lanes); | ||||||
|  | 
 | ||||||
|  |     return steps; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| LegGeometry resyncGeometry(LegGeometry leg_geometry, const std::vector<RouteStep> &steps) | LegGeometry resyncGeometry(LegGeometry leg_geometry, const std::vector<RouteStep> &steps) | ||||||
| { | { | ||||||
|     // The geometry uses an adjacency array-like structure for representation.
 |     // The geometry uses an adjacency array-like structure for representation.
 | ||||||
|  | |||||||
							
								
								
									
										68
									
								
								unit_tests/util/group_by.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								unit_tests/util/group_by.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,68 @@ | |||||||
|  | #include "util/group_by.hpp" | ||||||
|  | 
 | ||||||
|  | #include <boost/test/test_case_template.hpp> | ||||||
|  | #include <boost/test/unit_test.hpp> | ||||||
|  | 
 | ||||||
|  | #include <iterator> | ||||||
|  | #include <vector> | ||||||
|  | 
 | ||||||
|  | BOOST_AUTO_TEST_SUITE(group_by_test) | ||||||
|  | 
 | ||||||
|  | using namespace osrm; | ||||||
|  | using namespace osrm::util; | ||||||
|  | 
 | ||||||
|  | namespace | ||||||
|  | { | ||||||
|  | 
 | ||||||
|  | struct Yes | ||||||
|  | { | ||||||
|  |     template <typename T> bool operator()(T &&) { return true; } | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct No | ||||||
|  | { | ||||||
|  |     template <typename T> bool operator()(T &&) { return false; } | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct Alternating | ||||||
|  | { | ||||||
|  |     template <typename T> bool operator()(T &&) { return state = !state; } | ||||||
|  |     bool state = true; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct SubRangeCounter | ||||||
|  | { | ||||||
|  |     template <typename Range> void operator()(Range &&) { count += 1; } | ||||||
|  |     std::size_t count = 0; | ||||||
|  | }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | BOOST_AUTO_TEST_CASE(grouped_empty_test) | ||||||
|  | { | ||||||
|  |     std::vector<int> v{}; | ||||||
|  |     auto ranges = group_by(begin(v), end(v), Yes{}, SubRangeCounter{}); | ||||||
|  |     BOOST_CHECK_EQUAL(ranges.count, 0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | BOOST_AUTO_TEST_CASE(grouped_all_match_range_test) | ||||||
|  | { | ||||||
|  |     std::vector<int> v{1, 2, 3}; | ||||||
|  |     auto ranges = group_by(begin(v), end(v), Yes{}, SubRangeCounter{}); | ||||||
|  |     BOOST_CHECK_EQUAL(ranges.count, 1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | BOOST_AUTO_TEST_CASE(grouped_no_match_range_test) | ||||||
|  | { | ||||||
|  |     std::vector<int> v{1, 2, 3}; | ||||||
|  |     auto ranges = group_by(begin(v), end(v), No{}, SubRangeCounter{}); | ||||||
|  |     BOOST_CHECK_EQUAL(ranges.count, 1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | BOOST_AUTO_TEST_CASE(grouped_alternating_matches_range_test) | ||||||
|  | { | ||||||
|  |     std::vector<int> v{1, 2, 3}; | ||||||
|  |     auto ranges = group_by(begin(v), end(v), Alternating{}, SubRangeCounter{}); | ||||||
|  |     BOOST_CHECK_EQUAL(ranges.count, v.size()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | BOOST_AUTO_TEST_SUITE_END() | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user