From 5d91b759d12576a0b752dd7f156cc483d75ed2e2 Mon Sep 17 00:00:00 2001 From: Moritz Kobitzsch Date: Wed, 15 Jun 2016 14:38:24 +0200 Subject: [PATCH] Implement Turn Lane Api --- .clang-format | 4 +- .gitignore | 1 - CHANGELOG.md | 2 +- docs/http.md | 20 +- features/guidance/anticipate-lanes.feature | 74 ++-- features/guidance/turn-lanes.feature | 277 ++++++------ features/support/data.js | 4 +- features/support/route.js | 9 +- features/support/shared_steps.js | 5 +- include/engine/api/route_api.hpp | 1 + include/engine/datafacade/datafacade_base.hpp | 4 + .../engine/datafacade/internal_datafacade.hpp | 72 ++++ .../engine/datafacade/shared_datafacade.hpp | 75 ++++ include/engine/guidance/assemble_steps.hpp | 18 +- include/engine/guidance/lane_processing.hpp | 24 ++ include/engine/guidance/post_processing.hpp | 5 - include/engine/guidance/step_maneuver.hpp | 10 +- include/engine/internal_route_result.hpp | 6 +- .../routing_algorithms/routing_base.hpp | 5 + .../extractor/edge_based_graph_factory.hpp | 2 + include/extractor/extraction_way.hpp | 2 +- include/extractor/extractor_config.hpp | 6 +- include/extractor/guidance/debug.hpp | 2 +- include/extractor/guidance/intersection.hpp | 1 + .../guidance/intersection_generator.hpp | 2 +- include/extractor/guidance/toolkit.hpp | 7 + include/extractor/guidance/turn_analysis.hpp | 2 +- .../extractor/guidance/turn_instruction.hpp | 14 +- .../extractor/guidance/turn_lane_handler.hpp | 18 +- .../extractor/guidance/turn_lane_matcher.hpp | 7 +- include/extractor/node_based_edge.hpp | 4 +- include/extractor/original_edge_data.hpp | 9 +- include/storage/shared_datatype.hpp | 48 ++- include/storage/storage_config.hpp | 2 + include/util/guidance/turn_lanes.hpp | 19 +- include/util/node_based_graph.hpp | 3 +- include/util/typedefs.hpp | 4 +- src/engine/api/json_factory.cpp | 33 +- src/engine/guidance/lane_processing.cpp | 111 +++++ src/engine/guidance/post_processing.cpp | 98 +---- src/extractor/edge_based_graph_factory.cpp | 27 +- src/extractor/extraction_containers.cpp | 6 +- src/extractor/extractor.cpp | 5 +- src/extractor/extractor_callbacks.cpp | 14 +- src/extractor/graph_compressor.cpp | 10 +- src/extractor/guidance/intersection.cpp | 9 +- .../guidance/intersection_generator.cpp | 15 +- src/extractor/guidance/roundabout_handler.cpp | 5 +- src/extractor/guidance/turn_discovery.cpp | 2 +- .../guidance/turn_lane_augmentation.cpp | 3 +- src/extractor/guidance/turn_lane_data.cpp | 10 +- src/extractor/guidance/turn_lane_handler.cpp | 53 +-- src/extractor/guidance/turn_lane_matcher.cpp | 32 +- src/storage/storage.cpp | 86 +++- src/storage/storage_config.cpp | 3 +- src/util/guidance/turn_lanes.cpp | 3 +- src/util/name_table.cpp | 8 +- unit_tests/extractor/graph_compressor.cpp | 408 ++++++++++++++++-- unit_tests/mocks/mock_datafacade.hpp | 4 + 59 files changed, 1274 insertions(+), 439 deletions(-) create mode 100644 include/engine/guidance/lane_processing.hpp create mode 100644 src/engine/guidance/lane_processing.cpp diff --git a/.clang-format b/.clang-format index 285ed38ba..009977c96 100644 --- a/.clang-format +++ b/.clang-format @@ -2,7 +2,7 @@ Language: Cpp # BasedOnStyle: LLVM AccessModifierOffset: -2 -AlignAfterOpenBracket: Align +AlignAfterOpenBracket: true AlignConsecutiveAssignments: false AlignConsecutiveDeclarations: false AlignEscapedNewlinesLeft: false @@ -46,7 +46,7 @@ DerivePointerAlignment: false DisableFormat: false ExperimentalAutoDetectBinPacking: false ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] -IncludeCategories: +IncludeCategories: - Regex: '^<' Priority: 3 - Regex: '^"(osrm|util|engine|extract|contract)/' diff --git a/.gitignore b/.gitignore index c72377e48..17e0757e9 100644 --- a/.gitignore +++ b/.gitignore @@ -43,7 +43,6 @@ Thumbs.db /example/build/ /test/data/monaco* /cmake/postinst -.bundle/ # Eclipse related files # ######################### diff --git a/CHANGELOG.md b/CHANGELOG.md index 75b44e295..41811897e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ # 5.3.0 - API - Introduces new `TurnType` in the form of `use lane`. The type indicates that you have to stick to a lane without turning - - Introduces lanes to the route response, indicating which lanes are to be used on a turn + - Introduces lanes to the route response. The lane data contains both the markings at the intersection and a flag indicating their involvement in the turn - Infrastructure - BREAKING: The new turn type changes the turn-type order. This breaks the **data format**. diff --git a/docs/http.md b/docs/http.md index 1b02153e4..0654874b6 100644 --- a/docs/http.md +++ b/docs/http.md @@ -437,12 +437,17 @@ step. | geojson | [GeoJSON `LineString`](http://geojson.org/geojson-spec.html#linestring) or [GeoJSON `Point`](http://geojson.org/geojson-spec.html#point) if it is only one coordinate (not wrapped by a GeoJSON feature)| - `name`: The name of the way along which travel proceeds. +- `lanes`: the available turn lanes at the turn + - `marked`: markings on the road, following the OSM scheme (e.g. left, slight_right, or through) + - `take`: a boolean flag indicating whether the lane is a possible choice in the maneuver - `pronunciation`: The pronunciation hint of the way name. Will be `undefined` if there is no pronunciation hit. - `destinations`: The destinations of the way. Will be `undefined` if there are no destinations. - `mode`: A string signifying the mode of transportation. - `maneuver`: A `StepManeuver` object representing the maneuver. - `intersections`: A list of `Intersections` that are passed along the segment, the very first belonging to the StepManeuver +Currently, the supported lane tags are: `sharp_left, left, slight_left, sharp_right, right, slight_right, through, reverse, none`. + #### Example ``` @@ -450,17 +455,24 @@ step. "distance":152.3, "duration":15.6, "name":"Lortzingstraße", + "lanes":{ + {"marked":"left", + "take":"false"}, + {"marked":"right", + "take":"true"} + }, "maneuver":{ - "type":"depart", - "modifier":"left" + "type":"turn", + "modifier":"right" }, "geometry":"{lu_IypwpAVrAvAdI", "mode":"driving", "intersections":[ {"location":[13.39677,52.54366], + "in":2, "out":1, - "bearings":[66,246], - "entry":["true","true"]}, + "bearings":[10,184,270], + "entry":[false,"true","true"]}, {"location":[13.394718,52.543096], "in":0, "out":2, diff --git a/features/guidance/anticipate-lanes.feature b/features/guidance/anticipate-lanes.feature index 5c80cf635..713be5679 100644 --- a/features/guidance/anticipate-lanes.feature +++ b/features/guidance/anticipate-lanes.feature @@ -25,9 +25,9 @@ Feature: Turn Lane Guidance | 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 | + | waypoints | route | turns | lanes | # | + | a,d | ab,bc,cd,cd | depart,turn right,turn left,arrive | ,through:false right:true right:true right:false,left:true left:true through:false, | 2 hops | + | a,e | ab,bc,cd,de,de | depart,turn right,turn left,turn right,arrive | ,through:false right:false right:true right:false,left:false left:true through:false,through:false right:true, | 3 hops | @anticipate Scenario: Anticipate Lane Change for quick same direction turns, staying on the same street @@ -48,9 +48,9 @@ Feature: Turn Lane Guidance | 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, | + | waypoints | route | turns | lanes | + | a,e | MySt,MySt,MySt,MySt | depart,continue right,end of road right,arrive | ,through:false right:false right:true,left:false right:true, | + | e,a | MySt,MySt,MySt,MySt | depart,continue left,end of road left,arrive | ,left:true left:false through:false,left:true right:false, | @anticipate Scenario: Anticipate Lane Change for quick same direction turns, changing between streets @@ -71,9 +71,9 @@ Feature: Turn Lane Guidance | 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, | + | waypoints | route | turns | lanes | + | a,e | AXSt,BDSt,EYSt,EYSt | depart,turn right,end of road right,arrive | ,through:false right:false right:true,left:false right:true, | + | e,a | EYSt,BDSt,AXSt,AXSt | depart,turn left,end of road left,arrive | ,left:true left:false through:false,left:true right:false, | @anticipate @@ -92,8 +92,8 @@ Feature: Turn Lane Guidance | 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, | + | waypoints | route | turns | lanes | + | a,d | On,Hwy,Off,Off | depart,merge slight right,off ramp right,arrive | ,slight_left:false slight_left:true,through:false slight_right:true, | @anticipate @@ -114,9 +114,9 @@ Feature: Turn Lane Guidance | 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, | + | waypoints | route | turns | lanes | + | a,i | abx,bcd,di,di | depart,off ramp right,fork slight left,arrive | ,none:false none:false none:false slight_right:true slight_right:true,slight_left:true slight_left;slight_right:true slight_right:false, | + | a,j | abx,bcd,dj,dj | depart,off ramp right,fork slight right,arrive | ,none:false none:false none:false slight_right:true slight_right:true,slight_left:false slight_left;slight_right:true slight_right:true, | @anticipate @@ -135,9 +135,9 @@ Feature: Turn Lane Guidance | 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, | + | waypoints | route | turns | lanes | + | a,i | ab,xbcj,ci,ci | depart,merge slight left,turn slight right,arrive | ,,none:false slight_right:true, | + | a,j | ab,xbcj,xbcj,xbcj | depart,merge slight left,use lane straight,arrive | ,,none:true slight_right:false, | @anticipate @@ -160,9 +160,8 @@ Feature: Turn Lane Guidance | 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, | - + | waypoints | route | turns | lanes | + | a,e | abx,bcy,cdz,de,de | depart,turn right,turn left,turn right,arrive | ,through:false right:false right:true right:false,left:false left:true through:false,through:false right:true, | @anticipate Scenario: Lane anticipation for fan-out @@ -184,9 +183,8 @@ Feature: Turn Lane Guidance | 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, | - + | waypoints | route | turns | lanes | + | a,e | abx,bcy,cdz,de,de | depart,turn right,turn left,turn right,arrive | ,through:false right:true,left:true left:true through:false,through:false right:true right:true right:true, | @anticipate Scenario: Lane anticipation for fan-in followed by fan-out @@ -208,9 +206,8 @@ Feature: Turn Lane Guidance | 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, | - + | waypoints | route | turns | lanes | + | a,e | abx,bcy,cdz,de,de | depart,turn right,turn left,turn right,arrive | ,through:false right:true right:true right:false,left:true left:true through:false,through:false right:true right:true right:true, | @anticipate Scenario: Lane anticipation for fan-out followed by fan-in @@ -232,9 +229,8 @@ Feature: Turn Lane Guidance | 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, | - + | waypoints | route | turns | lanes | + | a,e | abx,bcy,cdz,de,de | depart,turn right,turn left,turn right,arrive | ,through:false right:true,left:false left:true through:false,through:false right:true, | @anticipate Scenario: Lane anticipation for multiple hops with same number of lanes @@ -260,10 +256,10 @@ Feature: Turn Lane Guidance | 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, | + | waypoints | route | turns | lanes | + | a,f | abx,bcy,cdz,dew,ef,ef | depart,turn right,turn left,turn right,turn left,arrive | ,through:false right:false right:true right:false,left:false left:true through:false,through:false right:true right:false,left:true through:false, | - @anticipate + @anticipate @bug @todo Scenario: Tripple Right keeping Left Given the node map | a | | | | b | | i | @@ -284,11 +280,11 @@ Feature: Turn Lane Guidance | 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, | + | waypoints | route | turns | lanes | + | a,f | start,first,second,third,fourth,fourth | depart,turn right,turn right,turn right,end of road left,arrive | ,none:false none:true right:false right:false,none:false none:true right:false right:false,none:false none:true right:false right:false,left:true right:false right:false, | + | a,g | start,first,second,third,fourth,fourth | depart,turn right,turn right,turn right,end of road right,arrive | ,none:false none:false right:true right:true,none:false none:false right:true right:true,none:false none:false right:true right:true,left:false right:true right:true, | - @anticipate + @anticipate @bug @todo Scenario: Tripple Left keeping Right Given the node map | i | | b | | | | a | @@ -309,6 +305,6 @@ Feature: Turn Lane Guidance | 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, | + | waypoints | route | turns | lanes | + | a,f | start,first,second,third,fourth,fourth | depart,turn left,turn left,turn left,end of road right,arrive | ,left:false left:false none:true none:false,left:false left:false none:true none:false,left:false left:false none:true none:false,left:false left:false right:true, | + | a,g | start,first,second,third,fourth,fourth | depart,turn left,turn left,turn left,end of road left,arrive | ,left:true left:true none:false none:false,left:true left:true none:false none:false,left:true left:true none:false none:false,left:true left:true right:false, | diff --git a/features/guidance/turn-lanes.feature b/features/guidance/turn-lanes.feature index 3e5b69823..4d244c839 100644 --- a/features/guidance/turn-lanes.feature +++ b/features/guidance/turn-lanes.feature @@ -20,11 +20,11 @@ Feature: Turn Lane Guidance | bd | | | left\|right | right | When I route I should get - | waypoints | route | turns | lanes | - | a,c | in,straight,straight | depart,new name straight,arrive | ,1, | - | a,d | in,right,right | depart,turn right,arrive | ,0, | - | c,a | straight,in,in | depart,new name straight,arrive | ,0 1 2, | - | c,d | straight,right,right | depart,turn left,arrive | ,3, | + | waypoints | route | turns | lanes | + | a,c | in,straight,straight | depart,new name straight,arrive | ,through:true right:false, | + | a,d | in,right,right | depart,turn right,arrive | ,through:false right:true, | + | c,a | straight,in,in | depart,new name straight,arrive | ,left:false through:true none:true none:true, | + | c,d | straight,right,right | depart,turn left,arrive | ,left:true through:false none:false none:false, | Scenario: Basic Turn Lane 4-Way Turn Given the node map @@ -40,13 +40,13 @@ Feature: Turn Lane Guidance | be | | | | left | When I route I should get - | waypoints | route | turns | lanes | - | a,c | in,straight,straight | depart,new name straight,arrive | ,1, | - | a,d | in,right,right | depart,turn right,arrive | ,0, | - | a,e | in,left,left | depart,turn left,arrive | ,1, | - | d,a | right,in,in | depart,turn left,arrive | ,1, | - | d,e | right,left,left | depart,new name straight,arrive | ,0, | - | d,c | right,straight,straight | depart,turn right,arrive | ,0, | + | waypoints | route | turns | lanes | + | a,c | in,straight,straight | depart,new name straight,arrive | ,none:true right:false, | + | a,d | in,right,right | depart,turn right,arrive | ,none:false right:true, | + | a,e | in,left,left | depart,turn left,arrive | ,none:true right:false, | + | d,a | right,in,in | depart,turn left,arrive | ,left:true none:false, | + | d,e | right,left,left | depart,new name straight,arrive | ,left:false none:true, | + | d,c | right,straight,straight | depart,turn right,arrive | ,left:false none:true, | Scenario: Basic Turn Lane 4-Way Turn using none Given the node map @@ -62,10 +62,10 @@ Feature: Turn Lane Guidance | be | | | | left | When I route I should get - | waypoints | route | turns | lanes | - | a,c | in,straight,straight | depart,new name straight,arrive | ,1, | - | a,d | in,right,right | depart,turn right,arrive | ,0, | - | a,e | in,left,left | depart,turn left,arrive | ,1, | + | waypoints | route | turns | lanes | + | a,c | in,straight,straight | depart,new name straight,arrive | ,none:true right:false, | + | a,d | in,right,right | depart,turn right,arrive | ,none:false right:true, | + | a,e | in,left,left | depart,turn left,arrive | ,none:true right:false, | Scenario: Basic Turn Lane 4-Way With U-Turn Lane Given the node map @@ -81,11 +81,11 @@ Feature: Turn Lane Guidance | be | | | left | When I route I should get - | from | to | bearings | route | turns | lanes | - | a | c | 180,180 180,180 | in,straight,straight | depart,new name straight,arrive | ,0, | - | a | d | 180,180 180,180 | in,right,right | depart,turn right,arrive | ,0, | - | a | e | 180,180 180,180 | in,left,left | depart,turn left,arrive | ,1, | - | 1 | a | 90,2 270,2 | in,in,in | depart,turn uturn,arrive | ,1, | + | from | to | bearings | route | turns | lanes | + | a | c | 180,180 180,180 | in,straight,straight | depart,new name straight,arrive | ,reverse;left:false through;right:true, | + | a | d | 180,180 180,180 | in,right,right | depart,turn right,arrive | ,reverse;left:false through;right:true, | + | a | e | 180,180 180,180 | in,left,left | depart,turn left,arrive | ,reverse;left:true through;right:false, | + | 1 | a | 90,2 270,2 | in,in,in | depart,turn uturn,arrive | ,reverse;left:true through;right:false, | #this next test requires decision on how to announce lanes for going straight if there is no turn @@ -103,12 +103,12 @@ Feature: Turn Lane Guidance | bd | turn | | | When I route I should get - | waypoints | route | turns | lanes | - | a,d | road,turn,turn | depart,turn right,arrive | ,0, | - | a,c | road,road,road | depart,use lane straight,arrive | ,1, | + | waypoints | route | turns | lanes | + | a,d | road,turn,turn | depart,turn right,arrive | ,through:false right:true, | + | a,c | road,road,road | depart,use lane straight,arrive | ,through:true right:false, | #turn lanes are often drawn at the incoming road, even though the actual turn requires crossing the intersection first - @TODO @WORKAROUND-FIXME + @todo @WORKAROUND-FIXME @bug Scenario: Turn Lanes at Segregated Road Given the node map | | | i | l | | | @@ -134,23 +134,57 @@ Feature: Turn Lane Guidance | fl | cross | | yes | When I route I should get - | waypoints | route | turns | lanes | # | - | a,j | road,cross,cross | depart,turn right,arrive | ,0, | | - | a,d | road,road,road | depart,use lane straight,arrive | ,1, | #post-processing reduction | - | a,l | road,cross,cross | depart,turn left,arrive | ,2, | | - | a,h | road,road,road | depart,continue uturn,arrive | ,2, | | - | k,d | cross,road,road | depart,turn right,arrive | ,0, | | - | k,l | cross,cross,cross | depart,use lane straight,arrive | ,0, | | - | k,h | cross,road,road | depart,turn left,arrive | ,1, | | - | k,j | cross,cross,cross | depart,continue uturn,arrive | ,1, | | - | e,l | road,cross,cross | depart,turn right,arrive | ,0, | | - | e,h | road,road | depart,arrive | , | | - | e,j | road,cross,cross | depart,turn left,arrive | ,2, | | - | e,d | road,road,road | depart,continue uturn,arrive | ,2, | | - | i,h | cross,road,road | depart,turn right,arrive | ,, | | - | i,j | cross,cross,cross | depart,use lane straight,arrive | ,0, | | - | i,d | cross,road,road | depart,turn left,arrive | ,1, | | - | i,l | cross,cross,cross | depart,continue uturn,arrive | ,1, | | + | waypoints | route | turns | lanes | + | a,j | road,cross,cross | depart,turn right,arrive | ,left:false through:false right:true | + | a,d | road,road,road | depart,use lane straight,arrive | ,left:false through:true right:false, | + | a,l | road,cross,cross | depart,turn left,arrive | ,left:true through:false right:false, | + | a,h | road,road,road | depart,continue uturn,arrive | ,left:true through:false right:false, | + | k,d | cross,road,road | depart,turn right,arrive | ,left:false through;right:true, | + | k,l | cross,cross,cross | depart,use lane straight,arrive | ,left:false through;right:true, | + | k,h | cross,road,road | depart,turn left,arrive | ,left:true through;right:false, | + | k,j | cross,cross,cross | depart,continue uturn,arrive | ,left:true through;right:false, | + | e,l | road,cross,cross | depart,turn right,arrive | ,none:false through:false through;right:true, | + | e,h | road,road | depart,arrive | ,none:false through:true through;right:true | + | e,j | road,cross,cross | depart,turn left,arrive | ,none:true through:false through;right:false, | + | e,d | road,road,road | depart,continue uturn,arrive | ,none:true through:false through;right:false, | + | i,h | cross,road,road | depart,turn right,arrive | ,, | + | i,j | cross,cross,cross | depart,use lane straight,arrive | ,left:false through:true, | + | i,d | cross,road,road | depart,turn left,arrive | ,left:true through:false, | + | i,l | cross,cross,cross | depart,continue uturn,arrive | ,left:true through:false, | + + #copy of former case to prevent further regression + Scenario: Turn Lanes at Segregated Road + Given the node map + | | | i | l | | | + | | | | | | | + | h | | g | f | | e | + | a | | b | c | | d | + | | | | | | | + | | | j | k | | | + + And the ways + | nodes | name | turn:lanes:forward | oneway | + | ab | road | left\|through&right | yes | + | bc | road | left\|through | yes | + | cd | road | | yes | + | ef | road | \|through&through;right | yes | + | fg | road | left;through\|through& | yes | + | gh | road | | yes | + | ig | cross | | yes | + | gb | cross | left\|through | yes | + | bj | cross | | yes | + | kc | cross | left\|through;right | yes | + | cf | cross | left\|through | yes | + | fl | cross | | yes | + + When I route I should get + | waypoints | route | turns | lanes | + | a,j | road,cross,cross | depart,turn right,arrive | ,left:false through:false right:true, | + | k,d | cross,road,road | depart,turn right,arrive | ,left:false through;right:true, | + | e,l | road,cross,cross | depart,turn right,arrive | ,none:false through:false through;right:true, | + | i,h | cross,road,road | depart,turn right,arrive | ,, | + | i,j | cross,cross,cross | depart,use lane straight,arrive | ,left:false through:true, | + | i,l | cross,cross,cross | depart,continue uturn,arrive | ,left:true through:false, | Scenario: Turn Lanes at Segregated Road Given the node map @@ -170,8 +204,8 @@ Feature: Turn Lane Guidance | cf | cross | | yes | When I route I should get - | waypoints | route | turns | lanes | - | a,j | road,cross,cross | depart,turn right,arrive | ,0, | + | waypoints | route | turns | lanes | + | a,j | road,cross,cross | depart,turn right,arrive | ,left:false through:false right:true, | #this can happen due to traffic lights / lanes not drawn up to the intersection itself Scenario: Turn Lanes Given earlier than actual turn @@ -188,9 +222,9 @@ Feature: Turn Lane Guidance | ce | turn | | When I route I should get - | waypoints | route | turns | lanes | - | a,e | road,turn,turn | depart,turn right,arrive | ,0, | - | a,d | road,road,road | depart,use lane straight,arrive | ,1, | + | waypoints | route | turns | lanes | + | a,e | road,turn,turn | depart,turn right,arrive | ,none:false right:true, | + | a,d | road,road,road | depart,use lane straight,arrive | ,none:true right:false, | Scenario: Turn Lanes Given earlier than actual turn Given the node map @@ -208,11 +242,11 @@ Feature: Turn Lane Guidance | hk | second-turn | | | When I route I should get - | waypoints | route | turns | lanes | - | a,k | road,second-turn,second-turn | depart,turn right,arrive | ,0, | - | a,i | road,road,road | depart,use lane straight,arrive | ,1, | - | i,j | road,first-turn,first-turn | depart,turn left,arrive | ,1, | - | i,a | road,road,road | depart,use lane straight,arrive | ,0, | + | waypoints | route | turns | lanes | + | a,k | road,second-turn,second-turn | depart,turn right,arrive | ,none:false right:true, | + | a,i | road,road,road | depart,use lane straight,arrive | ,none:true right:false, | + | i,j | road,first-turn,first-turn | depart,turn left,arrive | ,left:true none:false, | + | i,a | road,road,road | depart,use lane straight,arrive | ,left:false none:true, | Scenario: Passing a one-way street Given the node map @@ -227,8 +261,8 @@ Feature: Turn Lane Guidance | cf | turn | | | When I route I should get - | waypoints | route | turns | lanes | - | a,f | road,turn,turn | depart,turn left,arrive | ,1, | + | waypoints | route | turns | lanes | + | a,f | road,turn,turn | depart,turn left,arrive | ,left:true through:false, | Scenario: Passing a one-way street, partly pulled back lanes Given the node map @@ -245,9 +279,9 @@ Feature: Turn Lane Guidance | bg | right | | no | When I route I should get - | waypoints | route | turns | lanes | - | a,f | road,turn,turn | depart,turn left,arrive | ,1, | - | a,g | road,right,right | depart,turn right,arrive | ,0, | + | waypoints | route | turns | lanes | + | a,f | road,turn,turn | depart,turn left,arrive | ,left:true through;right:false, | + | a,g | road,right,right | depart,turn right,arrive | ,left:false through;right:true, | Scenario: Passing a one-way street, partly pulled back lanes, no through Given the node map @@ -264,11 +298,12 @@ Feature: Turn Lane Guidance | bg | right | | no | When I route I should get - | waypoints | route | turns | lanes | - | a,f | road,turn,turn | depart,turn left,arrive | ,1, | - | a,g | road,right,right | depart,turn right,arrive | ,0, | + | waypoints | route | turns | lanes | + | a,f | road,turn,turn | depart,turn left,arrive | ,left:true right:false, | + | a,g | road,right,right | depart,turn right,arrive | ,left:false right:true, | - Scenario: Narrowing Turn Lanes + @todo @bug + Scenario: Narrowing Turn Lanes Given the node map | | | | | g | | | | | | | | | @@ -285,12 +320,12 @@ Feature: Turn Lane Guidance | cf | right | | When I route I should get - | waypoints | route | turns | lanes | - | a,g | road,left,left | depart,turn left,arrive | ,2, | - | a,e | road,through,through | depart,new name straight,arrive | ,1, | - | a,f | road,right,right | depart,turn right,arrive | ,0, | + | waypoints | route | turns | lanes | + | a,g | road,left,left | depart,turn left,arrive | ,left:true through:false right:false, | + | a,e | road,through,through | depart,new name straight,arrive | ,left:false through:true right:false, | + | a,f | road,right,right | depart,turn right,arrive | ,left:false through:false right:true, | - Scenario: Turn at a traffic light + Scenario: Turn at a traffic light Given the node map | a | b | c | d | | | | e | | @@ -307,12 +342,12 @@ Feature: Turn Lane Guidance | ce | turn | | When I route I should get - | waypoints | route | turns | lanes | - | a,d | road,road,road | depart,use lane straight,arrive | ,1, | - | a,e | road,turn,turn | depart,turn right,arrive | ,0, | + | waypoints | route | turns | lanes | + | a,d | road,road,road | depart,use lane straight,arrive | ,through:true right:false, | + | a,e | road,turn,turn | depart,turn right,arrive | ,through:false right:true, | - - Scenario: Theodor Heuss Platz + @bug @todo + Scenario: Theodor Heuss Platz Given the node map | | | | i | o | | | l | | | | | b | | | | a | | m | @@ -343,10 +378,10 @@ Feature: Turn Lane Guidance | hl | top-right-out | | | yes | secondary | When I route I should get - | waypoints | route | turns | lanes | - | i,m | top,top-right,top-right | depart,roundabout-exit-4,arrive | ,0 1 2, | - | i,l | top,top-right-out,top-right-out | depart,roundabout-exit-4,arrive | ,2 3, | - | i,o | top,top,top | depart,roundabout-exit-5,arrive | ,, | + | waypoints | route | turns | lanes | + | i,m | top,top-right,top-right | depart,roundabout-exit-4,arrive | ,slight_left:false slight_left;slight_right:true slight_right:true slight_right:true, | + | i,l | top,top-right-out,top-right-out | depart,roundabout-exit-4,arrive | ,slight_left:true slight_left;slight_right:true slight_right:false slight_right:false, | + | i,o | top,top,top | depart,roundabout-exit-5,arrive | ,, | Scenario: Turn Lanes Breaking up Given the node map @@ -371,9 +406,9 @@ Feature: Turn Lane Guidance | restriction | bc | fdcg | c | no_right_turn | When I route I should get - | waypoints | route | turns | lanes | - | a,g | road,cross,cross | depart,turn left,arrive | ,2 3, | - | a,e | road,road,road | depart,use lane straight,arrive | ,0 1, | + | waypoints | route | turns | lanes | + | a,g | road,cross,cross | depart,turn left,arrive | ,left:true left:true through:false through:false, | + | a,e | road,road,road | depart,use lane straight,arrive | ,left:false left:false through:true through:true, | Scenario: U-Turn Road at Intersection Given the node map @@ -394,11 +429,11 @@ Feature: Turn Lane Guidance | gdeh | cross | | no | primary | When I route I should get - | from | to | bearings | route | turns | lanes | - | a | g | 180,180 180,180 | road,cross,cross | depart,turn right,arrive | ,0, | - | a | h | 180,180 180,180 | road,cross,cross | depart,turn left,arrive | ,2, | - | a | i | 180,180 180,180 | road,road,road | depart,use lane straight,arrive | ,1 2, | - | b | a | 90,2 270,2 | road,road,road | depart,continue uturn,arrive | ,2, | + | from | to | bearings | route | turns | lanes | + | a | g | 180,180 180,180 | road,cross,cross | depart,turn right,arrive | ,none:false through:false right:true, | + | a | h | 180,180 180,180 | road,cross,cross | depart,turn left,arrive | ,none:true through:false right:false, | + | a | i | 180,180 180,180 | road,road,road | depart,use lane straight,arrive | ,none:true through:true right:false, | + | b | a | 90,2 270,2 | road,road,road | depart,continue uturn,arrive | ,none:true through:false right:false, | Scenario: Segregated Intersection Merges With Lanes Given the node map @@ -419,12 +454,13 @@ Feature: Turn Lane Guidance | cf | left | | yes | primary | When I route I should get - | waypoints | route | turns | lanes | - | a,f | road,left,left | depart,turn left,arrive | ,2 3 4, | - | a,e | road,road,road | depart,turn uturn,arrive | ,4, | - | a,g | road,straight,straight | depart,new name straight,arrive | ,0 1, | + | waypoints | route | turns | lanes | + | a,f | road,left,left | depart,turn left,arrive | ,left:true left:true left:true through:false through:false, | + | a,e | road,road,road | depart,turn uturn,arrive | ,left:true left:false left:false through:false through:false, | + | a,g | road,straight,straight | depart,new name straight,arrive | ,left:false left:false left:false through:true through:true, | - Scenario: Passing Through a Roundabout + @bug @todo + Scenario: Passing Through a Roundabout Given the node map | | | h | | g | | | | | a | | | | f | k | @@ -466,9 +502,9 @@ Feature: Turn Lane Guidance | ce | cross | | primary | When I route I should get - | waypoints | route | turns | lanes | - | a,d | road,road,road | depart,use lane straight,arrive | ,1 2 3, | - | a,e | road,cross,cross | depart,turn slight right,arrive | ,0 1, | + | waypoints | route | turns | lanes | + | a,d | road,road,road | depart,use lane straight,arrive | ,through:true through:true through;slight_right:true slight_right:false, | + | a,e | road,cross,cross | depart,turn slight right,arrive | ,through:false through:false through;slight_right:true slight_right:true, | Scenario: Highway Ramp Given the node map @@ -482,11 +518,12 @@ Feature: Turn Lane Guidance | ce | ramp | | motorway_link | When I route I should get - | waypoints | route | turns | lanes | - | a,d | hwy,hwy,hwy | depart,use lane straight,arrive | ,1 2 3, | - | a,e | hwy,ramp,ramp | depart,off ramp slight right,arrive | ,0 1, | + | waypoints | route | turns | lanes | + | a,d | hwy,hwy,hwy | depart,use lane straight,arrive | ,through:true through:true through;slight_right:true slight_right:false, | + | a,e | hwy,ramp,ramp | depart,off ramp slight right,arrive | ,through:false through:false through;slight_right:true slight_right:true, | - Scenario: Turning Off Ramp + @bug @todo + Scenario: Turning Off Ramp Given the node map | | a | | | d | c | b | @@ -502,12 +539,12 @@ Feature: Turn Lane Guidance | fh | on | | motorway_link | yes | When I route I should get - | waypoints | route | turns | lanes | - | a,d | off,road,road | depart,turn_right,arrive | ,0, | - | a,g | off,road,road | depart,turn_left,arrive | ,1, | - | a,h | | | | + | waypoints | route | turns | lanes | + | a,d | off,road,road | depart,turn_right,arrive | ,left:false right:true, | + | a,g | off,road,road | depart,turn_left,arrive | ,left:true right:false, | + | a,h | | | | - Scenario: Off Ramp In a Turn + Scenario: Off Ramp In a Turn Given the node map | a | | | | | | | | | | | | | | | | | | | | | | | | | @@ -521,11 +558,11 @@ Feature: Turn Lane Guidance | bd | ramp | | motorway_link | yes | When I route I should get - | waypoints | route | turns | lanes | - | a,c | hwy,hwy,hwy | depart,use lane slight left,arrive | ,1 2, | - | a,d | hwy,ramp,ramp | depart,off ramp slight right,arrive | ,0, | + | waypoints | route | turns | lanes | + | a,c | hwy,hwy,hwy | depart,use lane slight left,arrive | ,through:true through:true slight_right:false, | + | a,d | hwy,ramp,ramp | depart,off ramp slight right,arrive | ,through:false through:false slight_right:true, | - Scenario: Reverse Lane in Segregated Road + Scenario: Reverse Lane in Segregated Road Given the node map | h | | | | | g | | | | | | f | | | | | | | | | e | | | | | @@ -540,8 +577,8 @@ Feature: Turn Lane Guidance | fgh | road | | primary | yes | When I route I should get - | waypoints | route | turns | lanes | - | a,h | road,road,road | depart,continue uturn,arrive | ,2, | + | waypoints | route | turns | lanes | + | a,h | road,road,road | depart,continue uturn,arrive | ,reverse:true through:false through:false,| Scenario: Reverse Lane in Segregated Road with none Given the node map @@ -558,8 +595,8 @@ Feature: Turn Lane Guidance | fgh | road | | primary | yes | When I route I should get - | waypoints | route | turns | lanes | - | a,h | road,road,road | depart,continue uturn,arrive | ,2, | + | waypoints | route | turns | lanes | + | a,h | road,road,road | depart,continue uturn,arrive | ,reverse:true through:false none:false, | Scenario: Reverse Lane in Segregated Road with none, Service Turn Prior Given the node map @@ -578,8 +615,8 @@ Feature: Turn Lane Guidance | ji | park | | service | no | When I route I should get - | waypoints | route | turns | lanes | - | a,h | road,road,road | depart,continue uturn,arrive | ,2, | + | waypoints | route | turns | lanes | + | a,h | road,road,road | depart,continue uturn,arrive | ,reverse:true through:false none:false, | Scenario: Don't collapse everything to u-turn / too wide Given the node map @@ -596,11 +633,11 @@ Feature: Turn Lane Guidance | cf | secondary | bottom | | When I route I should get - | waypoints | turns | route | lanes | - | a,d | depart,continue right,end of road right,arrive | road,road,road,road | ,0,, | - | d,a | depart,continue left,end of road left,arrive | road,road,road,road | ,1,, | + | waypoints | turns | route | lanes | + | a,d | depart,continue right,end of road right,arrive | road,road,road,road | ,through:false right:true,, | + | d,a | depart,continue left,end of road left,arrive | road,road,road,road | ,left:true through:false,, | - Scenario: Merge Lanes Onto Freeway + Scenario: Merge Lanes Onto Freeway Given the node map | a | | | b | c | | | d | | | | @@ -611,10 +648,10 @@ Feature: Turn Lane Guidance | db | motorway_link | ramp | slight_right\|slight_right | When I route I should get - | waypoints | turns | route | lanes | - | d,c | depart,merge slight left,arrive | ramp,Hwy,Hwy | ,0 1, | + | waypoints | turns | route | lanes | + | d,c | depart,merge slight left,arrive | ramp,Hwy,Hwy | ,slight_right:true slight_right:true, | - Scenario: Fork on motorway links - don't fork on through but use lane + Scenario: Fork on motorway links - don't fork on through but use lane Given the node map | i | | | | | a | | j | | c | b | | x | @@ -628,6 +665,6 @@ Feature: Turn Lane Guidance | ab | on | motorway_link | | When I route I should get - | waypoints | route | turns | lanes | - | a,j | on,xbcj,xbcj,xbcj | depart,merge slight left,use lane straight,arrive | ,,1, | - | a,i | on,xbcj,off,off | depart,merge slight left,turn slight right,arrive | ,,0, | + | waypoints | route | turns | lanes | + | a,j | on,xbcj,xbcj,xbcj | depart,merge slight left,use lane straight,arrive | ,,none:true slight_right:false, | + | a,i | on,xbcj,off,off | depart,merge slight left,turn slight right,arrive | ,,none:false slight_right:true, | diff --git a/features/support/data.js b/features/support/data.js index 375229d67..17c5bbfdd 100644 --- a/features/support/data.js +++ b/features/support/data.js @@ -223,7 +223,7 @@ module.exports = function () { }; ['osrm', 'osrm.ebg', 'osrm.edges', 'osrm.enw', 'osrm.fileIndex', 'osrm.geometry', 'osrm.icd', - 'osrm.names', 'osrm.nodes', 'osrm.properties', 'osrm.ramIndex', 'osrm.restrictions'].forEach(file => { + 'osrm.names', 'osrm.nodes', 'osrm.properties', 'osrm.ramIndex', 'osrm.restrictions', 'osrm.tld', 'osrm.tls'].forEach(file => { q.defer(rename, file); }); @@ -283,7 +283,7 @@ module.exports = function () { ['osrm', 'osrm.core', 'osrm.datasource_indexes', 'osrm.datasource_names', 'osrm.ebg','osrm.edges', 'osrm.enw', 'osrm.fileIndex', 'osrm.geometry', 'osrm.hsgr', 'osrm.icd','osrm.level', 'osrm.names', - 'osrm.nodes', 'osrm.properties', 'osrm.ramIndex', 'osrm.restrictions'].forEach((file) => { + 'osrm.nodes', 'osrm.properties', 'osrm.ramIndex', 'osrm.restrictions', 'osrm.tld', 'osrm.tls'].forEach((file) => { q.defer(rename, file); }); diff --git a/features/support/route.js b/features/support/route.js index 20e052b5a..ea0482627 100644 --- a/features/support/route.js +++ b/features/support/route.js @@ -169,7 +169,14 @@ module.exports = function () { }; this.lanesList = (instructions) => { - return this.extractInstructionList(instructions, instruction => ('lanes' in instruction.maneuver ? instruction.maneuver.lanes.join(' ') : '')); + return this.extractInstructionList(instructions, instruction => { + if( 'lanes' in instruction.maneuver ) + { + return instruction.maneuver.lanes.map( p => { return p.marked + ':' + p.take; } ).join(' '); + } else + { + return ''; + }}); }; this.turnList = (instructions) => { diff --git a/features/support/shared_steps.js b/features/support/shared_steps.js index 6ffe62886..6db540069 100644 --- a/features/support/shared_steps.js +++ b/features/support/shared_steps.js @@ -33,7 +33,8 @@ module.exports = function () { var afterRequest = (err, res, body) => { if (err) return cb(err); if (body && body.length) { - let destinations, pronunciations, instructions, bearings, turns, modes, times, distances, summary, intersections, lanes; + let destinations, pronunciations, instructions, bearings, turns, modes, times, + distances, summary, intersections, lanes; let json = JSON.parse(body); @@ -103,12 +104,10 @@ module.exports = function () { got.time = instructions ? util.format('%ds', time) : ''; } - if (headers.has('lanes')) { got.lanes = (lanes || '').trim(); } - if (headers.has('speed')) { if (row.speed !== '' && instructions) { if (!row.speed.match(/\d+ km\/h/)) diff --git a/include/engine/api/route_api.hpp b/include/engine/api/route_api.hpp index 31724fe5e..f3965caa1 100644 --- a/include/engine/api/route_api.hpp +++ b/include/engine/api/route_api.hpp @@ -12,6 +12,7 @@ #include "engine/guidance/assemble_overview.hpp" #include "engine/guidance/assemble_route.hpp" #include "engine/guidance/assemble_steps.hpp" +#include "engine/guidance/lane_processing.hpp" #include "engine/guidance/post_processing.hpp" #include "engine/internal_route_result.hpp" diff --git a/include/engine/datafacade/datafacade_base.hpp b/include/engine/datafacade/datafacade_base.hpp index 22b8ad169..8f2558fce 100644 --- a/include/engine/datafacade/datafacade_base.hpp +++ b/include/engine/datafacade/datafacade_base.hpp @@ -138,6 +138,10 @@ class BaseDataFacade const int bearing, const int bearing_range) const = 0; + virtual bool hasLaneData(const EdgeID id) const = 0; + virtual util::guidance::LaneTupelIdPair GetLaneData(const EdgeID id) const = 0; + virtual std::string GetTurnStringForID(const LaneStringID lane_string_id) const = 0; + virtual unsigned GetCheckSum() const = 0; virtual bool IsCoreNode(const NodeID id) const = 0; diff --git a/include/engine/datafacade/internal_datafacade.hpp b/include/engine/datafacade/internal_datafacade.hpp index bd45888ca..25a4a19db 100644 --- a/include/engine/datafacade/internal_datafacade.hpp +++ b/include/engine/datafacade/internal_datafacade.hpp @@ -16,6 +16,7 @@ #include "storage/storage_config.hpp" #include "engine/geospatial_query.hpp" #include "util/graph_loader.hpp" +#include "util/guidance/turn_lanes.hpp" #include "util/io.hpp" #include "util/packed_vector.hpp" #include "util/range_table.hpp" @@ -78,8 +79,11 @@ class InternalDataFacade final : public BaseDataFacade util::ShM::vector m_via_node_list; util::ShM::vector m_name_ID_list; util::ShM::vector m_turn_instruction_list; + util::ShM::vector m_lane_data_id; + util::ShM::vector m_lane_tupel_id_pairs; util::ShM::vector m_travel_mode_list; util::ShM::vector m_names_char_list; + util::ShM::vector m_lanes_char_list; util::ShM::vector m_geometry_indices; util::ShM::vector m_geometry_list; util::ShM::vector m_is_core_node; @@ -93,6 +97,7 @@ class InternalDataFacade final : public BaseDataFacade boost::filesystem::path ram_index_path; boost::filesystem::path file_index_path; util::RangeTable<16, false> m_name_table; + util::RangeTable<16, false> m_lane_string_table; // bearing classes by node based node util::ShM::vector m_bearing_class_id_table; @@ -118,6 +123,20 @@ class InternalDataFacade final : public BaseDataFacade sizeof(m_profile_properties)); } + void LoadLaneTupelIdPairs(const boost::filesystem::path &lane_data_path) + { + boost::filesystem::ifstream in_stream(lane_data_path); + if (!in_stream) + { + throw util::exception("Could not open " + lane_data_path.string() + " for reading."); + } + std::uint64_t size; + in_stream.read(reinterpret_cast(&size), sizeof(size)); + m_lane_tupel_id_pairs.resize(size); + in_stream.read(reinterpret_cast(&m_lane_tupel_id_pairs[0]), + sizeof(m_lane_tupel_id_pairs) * size); + } + void LoadTimestamp(const boost::filesystem::path ×tamp_path) { util::SimpleLogger().Write() << "Loading Timestamp"; @@ -173,6 +192,7 @@ class InternalDataFacade final : public BaseDataFacade m_via_node_list.resize(number_of_edges); m_name_ID_list.resize(number_of_edges); m_turn_instruction_list.resize(number_of_edges); + m_lane_data_id.resize(number_of_edges); m_travel_mode_list.resize(number_of_edges); m_entry_class_id_list.resize(number_of_edges); @@ -184,6 +204,7 @@ class InternalDataFacade final : public BaseDataFacade m_via_node_list[i] = current_edge_data.via_node; m_name_ID_list[i] = current_edge_data.name_id; m_turn_instruction_list[i] = current_edge_data.turn_instruction; + m_lane_data_id[i] = current_edge_data.lane_data_id; m_travel_mode_list[i] = current_edge_data.travel_mode; m_entry_class_id_list[i] = current_edge_data.entry_classid; } @@ -284,6 +305,20 @@ class InternalDataFacade final : public BaseDataFacade new InternalGeospatialQuery(*m_static_rtree, m_coordinate_list, *this)); } + void LoadLaneStrings(const boost::filesystem::path &lane_string_file) + { + boost::filesystem::ifstream lane_stream(lane_string_file, std::ios::binary); + + lane_stream >> m_lane_string_table; + + unsigned number_of_chars = 0; + lane_stream.read((char *)&number_of_chars, sizeof(unsigned)); + m_lanes_char_list.resize(number_of_chars + 1); //+1 gives sentinel element + if( number_of_chars ) + lane_stream.read((char *)&m_lanes_char_list[0], number_of_chars * sizeof(char)); + m_lanes_char_list[number_of_chars] = '\0'; + } + void LoadStreetNames(const boost::filesystem::path &names_file) { boost::filesystem::ifstream name_stream(names_file, std::ios::binary); @@ -386,11 +421,17 @@ class InternalDataFacade final : public BaseDataFacade util::SimpleLogger().Write() << "loading street names"; LoadStreetNames(config.names_data_path); + util::SimpleLogger().Write() << "loading lane tags"; + LoadLaneStrings(config.turn_lane_string_path); + util::SimpleLogger().Write() << "loading rtree"; LoadRTree(); util::SimpleLogger().Write() << "loading intersection class data"; LoadIntersectionClasses(config.intersection_class_path); + + util::SimpleLogger().Write() << "Loading Lane Data Pairs"; + LoadLaneTupelIdPairs(config.turn_lane_data_path); } // search graph access @@ -741,6 +782,37 @@ class InternalDataFacade final : public BaseDataFacade { return m_entry_class_table.at(entry_class_id); } + + bool hasLaneData(const EdgeID id) const override final + { + return m_lane_data_id[id] != INVALID_LANE_DATAID; + } + + util::guidance::LaneTupelIdPair GetLaneData(const EdgeID id) const override final + { + BOOST_ASSERT(hasLaneData(id)); + return m_lane_tupel_id_pairs[m_lane_data_id[id]]; + } + + std::string GetTurnStringForID(const LaneStringID lane_string_id) const override final + { + if (INVALID_LANE_STRINGID == lane_string_id) + { + return ""; + } + auto range = m_lane_string_table.GetRange(lane_string_id); + + std::string result; + result.reserve(range.size()); + if (range.begin() != range.end()) + { + result.resize(range.back() - range.front() + 1); + std::copy(m_lanes_char_list.begin() + range.front(), + m_lanes_char_list.begin() + range.back() + 1, + result.begin()); + } + return result; + } }; } } diff --git a/include/engine/datafacade/shared_datafacade.hpp b/include/engine/datafacade/shared_datafacade.hpp index ea20392e3..2ceeb9994 100644 --- a/include/engine/datafacade/shared_datafacade.hpp +++ b/include/engine/datafacade/shared_datafacade.hpp @@ -12,6 +12,7 @@ #include "extractor/profile_properties.hpp" #include "util/guidance/bearing_class.hpp" #include "util/guidance/entry_class.hpp" +#include "util/guidance/turn_lanes.hpp" #include "engine/geospatial_query.hpp" #include "util/make_unique.hpp" @@ -79,10 +80,14 @@ class SharedDataFacade final : public BaseDataFacade util::PackedVector m_osmnodeid_list; util::ShM::vector m_via_node_list; util::ShM::vector m_name_ID_list; + util::ShM::vector m_lane_data_id; util::ShM::vector m_turn_instruction_list; util::ShM::vector m_travel_mode_list; util::ShM::vector m_names_char_list; + util::ShM::vector m_turn_string_char_list; util::ShM::vector m_name_begin_indices; + util::ShM::vector m_lane_string_char_list; + util::ShM::vector m_lane_string_begin_indices; util::ShM::vector m_geometry_indices; util::ShM::vector m_geometry_list; util::ShM::vector m_is_core_node; @@ -91,12 +96,14 @@ class SharedDataFacade final : public BaseDataFacade util::ShM::vector m_datasource_name_data; util::ShM::vector m_datasource_name_offsets; util::ShM::vector m_datasource_name_lengths; + util::ShM::vector m_lane_tupel_id_pairs; std::unique_ptr m_static_rtree; std::unique_ptr m_geospatial_query; boost::filesystem::path file_index_path; std::shared_ptr> m_name_table; + std::shared_ptr> m_turn_string_table; // bearing classes by node based node util::ShM::vector m_bearing_class_id_table; @@ -186,6 +193,19 @@ class SharedDataFacade final : public BaseDataFacade travel_mode_list_ptr, data_layout->num_entries[storage::SharedDataLayout::TRAVEL_MODE]); m_travel_mode_list = std::move(travel_mode_list); + auto lane_data_id_ptr = data_layout->GetBlockPtr( + shared_memory, storage::SharedDataLayout::LANE_DATA_ID); + util::ShM::vector lane_data_id( + lane_data_id_ptr, data_layout->num_entries[storage::SharedDataLayout::LANE_DATA_ID]); + m_lane_data_id = std::move(lane_data_id); + + auto lane_tupel_id_pair_ptr = data_layout->GetBlockPtr( + shared_memory, storage::SharedDataLayout::TURN_LANE_DATA); + util::ShM::vector lane_tupel_id_pair( + lane_tupel_id_pair_ptr, + data_layout->num_entries[storage::SharedDataLayout::TURN_LANE_DATA]); + m_lane_tupel_id_pairs = std::move(lane_tupel_id_pair); + auto turn_instruction_list_ptr = data_layout->GetBlockPtr( shared_memory, storage::SharedDataLayout::TURN_INSTRUCTION); @@ -238,6 +258,29 @@ class SharedDataFacade final : public BaseDataFacade m_names_char_list = std::move(names_char_list); } + void LoadTurnLaneStrings() + { + auto offsets_ptr = data_layout->GetBlockPtr( + shared_memory, storage::SharedDataLayout::TURN_STRING_OFFSETS); + auto blocks_ptr = data_layout->GetBlockPtr( + shared_memory, storage::SharedDataLayout::TURN_STRING_BLOCKS); + util::ShM::vector turn_string_offsets( + offsets_ptr, data_layout->num_entries[storage::SharedDataLayout::TURN_STRING_OFFSETS]); + util::ShM::vector turn_string_blocks( + blocks_ptr, data_layout->num_entries[storage::SharedDataLayout::TURN_STRING_BLOCKS]); + + auto turn_strings_list_ptr = data_layout->GetBlockPtr( + shared_memory, storage::SharedDataLayout::TURN_STRING_CHAR_LIST); + util::ShM::vector turn_strings_char_list( + turn_strings_list_ptr, + data_layout->num_entries[storage::SharedDataLayout::TURN_STRING_CHAR_LIST]); + m_turn_string_table = util::make_unique>( + turn_string_offsets, + turn_string_blocks, + static_cast(turn_strings_char_list.size())); + + m_turn_string_char_list = std::move(turn_strings_char_list); + } void LoadCoreInformation() { if (data_layout->num_entries[storage::SharedDataLayout::CORE_MARKER] <= 0) @@ -416,6 +459,7 @@ class SharedDataFacade final : public BaseDataFacade LoadTimestamp(); LoadViaNodeList(); LoadNames(); + LoadTurnLaneStrings(); LoadCoreInformation(); LoadProfileProperties(); LoadRTree(); @@ -783,6 +827,37 @@ class SharedDataFacade final : public BaseDataFacade { return m_entry_class_table.at(entry_class_id); } + + bool hasLaneData(const EdgeID id) const override final + { + return INVALID_LANE_DATAID != m_lane_data_id.at(id); + } + + util::guidance::LaneTupelIdPair GetLaneData(const EdgeID id) const override final + { + BOOST_ASSERT(hasLaneData(id)); + return m_lane_tupel_id_pairs.at(m_lane_data_id.at(id)); + } + + std::string GetTurnStringForID(const LaneStringID lane_string_id) const override final + { + if (INVALID_LANE_STRINGID == lane_string_id) + { + return ""; + } + auto range = m_turn_string_table->GetRange(lane_string_id); + + std::string result; + result.reserve(range.size()); + if (range.begin() != range.end()) + { + result.resize(range.back() - range.front() + 1); + std::copy(m_turn_string_char_list.begin() + range.front(), + m_turn_string_char_list.begin() + range.back() + 1, + result.begin()); + } + return result; + } }; } } diff --git a/include/engine/guidance/assemble_steps.hpp b/include/engine/guidance/assemble_steps.hpp index 68a36b4c0..39526d1e5 100644 --- a/include/engine/guidance/assemble_steps.hpp +++ b/include/engine/guidance/assemble_steps.hpp @@ -15,6 +15,7 @@ #include "util/coordinate_calculation.hpp" #include "util/guidance/entry_class.hpp" #include "util/guidance/toolkit.hpp" +#include "util/guidance/turn_lanes.hpp" #include "util/typedefs.hpp" #include @@ -70,7 +71,9 @@ inline std::vector assembleSteps(const datafacade::BaseDataFacade &fa bearings.second, extractor::guidance::TurnInstruction::NO_TURN(), WaypointType::Depart, - 0}; + 0, + util::guidance::LaneTupel(), + ""}; Intersection intersection{source_node.location, std::vector({bearings.second}), std::vector({true}), @@ -147,7 +150,11 @@ inline std::vector assembleSteps(const datafacade::BaseDataFacade &fa bearings.second, path_point.turn_instruction, WaypointType::None, - 0}; + 0, + path_point.lane_data.first, + (path_point.lane_data.second != INVALID_LANE_STRINGID + ? facade.GetTurnStringForID(path_point.lane_data.second) + : "")}; segment_index++; segment_duration = 0; } @@ -202,7 +209,9 @@ inline std::vector assembleSteps(const datafacade::BaseDataFacade &fa bearings.second, extractor::guidance::TurnInstruction::NO_TURN(), WaypointType::Arrive, - 0}; + 0, + util::guidance::LaneTupel(), + ""}; intersection = { target_node.location, std::vector({static_cast(util::bearing::reverseBearing(bearings.first))}), @@ -233,6 +242,9 @@ inline std::vector assembleSteps(const datafacade::BaseDataFacade &fa BOOST_ASSERT(steps.back().intersections.front().bearings.size() == 1); BOOST_ASSERT(steps.back().intersections.front().entry.size() == 1); BOOST_ASSERT(steps.back().maneuver.waypoint_type == WaypointType::Arrive); + BOOST_ASSERT(steps.back().maneuver.lanes.lanes_in_turn == 0); + BOOST_ASSERT(steps.back().maneuver.lanes.first_lane_from_the_right == INVALID_LANEID); + BOOST_ASSERT(steps.back().maneuver.turn_lane_string == ""); return steps; } diff --git a/include/engine/guidance/lane_processing.hpp b/include/engine/guidance/lane_processing.hpp new file mode 100644 index 000000000..c3d7f16dd --- /dev/null +++ b/include/engine/guidance/lane_processing.hpp @@ -0,0 +1,24 @@ +#ifndef OSRM_ENGINE_GUIDANCE_LANE_PROCESSING_HPP_ +#define OSRM_ENGINE_GUIDANCE_LANE_PROCESSING_HPP_ + +#include + +#include "engine/guidance/route_step.hpp" + +namespace osrm +{ +namespace engine +{ +namespace guidance +{ + +// 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 anticipateLaneChange(std::vector steps); + +} // namespace guidance +} // namespace engine +} // namespace osrm + +#endif /* OSRM_ENGINE_GUIDANCE_LANE_PROCESSING_HPP_ */ diff --git a/include/engine/guidance/post_processing.hpp b/include/engine/guidance/post_processing.hpp index 37adf7637..16d383df6 100644 --- a/include/engine/guidance/post_processing.hpp +++ b/include/engine/guidance/post_processing.hpp @@ -43,11 +43,6 @@ std::vector buildIntersections(std::vector steps); // remove steps invalidated by post-processing std::vector removeNoTurnInstructions(std::vector 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 anticipateLaneChange(std::vector steps); - // postProcess will break the connection between the leg geometry // for which a segment is supposed to represent exactly the coordinates // between routing maneuvers and the route steps itself. diff --git a/include/engine/guidance/step_maneuver.hpp b/include/engine/guidance/step_maneuver.hpp index 1c2b55a2c..213a3695c 100644 --- a/include/engine/guidance/step_maneuver.hpp +++ b/include/engine/guidance/step_maneuver.hpp @@ -3,8 +3,10 @@ #include "extractor/guidance/turn_instruction.hpp" #include "util/coordinate.hpp" +#include "util/guidance/turn_lanes.hpp" #include +#include #include namespace osrm @@ -27,8 +29,12 @@ struct StepManeuver short bearing_before; short bearing_after; extractor::guidance::TurnInstruction instruction; + WaypointType waypoint_type; unsigned exit; + + util::guidance::LaneTupel lanes; + std::string turn_lane_string; }; inline StepManeuver getInvalidStepManeuver() @@ -38,7 +44,9 @@ inline StepManeuver getInvalidStepManeuver() 0, extractor::guidance::TurnInstruction::NO_TURN(), WaypointType::None, - 0}; + 0, + util::guidance::LaneTupel(), + ""}; } } // namespace guidance diff --git a/include/engine/internal_route_result.hpp b/include/engine/internal_route_result.hpp index af5870596..6f1076975 100644 --- a/include/engine/internal_route_result.hpp +++ b/include/engine/internal_route_result.hpp @@ -4,9 +4,9 @@ #include "extractor/guidance/turn_instruction.hpp" #include "extractor/travel_mode.hpp" #include "engine/phantom_node.hpp" -#include "util/typedefs.hpp" - #include "osrm/coordinate.hpp" +#include "util/guidance/turn_lanes.hpp" +#include "util/typedefs.hpp" #include @@ -27,6 +27,8 @@ struct PathData EdgeWeight duration_until_turn; // instruction to execute at the turn extractor::guidance::TurnInstruction turn_instruction; + // turn lane data + util::guidance::LaneTupelIdPair lane_data; // travel mode of the street that leads to the turn extractor::TravelMode travel_mode : 4; // entry class of the turn, indicating possibility of turns diff --git a/include/engine/routing_algorithms/routing_base.hpp b/include/engine/routing_algorithms/routing_base.hpp index 8181dffb4..c1ba386b8 100644 --- a/include/engine/routing_algorithms/routing_base.hpp +++ b/include/engine/routing_algorithms/routing_base.hpp @@ -327,10 +327,14 @@ template class BasicRoutingInterface name_index, weight_vector[i], extractor::guidance::TurnInstruction::NO_TURN(), + {{0, INVALID_LANEID}, INVALID_LANE_STRINGID}, travel_mode, INVALID_ENTRY_CLASSID}); } BOOST_ASSERT(unpacked_path.size() > 0); + if (facade->hasLaneData(ed.id)) + unpacked_path.back().lane_data = facade->GetLaneData(ed.id); + unpacked_path.back().entry_classid = facade->GetEntryClassID(ed.id); unpacked_path.back().turn_instruction = turn_instruction; unpacked_path.back().duration_until_turn += (ed.distance - total_weight); @@ -389,6 +393,7 @@ template class BasicRoutingInterface phantom_node_pair.target_phantom.name_id, weight_vector[i], extractor::guidance::TurnInstruction::NO_TURN(), + {{0, INVALID_LANEID}, INVALID_LANE_STRINGID}, target_traversed_in_reverse ? phantom_node_pair.target_phantom.backward_travel_mode : phantom_node_pair.target_phantom.forward_travel_mode, INVALID_ENTRY_CLASSID}); diff --git a/include/extractor/edge_based_graph_factory.hpp b/include/extractor/edge_based_graph_factory.hpp index 373c41111..491cb0fb7 100644 --- a/include/extractor/edge_based_graph_factory.hpp +++ b/include/extractor/edge_based_graph_factory.hpp @@ -59,6 +59,7 @@ class EdgeBasedGraphFactory const util::NameTable &turn_lanes); void Run(const std::string &original_edge_data_filename, + const std::string &turn_lane_data_filename, lua_State *lua_state, const std::string &edge_segment_lookup_filename, const std::string &edge_penalty_filename, @@ -124,6 +125,7 @@ class EdgeBasedGraphFactory unsigned RenumberEdges(); void GenerateEdgeExpandedNodes(); void GenerateEdgeExpandedEdges(const std::string &original_edge_data_filename, + const std::string &turn_lane_data_filename, lua_State *lua_state, const std::string &edge_segment_lookup_filename, const std::string &edge_fixed_penalties_filename, diff --git a/include/extractor/extraction_way.hpp b/include/extractor/extraction_way.hpp index cae6e8faf..8ae948a2c 100644 --- a/include/extractor/extraction_way.hpp +++ b/include/extractor/extraction_way.hpp @@ -2,8 +2,8 @@ #define EXTRACTION_WAY_HPP #include "extractor/travel_mode.hpp" -#include "util/typedefs.hpp" #include "util/guidance/turn_lanes.hpp" +#include "util/typedefs.hpp" #include #include diff --git a/include/extractor/extractor_config.hpp b/include/extractor/extractor_config.hpp index fda782213..fa3cf3979 100644 --- a/include/extractor/extractor_config.hpp +++ b/include/extractor/extractor_config.hpp @@ -61,7 +61,8 @@ struct ExtractorConfig output_file_name = basepath + ".osrm"; restriction_file_name = basepath + ".osrm.restrictions"; names_file_name = basepath + ".osrm.names"; - turn_lane_file_name = basepath + ".osrm.tld"; + turn_lane_strings_file_name = basepath + ".osrm.tls"; + turn_lane_data_file_name = basepath + ".osrm.tld"; timestamp_file_name = basepath + ".osrm.timestamp"; geometry_output_path = basepath + ".osrm.geometry"; node_output_path = basepath + ".osrm.nodes"; @@ -83,7 +84,8 @@ struct ExtractorConfig std::string output_file_name; std::string restriction_file_name; std::string names_file_name; - std::string turn_lane_file_name; + std::string turn_lane_data_file_name; + std::string turn_lane_strings_file_name; std::string timestamp_file_name; std::string geometry_output_path; std::string edge_output_path; diff --git a/include/extractor/guidance/debug.hpp b/include/extractor/guidance/debug.hpp index dd87ca515..601b72d63 100644 --- a/include/extractor/guidance/debug.hpp +++ b/include/extractor/guidance/debug.hpp @@ -35,7 +35,7 @@ inline void printTurnAssignmentData(const NodeID at, for (const auto &road) std::cout << "\t" << toString(road) << "\n"; - //flushes as well + // flushes as well print(turn_lane_data); } diff --git a/include/extractor/guidance/intersection.hpp b/include/extractor/guidance/intersection.hpp index 6665f91b1..940d26fe0 100644 --- a/include/extractor/guidance/intersection.hpp +++ b/include/extractor/guidance/intersection.hpp @@ -22,6 +22,7 @@ struct TurnOperation final EdgeID eid; double angle; TurnInstruction instruction; + LaneDataID lane_data_id; }; // A Connected Road is the internal representation of a potential turn. Internally, we require diff --git a/include/extractor/guidance/intersection_generator.hpp b/include/extractor/guidance/intersection_generator.hpp index e2a72934e..6dcba082c 100644 --- a/include/extractor/guidance/intersection_generator.hpp +++ b/include/extractor/guidance/intersection_generator.hpp @@ -5,9 +5,9 @@ #include "extractor/guidance/intersection.hpp" #include "extractor/query_node.hpp" #include "extractor/restriction_map.hpp" +#include "util/name_table.hpp" #include "util/node_based_graph.hpp" #include "util/typedefs.hpp" -#include "util/name_table.hpp" #include #include diff --git a/include/extractor/guidance/toolkit.hpp b/include/extractor/guidance/toolkit.hpp index f44820ab7..88a52e46a 100644 --- a/include/extractor/guidance/toolkit.hpp +++ b/include/extractor/guidance/toolkit.hpp @@ -5,6 +5,8 @@ #include "util/coordinate.hpp" #include "util/coordinate_calculation.hpp" #include "util/guidance/toolkit.hpp" +#include "util/guidance/turn_lanes.hpp" +#include "util/typedefs.hpp" #include "extractor/compressed_edge_container.hpp" #include "extractor/query_node.hpp" @@ -20,10 +22,12 @@ #include #include #include +#include #include #include #include +#include namespace osrm { @@ -32,6 +36,9 @@ namespace extractor namespace guidance { +using util::guidance::LaneTupelIdPair; +using LaneDataIdMap = std::unordered_map>; + using util::guidance::angularDeviation; namespace detail diff --git a/include/extractor/guidance/turn_analysis.hpp b/include/extractor/guidance/turn_analysis.hpp index d1a880e1d..5642ea5af 100644 --- a/include/extractor/guidance/turn_analysis.hpp +++ b/include/extractor/guidance/turn_analysis.hpp @@ -51,7 +51,7 @@ class TurnAnalysis std::vector transformIntersectionIntoTurns(const Intersection &intersection) const; - const IntersectionGenerator& getGenerator() const; + const IntersectionGenerator &getGenerator() const; private: const util::NodeBasedDynamicGraph &node_based_graph; diff --git a/include/extractor/guidance/turn_instruction.hpp b/include/extractor/guidance/turn_instruction.hpp index d451697ec..c85c0d2c1 100644 --- a/include/extractor/guidance/turn_instruction.hpp +++ b/include/extractor/guidance/turn_instruction.hpp @@ -77,16 +77,14 @@ struct TurnInstruction { using LaneTupel = util::guidance::LaneTupel; TurnInstruction(const TurnType::Enum type = TurnType::Invalid, - const DirectionModifier::Enum direction_modifier = DirectionModifier::Straight, - const LaneTupel lane_tupel = {0, INVALID_LANEID}) - : type(type), direction_modifier(direction_modifier), lane_tupel(lane_tupel) + const DirectionModifier::Enum direction_modifier = DirectionModifier::UTurn) + : type(type), direction_modifier(direction_modifier) { } TurnType::Enum type : 5; DirectionModifier::Enum direction_modifier : 3; // the lane tupel that is used for the turn - LaneTupel lane_tupel; static TurnInstruction INVALID() { return {TurnType::Invalid, DirectionModifier::UTurn}; } @@ -147,18 +145,16 @@ struct TurnInstruction } }; -static_assert(sizeof(TurnInstruction) == 3, "TurnInstruction does not fit three byte"); +static_assert(sizeof(TurnInstruction) == 1, "TurnInstruction does not fit a byte"); inline bool operator!=(const TurnInstruction lhs, const TurnInstruction rhs) { - return lhs.type != rhs.type || lhs.direction_modifier != rhs.direction_modifier || - lhs.lane_tupel != rhs.lane_tupel; + return lhs.type != rhs.type || lhs.direction_modifier != rhs.direction_modifier; } inline bool operator==(const TurnInstruction lhs, const TurnInstruction rhs) { - return lhs.type == rhs.type && lhs.direction_modifier == rhs.direction_modifier && - lhs.lane_tupel == rhs.lane_tupel; + return lhs.type == rhs.type && lhs.direction_modifier == rhs.direction_modifier; } } // namespace guidance diff --git a/include/extractor/guidance/turn_lane_handler.hpp b/include/extractor/guidance/turn_lane_handler.hpp index 3320d6f79..fe675a7d4 100644 --- a/include/extractor/guidance/turn_lane_handler.hpp +++ b/include/extractor/guidance/turn_lane_handler.hpp @@ -2,6 +2,7 @@ #define OSRM_EXTRACTOR_GUIDANCE_TURN_LANE_HANDLER_HPP_ #include "extractor/guidance/intersection.hpp" +#include "extractor/guidance/toolkit.hpp" #include "extractor/guidance/turn_analysis.hpp" #include "extractor/guidance/turn_lane_data.hpp" #include "extractor/query_node.hpp" @@ -13,7 +14,6 @@ #include #include -#include #include #include @@ -38,13 +38,12 @@ class TurnLaneHandler const std::vector &node_info_list, const TurnAnalysis &turn_analysis); - Intersection - assignTurnLanes(const NodeID at, const EdgeID via_edge, Intersection intersection) const; + Intersection assignTurnLanes(const NodeID at, + const EdgeID via_edge, + Intersection intersection, + LaneDataIdMap &id_map) const; private: - using LaneTupel = util::guidance::LaneTupel; - std::unordered_map lane_tupels; - // we need to be able to look at previous intersections to, in some cases, find the correct turn // lanes for a turn const util::NodeBasedDynamicGraph &node_based_graph; @@ -58,7 +57,9 @@ class TurnLaneHandler // in case of a simple intersection, assign the lane entries Intersection simpleMatchTuplesToTurns(Intersection intersection, - const LaneDataVector &lane_data) const; + const LaneDataVector &lane_data, + const LaneStringID lane_string_id, + LaneDataIdMap &id_map) const; // partition lane data into lane data relevant at current turn and at next turn std::pair partitionLaneData( @@ -68,7 +69,8 @@ class TurnLaneHandler // intersection whose turns might be related to this current intersection Intersection handleTurnAtPreviousIntersection(const NodeID at, const EdgeID via_edge, - Intersection intersection) const; + Intersection intersection, + LaneDataIdMap &id_map) const; }; } // namespace lanes diff --git a/include/extractor/guidance/turn_lane_matcher.hpp b/include/extractor/guidance/turn_lane_matcher.hpp index 5b2635339..36bf8cf5b 100644 --- a/include/extractor/guidance/turn_lane_matcher.hpp +++ b/include/extractor/guidance/turn_lane_matcher.hpp @@ -2,12 +2,15 @@ #define OSRM_EXTRACTOR_GUIDANCE_TURN_LANE_MATCHER_HPP_ #include "extractor/guidance/intersection.hpp" +#include "extractor/guidance/toolkit.hpp" #include "extractor/guidance/turn_instruction.hpp" #include "extractor/guidance/turn_lane_data.hpp" #include "util/guidance/turn_lanes.hpp" #include "util/node_based_graph.hpp" +#include + namespace osrm { namespace extractor @@ -44,7 +47,9 @@ bool canMatchTrivially(const Intersection &intersection, const LaneDataVector &l // perform a trivial match on the turn lanes Intersection triviallyMatchLanesToTurns(Intersection intersection, const LaneDataVector &lane_data, - const util::NodeBasedDynamicGraph &node_based_graph); + const util::NodeBasedDynamicGraph &node_based_graph, + const LaneStringID lane_string_id, + LaneDataIdMap &lane_data_to_id); } // namespace lanes } // namespace guidance diff --git a/include/extractor/node_based_edge.hpp b/include/extractor/node_based_edge.hpp index 4e050df85..6c1d212fe 100644 --- a/include/extractor/node_based_edge.hpp +++ b/include/extractor/node_based_edge.hpp @@ -90,8 +90,8 @@ inline NodeBasedEdge::NodeBasedEdge(NodeID source, guidance::RoadClassificationData road_classification) : source(source), target(target), name_id(name_id), weight(weight), forward(forward), backward(backward), roundabout(roundabout), access_restricted(access_restricted), - startpoint(startpoint), is_split(is_split), travel_mode(travel_mode), lane_string_id(lane_string_id), - road_classification(std::move(road_classification)) + startpoint(startpoint), is_split(is_split), travel_mode(travel_mode), + lane_string_id(lane_string_id), road_classification(std::move(road_classification)) { } diff --git a/include/extractor/original_edge_data.hpp b/include/extractor/original_edge_data.hpp index dce4fb74b..558fcb6a0 100644 --- a/include/extractor/original_edge_data.hpp +++ b/include/extractor/original_edge_data.hpp @@ -17,18 +17,19 @@ struct OriginalEdgeData { explicit OriginalEdgeData(NodeID via_node, unsigned name_id, + LaneDataID lane_data_id, guidance::TurnInstruction turn_instruction, EntryClassID entry_classid, TravelMode travel_mode) : via_node(via_node), name_id(name_id), entry_classid(entry_classid), - turn_instruction(turn_instruction), travel_mode(travel_mode) + lane_data_id(lane_data_id), turn_instruction(turn_instruction), travel_mode(travel_mode) { } OriginalEdgeData() : via_node(std::numeric_limits::max()), name_id(std::numeric_limits::max()), entry_classid(INVALID_ENTRY_CLASSID), - turn_instruction(guidance::TurnInstruction::INVALID()), + lane_data_id(INVALID_LANE_DATAID), turn_instruction(guidance::TurnInstruction::INVALID()), travel_mode(TRAVEL_MODE_INACCESSIBLE) { } @@ -36,9 +37,13 @@ struct OriginalEdgeData NodeID via_node; unsigned name_id; EntryClassID entry_classid; + LaneDataID lane_data_id; guidance::TurnInstruction turn_instruction; TravelMode travel_mode; }; + +static_assert(sizeof(OriginalEdgeData) == 16, + "Increasing the size of OriginalEdgeData increases memory consumption"); } } diff --git a/include/storage/shared_datatype.hpp b/include/storage/shared_datatype.hpp index 1be9fffea..33b841d70 100644 --- a/include/storage/shared_datatype.hpp +++ b/include/storage/shared_datatype.hpp @@ -16,6 +16,41 @@ namespace storage // Added at the start and end of each block as sanity check const constexpr char CANARY[4] = {'O', 'S', 'R', 'M'}; +const constexpr char *block_id_to_name[] = {"NAME_OFFSETS", + "NAME_BLOCKS", + "NAME_CHAR_LIST", + "NAME_ID_LIST", + "VIA_NODE_LIST", + "GRAPH_NODE_LIST", + "GRAPH_EDGE_LIST", + "COORDINATE_LIST", + "OSM_NODE_ID_LIST", + "TURN_INSTRUCTION", + "TRAVEL_MODE", + "ENTRY_CLASSID", + "R_SEARCH_TREE", + "GEOMETRIES_INDEX", + "GEOMETRIES_LIST", + "HSGR_CHECKSUM", + "TIMESTAMP", + "FILE_INDEX_PATH", + "CORE_MARKER", + "DATASOURCES_LIST", + "DATASOURCE_NAME_DATA", + "DATASOURCE_NAME_OFFSETS", + "DATASOURCE_NAME_LENGTHS", + "PROPERTIES", + "BEARING_CLASSID", + "BEARING_OFFSETS", + "BEARING_BLOCKS", + "BEARING_VALUES", + "ENTRY_CLASS", + "LANE_DATA_ID", + "TURN_LANE_DATA", + "TURN_STRING_OFFSETS", + "TURN_STRING_BLOCKS", + "TURN_STRING_CHAR_LIST"}; + struct SharedDataLayout { enum BlockID @@ -30,8 +65,8 @@ struct SharedDataLayout COORDINATE_LIST, OSM_NODE_ID_LIST, TURN_INSTRUCTION, - ENTRY_CLASSID, TRAVEL_MODE, + ENTRY_CLASSID, R_SEARCH_TREE, GEOMETRIES_INDEX, GEOMETRIES_LIST, @@ -49,6 +84,11 @@ struct SharedDataLayout BEARING_BLOCKS, BEARING_VALUES, ENTRY_CLASS, + LANE_DATA_ID, + TURN_LANE_DATA, + TURN_STRING_OFFSETS, + TURN_STRING_BLOCKS, + TURN_STRING_CHAR_LIST, NUM_BLOCKS }; @@ -113,11 +153,13 @@ struct SharedDataLayout bool end_canary_alive = std::equal(CANARY, CANARY + sizeof(CANARY), end_canary_ptr); if (!start_canary_alive) { - throw util::exception("Start canary of block corrupted."); + throw util::exception(std::string("Start canary of block corrupted. (") + + block_id_to_name[bid] + ")"); } if (!end_canary_alive) { - throw util::exception("End canary of block corrupted."); + throw util::exception(std::string("End canary of block corrupted. (") + + block_id_to_name[bid] + ")"); } } diff --git a/include/storage/storage_config.hpp b/include/storage/storage_config.hpp index 94e6e01b0..0d877772b 100644 --- a/include/storage/storage_config.hpp +++ b/include/storage/storage_config.hpp @@ -65,6 +65,8 @@ struct StorageConfig final boost::filesystem::path names_data_path; boost::filesystem::path properties_path; boost::filesystem::path intersection_class_path; + boost::filesystem::path turn_lane_data_path; + boost::filesystem::path turn_lane_string_path; }; } } diff --git a/include/util/guidance/turn_lanes.hpp b/include/util/guidance/turn_lanes.hpp index ce466132a..5eec9de44 100644 --- a/include/util/guidance/turn_lanes.hpp +++ b/include/util/guidance/turn_lanes.hpp @@ -65,21 +65,18 @@ class LaneTupel LaneID lanes_in_turn; LaneID first_lane_from_the_right; - friend std::size_t std::hash::operator()(const LaneTupel &) const; + friend std::size_t hash_value(const LaneTupel &tup) + { + std::size_t seed{0}; + boost::hash_combine(seed, tup.lanes_in_turn); + boost::hash_combine(seed, tup.first_lane_from_the_right); + return seed; + } }; +using LaneTupelIdPair = std::pair; } // namespace guidance } // namespace util } // namespace osrm -// make Bearing Class hasbable -namespace std -{ -inline size_t hash<::osrm::util::guidance::LaneTupel>:: -operator()(const ::osrm::util::guidance::LaneTupel &lane_tupel) const -{ - return boost::hash_value(*reinterpret_cast(&lane_tupel)); -} -} // namespace std - #endif /* OSRM_UTIL_GUIDANCE_TURN_LANES_HPP */ diff --git a/include/util/node_based_graph.hpp b/include/util/node_based_graph.hpp index 41882201c..cfdfc77d9 100644 --- a/include/util/node_based_graph.hpp +++ b/include/util/node_based_graph.hpp @@ -20,7 +20,8 @@ struct NodeBasedEdgeData NodeBasedEdgeData() : distance(INVALID_EDGE_WEIGHT), edge_id(SPECIAL_NODEID), name_id(std::numeric_limits::max()), access_restricted(false), reversed(false), - roundabout(false), travel_mode(TRAVEL_MODE_INACCESSIBLE), lane_string_id(INVALID_LANE_STRINGID) + roundabout(false), travel_mode(TRAVEL_MODE_INACCESSIBLE), + lane_string_id(INVALID_LANE_STRINGID) { } diff --git a/include/util/typedefs.hpp b/include/util/typedefs.hpp index ef4c9aedf..7893f7553 100644 --- a/include/util/typedefs.hpp +++ b/include/util/typedefs.hpp @@ -60,9 +60,11 @@ using NameID = std::uint32_t; using EdgeWeight = std::int32_t; using LaneStringID = std::uint16_t; +static const LaneStringID INVALID_LANE_STRINGID = std::numeric_limits::max(); using LaneID = std::uint8_t; static const LaneID INVALID_LANEID = std::numeric_limits::max(); -static const LaneStringID INVALID_LANE_STRINGID = std::numeric_limits::max(); +using LaneDataID = std::uint16_t; +static const LaneDataID INVALID_LANE_DATAID = std::numeric_limits::max(); using BearingClassID = std::uint32_t; static const BearingClassID INVALID_BEARING_CLASSID = std::numeric_limits::max(); diff --git a/src/engine/api/json_factory.cpp b/src/engine/api/json_factory.cpp index cd1b3d874..1a5fe31fe 100644 --- a/src/engine/api/json_factory.cpp +++ b/src/engine/api/json_factory.cpp @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -63,7 +64,7 @@ inline bool isValidModifier(const guidance::StepManeuver maneuver) inline bool hasValidLanes(const guidance::StepManeuver maneuver) { - return maneuver.instruction.lane_tupel.lanes_in_turn > 0; + return maneuver.lanes.lanes_in_turn > 0; } std::string instructionTypeToString(const TurnType::Enum type) @@ -71,12 +72,31 @@ std::string instructionTypeToString(const TurnType::Enum type) return turn_type_names[static_cast(type)]; } -util::json::Array laneArrayFromLaneTupe(const util::guidance::LaneTupel lane_tupel) +util::json::Array lanesFromManeuver(const guidance::StepManeuver &maneuver) { - BOOST_ASSERT(lane_tupel.lanes_in_turn >= 1); + BOOST_ASSERT(maneuver.lanes.lanes_in_turn >= 1); util::json::Array result; - for (LaneID i = 0; i < lane_tupel.lanes_in_turn; ++i) - result.values.push_back(lane_tupel.first_lane_from_the_right + i); + LaneID lane_id = 0; + typedef boost::tokenizer> tokenizer; + boost::char_separator sep("|", "", boost::keep_empty_tokens); + tokenizer tokens(maneuver.turn_lane_string, sep); + + lane_id = std::distance(tokens.begin(), tokens.end()); + + for (auto iter = tokens.begin(); iter != tokens.end(); ++iter) + { + --lane_id; + util::json::Object lane; + lane.values["marked"] = (iter->empty() ? "none" : *iter); + if (lane_id >= maneuver.lanes.first_lane_from_the_right && + lane_id < maneuver.lanes.first_lane_from_the_right + maneuver.lanes.lanes_in_turn) + lane.values["take"] = util::json::True(); + else + lane.values["take"] = util::json::False(); + + result.values.push_back(lane); + } + return result; } @@ -162,8 +182,7 @@ util::json::Object makeStepManeuver(const guidance::StepManeuver &maneuver) detail::instructionModifierToString(maneuver.instruction.direction_modifier); if (detail::hasValidLanes(maneuver)) - step_maneuver.values["lanes"] = - detail::laneArrayFromLaneTupe(maneuver.instruction.lane_tupel); + step_maneuver.values["lanes"] = detail::lanesFromManeuver(maneuver); step_maneuver.values["location"] = detail::coordinateToLonLat(maneuver.location); step_maneuver.values["bearing_before"] = std::round(maneuver.bearing_before); diff --git a/src/engine/guidance/lane_processing.cpp b/src/engine/guidance/lane_processing.cpp new file mode 100644 index 000000000..b84113bf0 --- /dev/null +++ b/src/engine/guidance/lane_processing.cpp @@ -0,0 +1,111 @@ +#include "util/for_each_pair.hpp" +#include "util/group_by.hpp" +#include "util/guidance/toolkit.hpp" + +#include "extractor/guidance/turn_instruction.hpp" + +#include + +using TurnInstruction = osrm::extractor::guidance::TurnInstruction; +namespace TurnType = osrm::extractor::guidance::TurnType; +namespace DirectionModifier = osrm::extractor::guidance::DirectionModifier; + +using osrm::util::guidance::isLeftTurn; +using osrm::util::guidance::isRightTurn; + +namespace osrm +{ +namespace engine +{ +namespace guidance +{ + +std::vector anticipateLaneChange(std::vector 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 = [MIN_DURATION_NEEDED_FOR_LANE_CHANGE](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; + + std::vector 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 rev_first{turns.second}; + const std::reverse_iterator 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.maneuver.lanes; + + // Constrain the previous turn's lanes + auto &previous_inst = previous.maneuver.instruction; + auto &previous_lanes = previous.maneuver.lanes; + // 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; +} + +} // namespace guidance +} // namespace engine +} // namespace osrm diff --git a/src/engine/guidance/post_processing.cpp b/src/engine/guidance/post_processing.cpp index 48c9065a2..2dcadbe69 100644 --- a/src/engine/guidance/post_processing.cpp +++ b/src/engine/guidance/post_processing.cpp @@ -4,9 +4,8 @@ #include "engine/guidance/assemble_steps.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/turn_lanes.hpp" #include #include @@ -15,7 +14,6 @@ #include #include #include -#include #include #include @@ -24,8 +22,6 @@ namespace TurnType = osrm::extractor::guidance::TurnType; namespace DirectionModifier = osrm::extractor::guidance::DirectionModifier; using osrm::util::guidance::angularDeviation; using osrm::util::guidance::getTurnDirection; -using osrm::util::guidance::isLeftTurn; -using osrm::util::guidance::isRightTurn; namespace osrm { @@ -867,6 +863,8 @@ void trimShortSegments(std::vector &steps, LegGeometry &geometry) designated_depart.maneuver.instruction = TurnInstruction::NO_TURN(); // we need to make this conform with the intersection format for the first intersection auto &first_intersection = designated_depart.intersections.front(); + designated_depart.maneuver.lanes = util::guidance::LaneTupel(); + designated_depart.maneuver.turn_lane_string = ""; first_intersection.bearings = {first_intersection.bearings[first_intersection.out]}; first_intersection.entry = {true}; first_intersection.in = Intersection::NO_INDEX; @@ -933,6 +931,8 @@ void trimShortSegments(std::vector &steps, LegGeometry &geometry) next_to_last_step.maneuver.waypoint_type = WaypointType::Arrive; next_to_last_step.maneuver.instruction = TurnInstruction::NO_TURN(); next_to_last_step.maneuver.bearing_after = 0; + next_to_last_step.maneuver.lanes = util::guidance::LaneTupel(); + next_to_last_step.maneuver.turn_lane_string = ""; BOOST_ASSERT(next_to_last_step.intersections.size() == 1); auto &last_intersection = next_to_last_step.intersections.back(); last_intersection.bearings = {last_intersection.bearings[last_intersection.in]}; @@ -1038,94 +1038,6 @@ std::vector assignRelativeLocations(std::vector steps, return steps; } -std::vector anticipateLaneChange(std::vector 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; - - std::vector 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 rev_first{turns.second}; - const std::reverse_iterator 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 &steps) { // The geometry uses an adjacency array-like structure for representation. diff --git a/src/extractor/edge_based_graph_factory.cpp b/src/extractor/edge_based_graph_factory.cpp index 52ce83050..da1a7b1ff 100644 --- a/src/extractor/edge_based_graph_factory.cpp +++ b/src/extractor/edge_based_graph_factory.cpp @@ -1,5 +1,5 @@ -#include "extractor/edge_based_edge.hpp" #include "extractor/edge_based_graph_factory.hpp" +#include "extractor/edge_based_edge.hpp" #include "util/coordinate.hpp" #include "util/coordinate_calculation.hpp" #include "util/exception.hpp" @@ -182,6 +182,7 @@ void EdgeBasedGraphFactory::FlushVectorToStream( } void EdgeBasedGraphFactory::Run(const std::string &original_edge_data_filename, + const std::string &turn_lane_data_filename, lua_State *lua_state, const std::string &edge_segment_lookup_filename, const std::string &edge_penalty_filename, @@ -198,6 +199,7 @@ void EdgeBasedGraphFactory::Run(const std::string &original_edge_data_filename, TIMER_START(generate_edges); GenerateEdgeExpandedEdges(original_edge_data_filename, + turn_lane_data_filename, lua_state, edge_segment_lookup_filename, edge_penalty_filename, @@ -296,6 +298,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedNodes() /// Actually it also generates OriginalEdgeData and serializes them... void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( const std::string &original_edge_data_filename, + const std::string &turn_lane_data_filename, lua_State *lua_state, const std::string &edge_segment_lookup_filename, const std::string &edge_fixed_penalties_filename, @@ -348,6 +351,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( bearing_class_by_node_based_node.resize(m_node_based_graph->GetNumberOfNodes(), std::numeric_limits::max()); + guidance::LaneDataIdMap lane_data_map; for (const auto node_u : util::irange(0u, m_node_based_graph->GetNumberOfNodes())) { progress.PrintStatus(node_u); @@ -364,8 +368,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( intersection = turn_analysis.assignTurnTypes(node_u, edge_from_u, std::move(intersection)); - intersection = - turn_lane_handler.assignTurnLanes(node_u, edge_from_u, std::move(intersection)); + intersection = turn_lane_handler.assignTurnLanes( + node_u, edge_from_u, std::move(intersection), lane_data_map); const auto possible_turns = turn_analysis.transformIntersectionIntoTurns(intersection); // the entry class depends on the turn, so we have to classify the interesction for @@ -437,6 +441,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( original_edge_data_vector.emplace_back( m_compressed_edge_container.GetPositionForID(edge_from_u), edge_data1.name_id, + turn.lane_data_id, turn_instruction, entry_class_id, edge_data1.travel_mode); @@ -541,6 +546,22 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( util::SimpleLogger().Write() << "Created " << entry_class_hash.size() << " entry classes and " << bearing_class_hash.size() << " Bearing Classes"; + util::SimpleLogger().Write() << "Writing Turn Lane Data to File..."; + std::ofstream turn_lane_data_file(turn_lane_data_filename.c_str(), std::ios::binary); + std::vector lane_data(lane_data_map.size()); + // extract lane data sorted by ID + for (auto itr : lane_data_map) + lane_data[itr.second] = itr.first; + + std::uint64_t size = lane_data.size(); + turn_lane_data_file.write(reinterpret_cast(&size), sizeof(size)); + + if (!lane_data.empty()) + turn_lane_data_file.write(reinterpret_cast(&lane_data[0]), + sizeof(util::guidance::LaneTupelIdPair) * lane_data.size()); + + util::SimpleLogger().Write() << "done."; + FlushVectorToStream(edge_data_file, original_edge_data_vector); // Finally jump back to the empty space at the beginning and write length prefix diff --git a/src/extractor/extraction_containers.cpp b/src/extractor/extraction_containers.cpp index 76fc36c1d..2f945c1d3 100644 --- a/src/extractor/extraction_containers.cpp +++ b/src/extractor/extraction_containers.cpp @@ -51,8 +51,6 @@ ExtractionContainers::ExtractionContainers() name_lengths.push_back(0); name_lengths.push_back(0); name_lengths.push_back(0); - name_lengths.push_back(0); - name_lengths.push_back(0); turn_lane_lengths.push_back(0); } @@ -87,8 +85,8 @@ void ExtractionContainers::PrepareData(const std::string &output_file_name, PrepareRestrictions(); WriteRestrictions(restrictions_file_name); - WriteCharData(name_file_name,name_lengths,name_char_data); - WriteCharData(turn_lane_file_name,turn_lane_lengths,turn_lane_char_data); + WriteCharData(name_file_name, name_lengths, name_char_data); + WriteCharData(turn_lane_file_name, turn_lane_lengths, turn_lane_char_data); } catch (const std::exception &e) { diff --git a/src/extractor/extractor.cpp b/src/extractor/extractor.cpp index 7ff1c8e88..3861b521c 100644 --- a/src/extractor/extractor.cpp +++ b/src/extractor/extractor.cpp @@ -239,7 +239,7 @@ int Extractor::run() extraction_containers.PrepareData(config.output_file_name, config.restriction_file_name, config.names_file_name, - config.turn_lane_file_name, + config.turn_lane_strings_file_name, main_context.state); WriteProfileProperties(config.profile_properties_output_path, main_context.properties); @@ -504,7 +504,7 @@ Extractor::BuildEdgeExpandedGraph(lua_State *lua_state, compressed_edge_container.SerializeInternalVector(config.geometry_output_path); util::NameTable name_table(config.names_file_name); - util::NameTable turn_lanes(config.turn_lane_file_name); + util::NameTable turn_lanes(config.turn_lane_strings_file_name); EdgeBasedGraphFactory edge_based_graph_factory( node_based_graph, @@ -518,6 +518,7 @@ Extractor::BuildEdgeExpandedGraph(lua_State *lua_state, turn_lanes); edge_based_graph_factory.Run(config.edge_output_path, + config.turn_lane_data_file_name, lua_state, config.edge_segment_lookup_path, config.edge_penalty_path, diff --git a/src/extractor/extractor_callbacks.cpp b/src/extractor/extractor_callbacks.cpp index 70af37687..9d26e7266 100644 --- a/src/extractor/extractor_callbacks.cpp +++ b/src/extractor/extractor_callbacks.cpp @@ -1,7 +1,7 @@ +#include "extractor/extractor_callbacks.hpp" #include "extractor/extraction_containers.hpp" #include "extractor/extraction_node.hpp" #include "extractor/extraction_way.hpp" -#include "extractor/extractor_callbacks.hpp" #include "extractor/external_memory_node.hpp" #include "extractor/restriction.hpp" @@ -149,9 +149,17 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti // Otherwise fetches the id based on the name and returns it without insertion. const constexpr auto MAX_STRING_LENGTH = 255u; - const auto requestId = [this,MAX_STRING_LENGTH](const std::string turn_lane_string) { - if( turn_lane_string == "" ) + const auto requestId = [this, MAX_STRING_LENGTH](const std::string &turn_lane_string_) { + if (turn_lane_string_ == "") return INVALID_LANE_STRINGID; + + // requires https://github.com/cucumber/cucumber-js/issues/417 + // remove this handling when the issue is contained + std::string turn_lane_string = turn_lane_string_; + for (auto &val : turn_lane_string) + if (val == '&') + val = '|'; + const auto &lane_map_iterator = lane_map.find(turn_lane_string); if (lane_map.end() == lane_map_iterator) { diff --git a/src/extractor/graph_compressor.cpp b/src/extractor/graph_compressor.cpp index 1d3606ed6..02c1841f6 100644 --- a/src/extractor/graph_compressor.cpp +++ b/src/extractor/graph_compressor.cpp @@ -113,7 +113,7 @@ void GraphCompressor::Compress(const std::unordered_set &barrier_nodes, // traffic signals in the `traffic_lights` list, which EdgeData // doesn't have access to. const bool has_node_penalty = traffic_lights.find(node_v) != traffic_lights.end(); - if( has_node_penalty ) + if (has_node_penalty) continue; // Get distances before graph is modified @@ -168,10 +168,10 @@ void GraphCompressor::Compress(const std::unordered_set &barrier_nodes, return front; return back; }; - graph.GetEdgeData(forward_e1).lane_string_id = - selectLaneID(graph.GetEdgeData(forward_e1).lane_string_id, fwd_edge_data2.lane_string_id); - graph.GetEdgeData(reverse_e1).lane_string_id = - selectLaneID(graph.GetEdgeData(reverse_e1).lane_string_id, rev_edge_data2.lane_string_id); + graph.GetEdgeData(forward_e1).lane_string_id = selectLaneID( + graph.GetEdgeData(forward_e1).lane_string_id, fwd_edge_data2.lane_string_id); + graph.GetEdgeData(reverse_e1).lane_string_id = selectLaneID( + graph.GetEdgeData(reverse_e1).lane_string_id, rev_edge_data2.lane_string_id); // remove e2's (if bidir, otherwise only one) graph.DeleteEdge(node_v, forward_e2); diff --git a/src/extractor/guidance/intersection.cpp b/src/extractor/guidance/intersection.cpp index 3d48015d7..350c1b85c 100644 --- a/src/extractor/guidance/intersection.cpp +++ b/src/extractor/guidance/intersection.cpp @@ -22,12 +22,9 @@ std::string toString(const ConnectedRoad &road) result += " angle: "; result += std::to_string(road.turn.angle); result += " instruction: "; - result += - std::to_string(static_cast(road.turn.instruction.type)) + " " + - std::to_string(static_cast(road.turn.instruction.direction_modifier)) + " " + - std::to_string(static_cast(road.turn.instruction.lane_tupel.lanes_in_turn)) + - " " + std::to_string(static_cast( - road.turn.instruction.lane_tupel.first_lane_from_the_right)); + result += std::to_string(static_cast(road.turn.instruction.type)) + " " + + std::to_string(static_cast(road.turn.instruction.direction_modifier)) + + " " + std::to_string(static_cast(road.turn.lane_data_id)); return result; } diff --git a/src/extractor/guidance/intersection_generator.cpp b/src/extractor/guidance/intersection_generator.cpp index 7c73c519a..bd655a502 100644 --- a/src/extractor/guidance/intersection_generator.cpp +++ b/src/extractor/guidance/intersection_generator.cpp @@ -1,5 +1,5 @@ -#include "extractor/guidance/constants.hpp" #include "extractor/guidance/intersection_generator.hpp" +#include "extractor/guidance/constants.hpp" #include "extractor/guidance/toolkit.hpp" #include @@ -114,9 +114,12 @@ Intersection IntersectionGenerator::getConnectedRoads(const NodeID from_node, has_uturn_edge = true; } - intersection.push_back(ConnectedRoad( - TurnOperation{onto_edge, angle, {TurnType::Invalid, DirectionModifier::UTurn}}, - turn_is_valid)); + intersection.push_back( + ConnectedRoad(TurnOperation{onto_edge, + angle, + {TurnType::Invalid, DirectionModifier::UTurn}, + INVALID_LANE_DATAID}, + turn_is_valid)); } // We hit the case of a street leading into nothing-ness. Since the code here assumes that this @@ -124,7 +127,9 @@ Intersection IntersectionGenerator::getConnectedRoads(const NodeID from_node, if (!has_uturn_edge) { intersection.push_back( - {TurnOperation{via_eid, 0., {TurnType::Invalid, DirectionModifier::UTurn}}, false}); + {TurnOperation{ + via_eid, 0., {TurnType::Invalid, DirectionModifier::UTurn}, INVALID_LANE_DATAID}, + false}); } const auto ByAngle = [](const ConnectedRoad &first, const ConnectedRoad second) { diff --git a/src/extractor/guidance/roundabout_handler.cpp b/src/extractor/guidance/roundabout_handler.cpp index 602326339..3a47d6476 100644 --- a/src/extractor/guidance/roundabout_handler.cpp +++ b/src/extractor/guidance/roundabout_handler.cpp @@ -373,11 +373,12 @@ Intersection RoundaboutHandler::handleRoundabouts(const RoundaboutType roundabou if (1 == node_based_graph.GetDirectedOutDegree(node_v)) { // No turn possible. - if( intersection.size() == 2 ) + if (intersection.size() == 2) turn.instruction = TurnInstruction::NO_TURN(); else { - turn.instruction.type = TurnType::Suppressed; //make sure to report intersection + turn.instruction.type = + TurnType::Suppressed; // make sure to report intersection turn.instruction.direction_modifier = getTurnDirection(turn.angle); } } diff --git a/src/extractor/guidance/turn_discovery.cpp b/src/extractor/guidance/turn_discovery.cpp index 4f71ae135..0bd272844 100644 --- a/src/extractor/guidance/turn_discovery.cpp +++ b/src/extractor/guidance/turn_discovery.cpp @@ -1,5 +1,5 @@ -#include "extractor/guidance/constants.hpp" #include "extractor/guidance/turn_discovery.hpp" +#include "extractor/guidance/constants.hpp" namespace osrm { diff --git a/src/extractor/guidance/turn_lane_augmentation.cpp b/src/extractor/guidance/turn_lane_augmentation.cpp index c1a82f2ee..755143370 100644 --- a/src/extractor/guidance/turn_lane_augmentation.cpp +++ b/src/extractor/guidance/turn_lane_augmentation.cpp @@ -2,9 +2,9 @@ #include "util/simple_logger.hpp" #include +#include #include #include -#include namespace osrm { @@ -171,7 +171,6 @@ LaneDataVector handleRenamingSituations(const std::size_t none_index, has_left |= modifier == DirectionModifier::SharpLeft; } - // find missing tag and augment neighboring, if possible if (none_index == 0) { diff --git a/src/extractor/guidance/turn_lane_data.cpp b/src/extractor/guidance/turn_lane_data.cpp index 3aca1f8d7..f407d4e5c 100644 --- a/src/extractor/guidance/turn_lane_data.cpp +++ b/src/extractor/guidance/turn_lane_data.cpp @@ -52,8 +52,7 @@ LaneDataVector laneDataFromString(std::string turn_lane_string) // count the number of lanes const auto num_lanes = [](const std::string &turn_lane_string) { return boost::numeric_cast( - std::count(turn_lane_string.begin(), turn_lane_string.end(), '|') + 1 + - std::count(turn_lane_string.begin(), turn_lane_string.end(), '&')); + std::count(turn_lane_string.begin(), turn_lane_string.end(), '|') + 1); }(turn_lane_string); const auto getNextTag = [](std::string &string, const char *separators) { @@ -103,7 +102,7 @@ LaneDataVector laneDataFromString(std::string turn_lane_string) // FIXME this is a cucumber workaround, since escaping does not work properly in // cucumber.js (see https://github.com/cucumber/cucumber-js/issues/417). Needs to be // changed to "|" only, when the bug is fixed - auto lane = getNextTag(turn_lane_string, "|&"); + auto lane = getNextTag(turn_lane_string, "|"); setLaneData(lane_map, lane, lane_nr); ++lane_nr; } while (lane_nr < num_lanes); @@ -135,8 +134,9 @@ LaneDataVector::const_iterator findTag(const std::string &tag, const LaneDataVec }); } -bool hasTag(const std::string &tag, const LaneDataVector &data){ - return findTag(tag,data) != data.cend(); +bool hasTag(const std::string &tag, const LaneDataVector &data) +{ + return findTag(tag, data) != data.cend(); } } // namespace lanes diff --git a/src/extractor/guidance/turn_lane_handler.cpp b/src/extractor/guidance/turn_lane_handler.cpp index 373f8b48d..f42b53224 100644 --- a/src/extractor/guidance/turn_lane_handler.cpp +++ b/src/extractor/guidance/turn_lane_handler.cpp @@ -1,8 +1,8 @@ +#include "extractor/guidance/turn_lane_handler.hpp" #include "extractor/guidance/constants.hpp" #include "extractor/guidance/turn_discovery.hpp" -#include "extractor/guidance/turn_lane_handler.hpp" -#include "extractor/guidance/turn_lane_matcher.hpp" #include "extractor/guidance/turn_lane_augmentation.hpp" +#include "extractor/guidance/turn_lane_matcher.hpp" #include "util/simple_logger.hpp" #include "util/typedefs.hpp" @@ -40,7 +40,7 @@ TurnLaneHandler::TurnLaneHandler(const util::NodeBasedDynamicGraph &node_based_g } /* - Turn lanes are given in the form of strings that closely correspond to the direction modifiers + Turn lanes are given in the form of strings that closely correspond to the direction modifiers we use for our turn types. However, we still cannot simply perform a 1:1 assignment. This function parses the turn_lane_strings of a format that describes an intersection as: @@ -58,11 +58,9 @@ TurnLaneHandler::TurnLaneHandler(const util::NodeBasedDynamicGraph &node_based_g */ Intersection TurnLaneHandler::assignTurnLanes(const NodeID at, const EdgeID via_edge, - Intersection intersection) const + Intersection intersection, + LaneDataIdMap &id_map) const { - // initialize to invalid - for (auto &road : intersection) - road.turn.instruction.lane_tupel = {0, INVALID_LANEID}; const auto &data = node_based_graph.GetEdgeData(via_edge); const auto turn_lane_string = data.lane_string_id != INVALID_LANE_STRINGID ? turn_lane_strings.GetNameForID(data.lane_string_id) @@ -89,17 +87,15 @@ Intersection TurnLaneHandler::assignTurnLanes(const NodeID at, const std::size_t possible_entries = getNumberOfTurns(intersection); // merge does not justify an instruction - const bool has_merge_lane = (hasTag("merge_to_left", lane_data) || - hasTag("merge_to_right", lane_data)); + const bool has_merge_lane = + (hasTag("merge_to_left", lane_data) || hasTag("merge_to_right", lane_data)); // Dead end streets that don't have any left-tag. This can happen due to the fallbacks for // broken data/barriers. const bool has_non_usable_u_turn = (intersection[0].entry_allowed && !hasTag("none", lane_data) && - !hasTag("left", lane_data) && - !hasTag("sharp_left", lane_data) && - !hasTag("reverse", lane_data) && - lane_data.size() + 1 == possible_entries); + !hasTag("left", lane_data) && !hasTag("sharp_left", lane_data) && + !hasTag("reverse", lane_data) && lane_data.size() + 1 == possible_entries); if (has_merge_lane || has_non_usable_u_turn) return std::move(intersection); @@ -118,7 +114,8 @@ Intersection TurnLaneHandler::assignTurnLanes(const NodeID at, if (is_simple) { lane_data = handleNoneValueAtSimpleTurn(std::move(lane_data), intersection); - return simpleMatchTuplesToTurns(std::move(intersection), lane_data); + return simpleMatchTuplesToTurns( + std::move(intersection), lane_data, data.lane_string_id, id_map); } // if the intersection is not simple but we have lane data, we check for intersections with // middle islands. We have two cases. The first one is providing lane data on the current @@ -138,7 +135,8 @@ Intersection TurnLaneHandler::assignTurnLanes(const NodeID at, isSimpleIntersection(lane_data, intersection)) { lane_data = handleNoneValueAtSimpleTurn(std::move(lane_data), intersection); - return simpleMatchTuplesToTurns(std::move(intersection), lane_data); + return simpleMatchTuplesToTurns( + std::move(intersection), lane_data, data.lane_string_id, id_map); } } } @@ -148,7 +146,7 @@ Intersection TurnLaneHandler::assignTurnLanes(const NodeID at, { // acquire the lane data of a previous segment and, if possible, use it for the current // intersection. - return handleTurnAtPreviousIntersection(at, via_edge, std::move(intersection)); + return handleTurnAtPreviousIntersection(at, via_edge, std::move(intersection), id_map); } return std::move(intersection); @@ -158,7 +156,8 @@ Intersection TurnLaneHandler::assignTurnLanes(const NodeID at, // actually take the turn, we need to look back to the edge we drove onto the intersection with. Intersection TurnLaneHandler::handleTurnAtPreviousIntersection(const NodeID at, const EdgeID via_edge, - Intersection intersection) const + Intersection intersection, + LaneDataIdMap &id_map) const { NodeID previous_node = SPECIAL_NODEID; Intersection previous_intersection; @@ -176,6 +175,7 @@ Intersection TurnLaneHandler::handleTurnAtPreviousIntersection(const NodeID at, previous_id, previous_intersection)) return ""; + BOOST_ASSERT(previous_id != SPECIAL_EDGEID); const auto &previous_data = node_based_graph.GetEdgeData(previous_id); auto previous_string = previous_data.lane_string_id != INVALID_LANE_STRINGID @@ -204,11 +204,13 @@ Intersection TurnLaneHandler::handleTurnAtPreviousIntersection(const NodeID at, if (lane_data.empty()) return std::move(intersection); + const auto &previous_data = node_based_graph.GetEdgeData(previous_id); const auto is_simple = isSimpleIntersection(lane_data, intersection); if (is_simple) { lane_data = handleNoneValueAtSimpleTurn(std::move(lane_data), intersection); - return simpleMatchTuplesToTurns(std::move(intersection), lane_data); + return simpleMatchTuplesToTurns( + std::move(intersection), lane_data, previous_data.lane_string_id, id_map); } else { @@ -227,14 +229,14 @@ Intersection TurnLaneHandler::handleTurnAtPreviousIntersection(const NodeID at, isSimpleIntersection(lane_data, intersection)) { lane_data = handleNoneValueAtSimpleTurn(std::move(lane_data), intersection); - return simpleMatchTuplesToTurns(std::move(intersection), lane_data); + return simpleMatchTuplesToTurns( + std::move(intersection), lane_data, previous_data.lane_string_id, id_map); } } } return std::move(intersection); } - /* A simple intersection does not depend on the next intersection coming up. This is important * for turn lanes, since traffic signals and/or segregated a intersection can influence the * interpretation of turn-lanes at a given turn. @@ -296,7 +298,7 @@ bool TurnLaneHandler::isSimpleIntersection(const LaneDataVector &lane_data, } if (num_turns > lane_data.size() && intersection[0].entry_allowed && - !( hasTag("reverse", lane_data) || + !(hasTag("reverse", lane_data) || (lane_data.back().tag != "left" && lane_data.back().tag != "sharp_left"))) { return false; @@ -417,7 +419,7 @@ std::pair TurnLaneHandler::partitionLaneData( return {turn_lane_data, {}}; } - std::size_t none_index = std::distance(turn_lane_data.begin(),findTag("none", turn_lane_data)); + std::size_t none_index = std::distance(turn_lane_data.begin(), findTag("none", turn_lane_data)); // if the turn lanes are pull forward, we might have to add an additional straight tag // did we find something that matches against the straightmost road? @@ -486,7 +488,9 @@ std::pair TurnLaneHandler::partitionLaneData( } Intersection TurnLaneHandler::simpleMatchTuplesToTurns(Intersection intersection, - const LaneDataVector &lane_data) const + const LaneDataVector &lane_data, + const LaneStringID lane_string_id, + LaneDataIdMap &id_map) const { if (lane_data.empty() || !canMatchTrivially(intersection, lane_data)) return std::move(intersection); @@ -496,7 +500,8 @@ Intersection TurnLaneHandler::simpleMatchTuplesToTurns(Intersection intersection return boost::starts_with(data.tag, "merge"); }) == 0); - return triviallyMatchLanesToTurns(std::move(intersection), lane_data, node_based_graph); + return triviallyMatchLanesToTurns( + std::move(intersection), lane_data, node_based_graph, lane_string_id, id_map); } } // namespace lanes diff --git a/src/extractor/guidance/turn_lane_matcher.cpp b/src/extractor/guidance/turn_lane_matcher.cpp index 27ac6a7ff..906edaddb 100644 --- a/src/extractor/guidance/turn_lane_matcher.cpp +++ b/src/extractor/guidance/turn_lane_matcher.cpp @@ -1,8 +1,11 @@ -#include "extractor/guidance/toolkit.hpp" #include "extractor/guidance/turn_lane_matcher.hpp" +#include "extractor/guidance/toolkit.hpp" #include "util/guidance/toolkit.hpp" #include +#include + +#include namespace osrm { @@ -169,9 +172,27 @@ bool canMatchTrivially(const Intersection &intersection, const LaneDataVector &l Intersection triviallyMatchLanesToTurns(Intersection intersection, const LaneDataVector &lane_data, - const util::NodeBasedDynamicGraph &node_based_graph) + const util::NodeBasedDynamicGraph &node_based_graph, + const LaneStringID lane_string_id, + LaneDataIdMap &lane_data_to_id) { std::size_t road_index = 1, lane = 0; + + const auto matchRoad = [&](ConnectedRoad &road, const TurnLaneData &data) { + LaneTupelIdPair key{{LaneID(data.to - data.from + 1), data.from}, lane_string_id}; + + auto lane_data_id = boost::numeric_cast(lane_data_to_id.size()); + const auto it = lane_data_to_id.find(key); + + if (it == lane_data_to_id.end()) + lane_data_to_id.insert({key, lane_data_id}); + else + lane_data_id = it->second; + + // set lane id instead after the switch: + road.turn.lane_data_id = lane_data_id; + }; + for (; road_index < intersection.size() && lane < lane_data.size(); ++road_index) { if (intersection[road_index].entry_allowed) @@ -185,8 +206,7 @@ Intersection triviallyMatchLanesToTurns(Intersection intersection, if (TurnType::Suppressed == intersection[road_index].turn.instruction.type) intersection[road_index].turn.instruction.type = TurnType::UseLane; - intersection[road_index].turn.instruction.lane_tupel = { - LaneID(lane_data[lane].to - lane_data[lane].from + 1), lane_data[lane].from}; + matchRoad(intersection[road_index], lane_data[lane]); ++lane; } } @@ -209,8 +229,8 @@ Intersection triviallyMatchLanesToTurns(Intersection intersection, intersection[u_turn].entry_allowed = true; intersection[u_turn].turn.instruction.type = TurnType::Turn; intersection[u_turn].turn.instruction.direction_modifier = DirectionModifier::UTurn; - intersection[u_turn].turn.instruction.lane_tupel = { - LaneID(lane_data.back().to - lane_data.back().from + 1), lane_data.back().from}; + + matchRoad(intersection[u_turn], lane_data.back()); } return std::move(intersection); } diff --git a/src/storage/storage.cpp b/src/storage/storage.cpp index 980cd333d..aa0972317 100644 --- a/src/storage/storage.cpp +++ b/src/storage/storage.cpp @@ -147,6 +147,26 @@ int Storage::Run() name_stream.read((char *)&number_of_chars, sizeof(unsigned)); shared_layout_ptr->SetBlockSize(SharedDataLayout::NAME_CHAR_LIST, number_of_chars); + boost::filesystem::ifstream turn_string_stream(config.turn_lane_string_path, std::ios::binary); + if (!turn_string_stream) + { + throw util::exception("Could not open " + config.turn_lane_string_path.string() + + " for reading."); + } + + unsigned turn_string_blocks = 0; + turn_string_stream.read((char *)&turn_string_blocks, sizeof(unsigned)); + shared_layout_ptr->SetBlockSize(SharedDataLayout::TURN_STRING_OFFSETS, + turn_string_blocks); + shared_layout_ptr->SetBlockSize::BlockT>( + SharedDataLayout::TURN_STRING_BLOCKS, turn_string_blocks); + BOOST_ASSERT_MSG(0 != turn_string_blocks, "turn string file broken"); + + unsigned number_of_turn_string_chars = 0; + turn_string_stream.read((char *)&number_of_turn_string_chars, sizeof(unsigned)); + shared_layout_ptr->SetBlockSize(SharedDataLayout::TURN_STRING_CHAR_LIST, + number_of_turn_string_chars); + // Loading information for original edges boost::filesystem::ifstream edges_input_stream(config.edges_data_path, std::ios::binary); if (!edges_input_stream) @@ -166,6 +186,8 @@ int Storage::Run() number_of_original_edges); shared_layout_ptr->SetBlockSize( SharedDataLayout::TURN_INSTRUCTION, number_of_original_edges); + shared_layout_ptr->SetBlockSize(SharedDataLayout::LANE_DATA_ID, + number_of_original_edges); shared_layout_ptr->SetBlockSize(SharedDataLayout::ENTRY_CLASSID, number_of_original_edges); @@ -368,6 +390,14 @@ int Storage::Run() sizeof(bearing_class_table[0]) * num_bearings); shared_layout_ptr->SetBlockSize(SharedDataLayout::BEARING_VALUES, num_bearings); + + // Loading turn lane data + boost::filesystem::ifstream lane_data_stream(config.turn_lane_data_path, std::ios::binary); + std::uint64_t lane_tupel_count = 0; + lane_data_stream.read(reinterpret_cast(&lane_tupel_count), sizeof(lane_tupel_count)); + shared_layout_ptr->SetBlockSize( + SharedDataLayout::TURN_LANE_DATA, lane_tupel_count); + if (!static_cast(intersection_stream)) throw util::exception("Failed to read bearing values from " + config.intersection_class_path.string()); @@ -436,9 +466,54 @@ int Storage::Run() name_stream.read(name_char_ptr, shared_layout_ptr->GetBlockSize(SharedDataLayout::NAME_CHAR_LIST)); } - name_stream.close(); + // Loading turn lane strings + unsigned *turn_string_offsets_ptr = shared_layout_ptr->GetBlockPtr( + shared_memory_ptr, SharedDataLayout::TURN_STRING_OFFSETS); + if (shared_layout_ptr->GetBlockSize(SharedDataLayout::TURN_STRING_OFFSETS) > 0) + { + turn_string_stream.read( + (char *)turn_string_offsets_ptr, + shared_layout_ptr->GetBlockSize(SharedDataLayout::TURN_STRING_OFFSETS)); + } + + // make sure do write canary... + auto *turn_lane_data_ptr = + shared_layout_ptr->GetBlockPtr( + shared_memory_ptr, SharedDataLayout::TURN_LANE_DATA); + if (shared_layout_ptr->GetBlockSize(SharedDataLayout::TURN_LANE_DATA) > 0) + { + lane_data_stream.read(reinterpret_cast(turn_lane_data_ptr), + shared_layout_ptr->GetBlockSize(SharedDataLayout::TURN_LANE_DATA)); + } + lane_data_stream.close(); + + unsigned *turn_string_blocks_ptr = shared_layout_ptr->GetBlockPtr( + shared_memory_ptr, SharedDataLayout::TURN_STRING_BLOCKS); + if (shared_layout_ptr->GetBlockSize(SharedDataLayout::TURN_STRING_BLOCKS) > 0) + { + turn_string_stream.read( + (char *)turn_string_blocks_ptr, + shared_layout_ptr->GetBlockSize(SharedDataLayout::TURN_STRING_BLOCKS)); + } + + char *turn_string_char_ptr = shared_layout_ptr->GetBlockPtr( + shared_memory_ptr, SharedDataLayout::TURN_STRING_CHAR_LIST); + turn_string_stream.read((char *)&temp_length, sizeof(unsigned)); + + BOOST_ASSERT_MSG(temp_length == + shared_layout_ptr->GetBlockSize(SharedDataLayout::TURN_STRING_CHAR_LIST), + "turn string file corrupted!"); + + if (shared_layout_ptr->GetBlockSize(SharedDataLayout::TURN_STRING_CHAR_LIST) > 0) + { + turn_string_stream.read( + turn_string_char_ptr, + shared_layout_ptr->GetBlockSize(SharedDataLayout::TURN_STRING_CHAR_LIST)); + } + turn_string_stream.close(); + // load original edge information NodeID *via_node_ptr = shared_layout_ptr->GetBlockPtr( shared_memory_ptr, SharedDataLayout::VIA_NODE_LIST); @@ -450,6 +525,9 @@ int Storage::Run() shared_layout_ptr->GetBlockPtr(shared_memory_ptr, SharedDataLayout::TRAVEL_MODE); + LaneDataID *lane_data_id_ptr = shared_layout_ptr->GetBlockPtr( + shared_memory_ptr, SharedDataLayout::LANE_DATA_ID); + extractor::guidance::TurnInstruction *turn_instructions_ptr = shared_layout_ptr->GetBlockPtr( shared_memory_ptr, SharedDataLayout::TURN_INSTRUCTION); @@ -464,6 +542,7 @@ int Storage::Run() via_node_ptr[i] = current_edge_data.via_node; name_id_ptr[i] = current_edge_data.name_id; travel_mode_ptr[i] = current_edge_data.travel_mode; + lane_data_id_ptr[i] = current_edge_data.lane_data_id; turn_instructions_ptr[i] = current_edge_data.turn_instruction; entry_class_id_ptr[i] = current_edge_data.entry_classid; } @@ -514,8 +593,9 @@ int Storage::Run() shared_memory_ptr, SharedDataLayout::DATASOURCE_NAME_DATA); if (shared_layout_ptr->GetBlockSize(SharedDataLayout::DATASOURCE_NAME_DATA) > 0) { - std::cout << "Copying " << (m_datasource_name_data.end() - m_datasource_name_data.begin()) - << " chars into name data ptr\n"; + util::SimpleLogger().Write() + << "Copying " << (m_datasource_name_data.end() - m_datasource_name_data.begin()) + << " chars into name data ptr\n"; std::copy( m_datasource_name_data.begin(), m_datasource_name_data.end(), datasource_name_data_ptr); } diff --git a/src/storage/storage_config.cpp b/src/storage/storage_config.cpp index c74d29686..984408b39 100644 --- a/src/storage/storage_config.cpp +++ b/src/storage/storage_config.cpp @@ -16,7 +16,8 @@ StorageConfig::StorageConfig(const boost::filesystem::path &base) datasource_names_path{base.string() + ".datasource_names"}, datasource_indexes_path{base.string() + ".datasource_indexes"}, names_data_path{base.string() + ".names"}, properties_path{base.string() + ".properties"}, - intersection_class_path{base.string() + ".icd"} + intersection_class_path{base.string() + ".icd"}, turn_lane_data_path{base.string() + ".tld"}, + turn_lane_string_path{base.string() + ".tls"} { } diff --git a/src/util/guidance/turn_lanes.cpp b/src/util/guidance/turn_lanes.cpp index a9859ee08..79d461878 100644 --- a/src/util/guidance/turn_lanes.cpp +++ b/src/util/guidance/turn_lanes.cpp @@ -11,8 +11,7 @@ namespace util { namespace guidance { -LaneTupel::LaneTupel() - : lanes_in_turn(0), first_lane_from_the_right(INVALID_LANEID) +LaneTupel::LaneTupel() : lanes_in_turn(0), first_lane_from_the_right(INVALID_LANEID) { // basic constructor, set everything to zero } diff --git a/src/util/name_table.cpp b/src/util/name_table.cpp index 0c3d942ad..e15a35f84 100644 --- a/src/util/name_table.cpp +++ b/src/util/name_table.cpp @@ -36,11 +36,13 @@ NameTable::NameTable(const std::string &filename) } else { - util::SimpleLogger().Write(logINFO) << "list of street names is empty in construction of name table from: \"" << filename << "\""; + util::SimpleLogger().Write(logINFO) + << "list of street names is empty in construction of name table from: \"" << filename + << "\""; } if (!name_stream) - throw exception("Failed to read " + std::to_string(number_of_chars) + - " characters from " + filename); + throw exception("Failed to read " + std::to_string(number_of_chars) + " characters from " + + filename); } std::string NameTable::GetNameForID(const unsigned name_id) const diff --git a/unit_tests/extractor/graph_compressor.cpp b/unit_tests/extractor/graph_compressor.cpp index b7d27e549..948e82db0 100644 --- a/unit_tests/extractor/graph_compressor.cpp +++ b/unit_tests/extractor/graph_compressor.cpp @@ -30,14 +30,94 @@ BOOST_AUTO_TEST_CASE(long_road_test) std::vector edges = { // src, tgt, dist, edge_id, name_id, access_restricted, fwd, bkwd, roundabout, travel_mode - {0, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE,INVALID_LANE_STRINGID}, - {1, 0, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE,INVALID_LANE_STRINGID}, - {1, 2, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE,INVALID_LANE_STRINGID}, - {2, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE,INVALID_LANE_STRINGID}, - {2, 3, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE,INVALID_LANE_STRINGID}, - {3, 2, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE,INVALID_LANE_STRINGID}, - {3, 4, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE,INVALID_LANE_STRINGID}, - {4, 3, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE,INVALID_LANE_STRINGID}}; + {0, + 1, + 1, + SPECIAL_EDGEID, + 0, + false, + false, + false, + true, + TRAVEL_MODE_INACCESSIBLE, + INVALID_LANE_STRINGID}, + {1, + 0, + 1, + SPECIAL_EDGEID, + 0, + false, + false, + false, + true, + TRAVEL_MODE_INACCESSIBLE, + INVALID_LANE_STRINGID}, + {1, + 2, + 1, + SPECIAL_EDGEID, + 0, + false, + false, + false, + true, + TRAVEL_MODE_INACCESSIBLE, + INVALID_LANE_STRINGID}, + {2, + 1, + 1, + SPECIAL_EDGEID, + 0, + false, + false, + false, + true, + TRAVEL_MODE_INACCESSIBLE, + INVALID_LANE_STRINGID}, + {2, + 3, + 1, + SPECIAL_EDGEID, + 0, + false, + false, + false, + true, + TRAVEL_MODE_INACCESSIBLE, + INVALID_LANE_STRINGID}, + {3, + 2, + 1, + SPECIAL_EDGEID, + 0, + false, + false, + false, + true, + TRAVEL_MODE_INACCESSIBLE, + INVALID_LANE_STRINGID}, + {3, + 4, + 1, + SPECIAL_EDGEID, + 0, + false, + false, + false, + true, + TRAVEL_MODE_INACCESSIBLE, + INVALID_LANE_STRINGID}, + {4, + 3, + 1, + SPECIAL_EDGEID, + 0, + false, + false, + false, + true, + TRAVEL_MODE_INACCESSIBLE, + INVALID_LANE_STRINGID}}; BOOST_ASSERT(edges[0].data.IsCompatibleTo(edges[2].data)); BOOST_ASSERT(edges[2].data.IsCompatibleTo(edges[4].data)); @@ -69,18 +149,138 @@ BOOST_AUTO_TEST_CASE(loop_test) std::vector edges = { // src, tgt, dist, edge_id, name_id, access_restricted, fwd, bkwd, roundabout, travel_mode - {0, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE,INVALID_LANE_STRINGID}, - {0, 5, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE,INVALID_LANE_STRINGID}, - {1, 0, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE,INVALID_LANE_STRINGID}, - {1, 2, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE,INVALID_LANE_STRINGID}, - {2, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE,INVALID_LANE_STRINGID}, - {2, 3, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE,INVALID_LANE_STRINGID}, - {3, 2, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE,INVALID_LANE_STRINGID}, - {3, 4, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE,INVALID_LANE_STRINGID}, - {4, 3, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE,INVALID_LANE_STRINGID}, - {4, 5, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE,INVALID_LANE_STRINGID}, - {5, 0, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE,INVALID_LANE_STRINGID}, - {5, 4, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE,INVALID_LANE_STRINGID}, + {0, + 1, + 1, + SPECIAL_EDGEID, + 0, + false, + false, + false, + true, + TRAVEL_MODE_INACCESSIBLE, + INVALID_LANE_STRINGID}, + {0, + 5, + 1, + SPECIAL_EDGEID, + 0, + false, + false, + false, + true, + TRAVEL_MODE_INACCESSIBLE, + INVALID_LANE_STRINGID}, + {1, + 0, + 1, + SPECIAL_EDGEID, + 0, + false, + false, + false, + true, + TRAVEL_MODE_INACCESSIBLE, + INVALID_LANE_STRINGID}, + {1, + 2, + 1, + SPECIAL_EDGEID, + 0, + false, + false, + false, + true, + TRAVEL_MODE_INACCESSIBLE, + INVALID_LANE_STRINGID}, + {2, + 1, + 1, + SPECIAL_EDGEID, + 0, + false, + false, + false, + true, + TRAVEL_MODE_INACCESSIBLE, + INVALID_LANE_STRINGID}, + {2, + 3, + 1, + SPECIAL_EDGEID, + 0, + false, + false, + false, + true, + TRAVEL_MODE_INACCESSIBLE, + INVALID_LANE_STRINGID}, + {3, + 2, + 1, + SPECIAL_EDGEID, + 0, + false, + false, + false, + true, + TRAVEL_MODE_INACCESSIBLE, + INVALID_LANE_STRINGID}, + {3, + 4, + 1, + SPECIAL_EDGEID, + 0, + false, + false, + false, + true, + TRAVEL_MODE_INACCESSIBLE, + INVALID_LANE_STRINGID}, + {4, + 3, + 1, + SPECIAL_EDGEID, + 0, + false, + false, + false, + true, + TRAVEL_MODE_INACCESSIBLE, + INVALID_LANE_STRINGID}, + {4, + 5, + 1, + SPECIAL_EDGEID, + 0, + false, + false, + false, + true, + TRAVEL_MODE_INACCESSIBLE, + INVALID_LANE_STRINGID}, + {5, + 0, + 1, + SPECIAL_EDGEID, + 0, + false, + false, + false, + true, + TRAVEL_MODE_INACCESSIBLE, + INVALID_LANE_STRINGID}, + {5, + 4, + 1, + SPECIAL_EDGEID, + 0, + false, + false, + false, + true, + TRAVEL_MODE_INACCESSIBLE, + INVALID_LANE_STRINGID}, }; BOOST_ASSERT(edges.size() == 12); @@ -124,12 +324,72 @@ BOOST_AUTO_TEST_CASE(t_intersection) std::vector edges = { // src, tgt, dist, edge_id, name_id, access_restricted, fwd, bkwd, roundabout, travel_mode - {0, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE,INVALID_LANE_STRINGID}, - {1, 0, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE,INVALID_LANE_STRINGID}, - {1, 2, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE,INVALID_LANE_STRINGID}, - {1, 3, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE,INVALID_LANE_STRINGID}, - {2, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE,INVALID_LANE_STRINGID}, - {3, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE,INVALID_LANE_STRINGID}, + {0, + 1, + 1, + SPECIAL_EDGEID, + 0, + false, + false, + false, + true, + TRAVEL_MODE_INACCESSIBLE, + INVALID_LANE_STRINGID}, + {1, + 0, + 1, + SPECIAL_EDGEID, + 0, + false, + false, + false, + true, + TRAVEL_MODE_INACCESSIBLE, + INVALID_LANE_STRINGID}, + {1, + 2, + 1, + SPECIAL_EDGEID, + 0, + false, + false, + false, + true, + TRAVEL_MODE_INACCESSIBLE, + INVALID_LANE_STRINGID}, + {1, + 3, + 1, + SPECIAL_EDGEID, + 0, + false, + false, + false, + true, + TRAVEL_MODE_INACCESSIBLE, + INVALID_LANE_STRINGID}, + {2, + 1, + 1, + SPECIAL_EDGEID, + 0, + false, + false, + false, + true, + TRAVEL_MODE_INACCESSIBLE, + INVALID_LANE_STRINGID}, + {3, + 1, + 1, + SPECIAL_EDGEID, + 0, + false, + false, + false, + true, + TRAVEL_MODE_INACCESSIBLE, + INVALID_LANE_STRINGID}, }; BOOST_ASSERT(edges[0].data.IsCompatibleTo(edges[1].data)); @@ -160,10 +420,50 @@ BOOST_AUTO_TEST_CASE(street_name_changes) std::vector edges = { // src, tgt, dist, edge_id, name_id, access_restricted, fwd, bkwd, roundabout, travel_mode - {0, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE,INVALID_LANE_STRINGID}, - {1, 0, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE,INVALID_LANE_STRINGID}, - {1, 2, 1, SPECIAL_EDGEID, 1, false, false, false, true, TRAVEL_MODE_INACCESSIBLE,INVALID_LANE_STRINGID}, - {2, 1, 1, SPECIAL_EDGEID, 1, false, false, false, true, TRAVEL_MODE_INACCESSIBLE,INVALID_LANE_STRINGID}, + {0, + 1, + 1, + SPECIAL_EDGEID, + 0, + false, + false, + false, + true, + TRAVEL_MODE_INACCESSIBLE, + INVALID_LANE_STRINGID}, + {1, + 0, + 1, + SPECIAL_EDGEID, + 0, + false, + false, + false, + true, + TRAVEL_MODE_INACCESSIBLE, + INVALID_LANE_STRINGID}, + {1, + 2, + 1, + SPECIAL_EDGEID, + 1, + false, + false, + false, + true, + TRAVEL_MODE_INACCESSIBLE, + INVALID_LANE_STRINGID}, + {2, + 1, + 1, + SPECIAL_EDGEID, + 1, + false, + false, + false, + true, + TRAVEL_MODE_INACCESSIBLE, + INVALID_LANE_STRINGID}, }; BOOST_ASSERT(edges[0].data.IsCompatibleTo(edges[1].data)); @@ -190,10 +490,50 @@ BOOST_AUTO_TEST_CASE(direction_changes) std::vector edges = { // src, tgt, dist, edge_id, name_id, access_restricted, fwd, bkwd, roundabout, travel_mode - {0, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE,INVALID_LANE_STRINGID}, - {1, 0, 1, SPECIAL_EDGEID, 0, false, true, false, true, TRAVEL_MODE_INACCESSIBLE,INVALID_LANE_STRINGID}, - {1, 2, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE,INVALID_LANE_STRINGID}, - {2, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE,INVALID_LANE_STRINGID}, + {0, + 1, + 1, + SPECIAL_EDGEID, + 0, + false, + false, + false, + true, + TRAVEL_MODE_INACCESSIBLE, + INVALID_LANE_STRINGID}, + {1, + 0, + 1, + SPECIAL_EDGEID, + 0, + false, + true, + false, + true, + TRAVEL_MODE_INACCESSIBLE, + INVALID_LANE_STRINGID}, + {1, + 2, + 1, + SPECIAL_EDGEID, + 0, + false, + false, + false, + true, + TRAVEL_MODE_INACCESSIBLE, + INVALID_LANE_STRINGID}, + {2, + 1, + 1, + SPECIAL_EDGEID, + 0, + false, + false, + false, + true, + TRAVEL_MODE_INACCESSIBLE, + INVALID_LANE_STRINGID}, }; Graph graph(5, edges); diff --git a/unit_tests/mocks/mock_datafacade.hpp b/unit_tests/mocks/mock_datafacade.hpp index c6fd567ce..17c511287 100644 --- a/unit_tests/mocks/mock_datafacade.hpp +++ b/unit_tests/mocks/mock_datafacade.hpp @@ -180,6 +180,10 @@ class MockDataFacade final : public engine::datafacade::BaseDataFacade BearingClassID GetBearingClassID(const NodeID /*id*/) const override { return 0; }; EntryClassID GetEntryClassID(const EdgeID /*id*/) const override { return 0; } + bool hasLaneData(const EdgeID /*id*/) const { return true; }; + util::guidance::LaneTupelIdPair GetLaneData(const EdgeID /*id*/) const { return {{0, 0}, 0}; } + std::string GetTurnStringForID(const LaneStringID /*lane_string_id*/) const { return ""; }; + util::guidance::BearingClass GetBearingClass(const BearingClassID /*bearing_class_id*/) const override {