diff --git a/features/guidance/anticipate-lanes.feature b/features/guidance/anticipate-lanes.feature index c9822c5be..f180b7a33 100644 --- a/features/guidance/anticipate-lanes.feature +++ b/features/guidance/anticipate-lanes.feature @@ -280,8 +280,8 @@ Feature: Turn Lane Guidance | di | | off | When I route I should get - | waypoints | route | turns | lanes | - | a,e | main,main,main,main | depart,use lane straight,use lane straight,arrive | ,left:false straight:false straight:true straight:false right:false,left:false straight:true right:false, | + | waypoints | route | turns | lanes | + | a,e | main,main,main | depart,use lane straight,arrive | ,left:false straight:false straight:true straight:false right:false, | @anticipate Scenario: Anticipate Lanes for through and collapse multiple use lanes @@ -305,9 +305,9 @@ Feature: Turn Lane Guidance | dj | | off | When I route I should get - | waypoints | route | turns | lanes | - | a,c | main,main,main | depart,use lane straight,arrive | ,left:false straight:true straight:true right:false, | - | a,d | main,main,main | depart,use lane straight,arrive | ,left:false straight:true straight:true right:false, | + | waypoints | route | turns | lanes | + | a,c | main,main | depart,arrive | , | + | a,d | main,main | depart,arrive | , | @anticipate Scenario: Anticipate Lanes for through followed by left/right @@ -419,8 +419,8 @@ Feature: Turn Lane Guidance | dt | | off | When I route I should get - | waypoints | route | turns | lanes | - | a,e | main,main,main,main,main | depart,use lane straight,continue right,use lane straight,arrive | ,left:false straight:false straight:false straight:false straight:true straight:true right:false,straight:false straight:false right:false right:true right:true,left:false straight:true straight:true, | + | waypoints | route | turns | lanes | + | a,e | main,main,main,main | depart,use lane straight,continue right,arrive | ,left:false straight:false straight:false straight:false straight:true straight:true right:false,straight:false straight:false right:false right:true right:true, | @anticipate @todo @bug @2661 Scenario: Anticipate with lanes in roundabout: roundabouts as the unit of anticipation @@ -615,7 +615,7 @@ Feature: Turn Lane Guidance | x,c | xb,roundabout,roundabout | depart,roundabout-exit-undefined,arrive | ,, | | x,a | xb,roundabout,roundabout | depart,roundabout-exit-undefined,arrive | ,, | - @anticipate + @anticipate @todo @2032 Scenario: No Lanes for Roundabouts, see #2626 Given the node map | a | b | | | x | diff --git a/features/guidance/collapse.feature b/features/guidance/collapse.feature index 04e98e6be..c66ee2813 100644 --- a/features/guidance/collapse.feature +++ b/features/guidance/collapse.feature @@ -767,8 +767,8 @@ Feature: Collapse | di | | off | When I route I should get - | waypoints | route | turns | - | a,e | main,main,main,main | depart,use lane straight,use lane straight,arrive | + | waypoints | route | turns | + | a,e | main,main,main | depart,use lane straight,arrive | Scenario: But _do_ collapse UseLane step when lanes stay the same Given the node map @@ -790,5 +790,5 @@ Feature: Collapse | di | | off | When I route I should get - | waypoints | route | turns | - | a,e | main,main,main | depart,use lane straight,arrive | + | waypoints | route | turns | + | a,e | main,main | depart,arrive | diff --git a/features/guidance/turn-lanes.feature b/features/guidance/turn-lanes.feature index 1f83f840e..34c7cbf8d 100644 --- a/features/guidance/turn-lanes.feature +++ b/features/guidance/turn-lanes.feature @@ -358,10 +358,10 @@ 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 | ,left:true straight;right:false, | - | a,d | road,road,road | depart,use lane straight,arrive | ,left:false straight;right:true, | - | a,g | road,right,right | depart,turn right,arrive | ,left:false straight;right:true, | + | waypoints | route | turns | lanes | + | a,f | road,turn,turn | depart,turn left,arrive | ,left:true straight;right:false, | + | a,d | road,road | depart,arrive | , | + | a,g | road,right,right | depart,turn right,arrive | ,left:false straight;right:true, | @partition-lanes @previous-lanes Scenario: Passing a one-way street, partly pulled back lanes, no through @@ -491,9 +491,9 @@ Feature: Turn Lane Guidance | restriction | bc | dc | c | no_right_turn | When I route I should get - | waypoints | route | turns | lanes | - | a,g | road,cross,cross | depart,turn left,arrive | ,left:true left:true straight:false straight:false, | - | a,e | road,road | depart,arrive | , | + | waypoints | route | turns | lanes | + | a,g | road,cross,cross | depart,turn left,arrive | ,left:true left:true straight:false straight:false right:false, | + | a,e | road,road | depart,arrive | , | #NEEDS TO BE INVESTIGATED. Turn restriction shouldn't be here. See #2867 @reverse @previous-lanes diff --git a/include/engine/geospatial_query.hpp b/include/engine/geospatial_query.hpp index 6a3b27a28..1ff56500f 100644 --- a/include/engine/geospatial_query.hpp +++ b/include/engine/geospatial_query.hpp @@ -20,7 +20,8 @@ namespace osrm namespace engine { -inline std::pair boolPairAnd(const std::pair &A, const std::pair &B) +inline std::pair boolPairAnd(const std::pair &A, + const std::pair &B) { return std::make_pair(A.first && B.first, A.second && B.second); } diff --git a/include/extractor/edge_based_graph_factory.hpp b/include/extractor/edge_based_graph_factory.hpp index e330f5a22..130e07800 100644 --- a/include/extractor/edge_based_graph_factory.hpp +++ b/include/extractor/edge_based_graph_factory.hpp @@ -83,18 +83,17 @@ class EdgeBasedGraphFactory EdgeBasedGraphFactory(const EdgeBasedGraphFactory &) = delete; EdgeBasedGraphFactory &operator=(const EdgeBasedGraphFactory &) = delete; - explicit EdgeBasedGraphFactory( - std::shared_ptr node_based_graph, - const CompressedEdgeContainer &compressed_edge_container, - const std::unordered_set &barrier_nodes, - const std::unordered_set &traffic_lights, - std::shared_ptr restriction_map, - const std::vector &node_info_list, - ProfileProperties profile_properties, - const util::NameTable &name_table, - std::vector &turn_lane_offsets, - std::vector &turn_lane_masks, - guidance::LaneDescriptionMap &lane_description_map); + explicit EdgeBasedGraphFactory(std::shared_ptr node_based_graph, + const CompressedEdgeContainer &compressed_edge_container, + const std::unordered_set &barrier_nodes, + const std::unordered_set &traffic_lights, + std::shared_ptr restriction_map, + const std::vector &node_info_list, + ProfileProperties profile_properties, + const util::NameTable &name_table, + std::vector &turn_lane_offsets, + std::vector &turn_lane_masks, + guidance::LaneDescriptionMap &lane_description_map); void Run(ScriptingEnvironment &scripting_environment, const std::string &original_edge_data_filename, diff --git a/include/extractor/extractor_callbacks.hpp b/include/extractor/extractor_callbacks.hpp index 5db7636a0..dd11c86cf 100644 --- a/include/extractor/extractor_callbacks.hpp +++ b/include/extractor/extractor_callbacks.hpp @@ -40,12 +40,11 @@ class ExtractorCallbacks using MapKey = std::pair; using MapVal = unsigned; std::unordered_map> string_map; - guidance::LaneDescriptionMap &lane_description_map; + guidance::LaneDescriptionMap lane_description_map; ExtractionContainers &external_memory; public: - explicit ExtractorCallbacks(ExtractionContainers &extraction_containers, - guidance::LaneDescriptionMap &lane_description_map); + explicit ExtractorCallbacks(ExtractionContainers &extraction_containers); ExtractorCallbacks(const ExtractorCallbacks &) = delete; ExtractorCallbacks &operator=(const ExtractorCallbacks &) = delete; @@ -58,6 +57,9 @@ class ExtractorCallbacks // warning: caller needs to take care of synchronization! void ProcessWay(const osmium::Way ¤t_way, const ExtractionWay &result_way); + + // destroys the internal laneDescriptionMap + guidance::LaneDescriptionMap &&moveOutLaneDescriptionMap(); }; } } diff --git a/include/extractor/guidance/turn_lane_data.hpp b/include/extractor/guidance/turn_lane_data.hpp index 17caecadd..113cda107 100644 --- a/include/extractor/guidance/turn_lane_data.hpp +++ b/include/extractor/guidance/turn_lane_data.hpp @@ -40,10 +40,6 @@ LaneDataVector::iterator findTag(const TurnLaneType::Mask tag, LaneDataVector &d // Returns true if any of the queried tags is contained bool hasTag(const TurnLaneType::Mask tag, const LaneDataVector &data); - -// Check if a set of lanes is a subset of a different set of lanes -bool isSubsetOf(const LaneDataVector &subset_candidate, const LaneDataVector &superset_candidate); - } // namespace lane_data_generation } // namespace guidance diff --git a/include/extractor/guidance/turn_lane_handler.hpp b/include/extractor/guidance/turn_lane_handler.hpp index 01d745394..12064e48a 100644 --- a/include/extractor/guidance/turn_lane_handler.hpp +++ b/include/extractor/guidance/turn_lane_handler.hpp @@ -14,6 +14,8 @@ #include "util/node_based_graph.hpp" #include "util/typedefs.hpp" +#include +#include #include #include #include @@ -31,36 +33,39 @@ namespace guidance // assigns appropriate turn tupels to the different turns. namespace lanes { + +namespace +{ +typedef enum TurnLaneScenario { + SIMPLE, // a straightforward assignment + PARTITION_LOCAL, // an assignment that requires partitioning, using local turns + SIMPLE_PREVIOUS, // an assignemtnn using the turns specified at the previous road (e.g. + // traffic light, lanes not drawn up to the intersection) + PARTITION_PREVIOUS, // a set of lanes on a turn with a traffic island. The lanes for the + // turn end at the previous turn (parts of it remain valid without being + // shown again) + SLIPROAD, // Sliproads are simple assignments that, for better visual representation should + // include turns from other roads in their listings + MERGE, // Merging Lanes + NONE, // not a turn lane scenario at all + INVALID, // some error might have occurred + UNKNOWN, // UNKNOWN describes all cases that we are currently not able to handle + NUM_SCENARIOS +} TurnLaneScenario; + +const constexpr char *scenario_names[] = {"Simple", + "Partition Local", + "Simple Previous", + "Partition Previous", + "Sliproad", + "Merge", + "None", + "Invalid", + "Unknown"}; +} // namespace + class TurnLaneHandler { - typedef enum TurnLaneScenario { - SIMPLE, // a straightforward assignment - PARTITION_LOCAL, // an assignment that requires partitioning, using local turns - SIMPLE_PREVIOUS, // an assignemtnn using the turns specified at the previous road (e.g. - // traffic light, lanes not drawn up to the intersection) - PARTITION_PREVIOUS, // a set of lanes on a turn with a traffic island. The lanes for the - // turn end at the previous turn (parts of it remain valid without being - // shown again) - SLIPROAD, // Sliproads are simple assignments that, for better visual representation should - // include turns from other roads in their listings - MERGE, // Merging Lanes - NONE, // not a turn lane scenario at all - INVALID, // some error might have occurred - UNKNOWN, // UNKNOWN describes all cases that we are currently not able to handle - NUM_SCENARIOS - } TurnLaneScenario; - - const constexpr static char *scenario_names[TurnLaneScenario::NUM_SCENARIOS] = { - "Simple", - "Partition Local", - "Simple Previous", - "Partition Previous", - "Sliproad", - "Merge", - "None", - "Invalid", - "Unknown"}; - public: typedef std::vector LaneDataVector; @@ -78,8 +83,8 @@ class TurnLaneHandler Intersection assignTurnLanes(const NodeID at, const EdgeID via_edge, Intersection intersection); private: - unsigned *count_handled; - unsigned *count_called; + mutable std::atomic count_handled; + mutable std::atomic count_called; // 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; @@ -133,6 +138,9 @@ class TurnLaneHandler LaneDataVector &lane_data) const; }; +static_assert(sizeof(scenario_names) / sizeof(*scenario_names) == TurnLaneScenario::NUM_SCENARIOS, + "Number of scenarios needs to match the number of scenario names."); + } // namespace lanes } // namespace guidance } // namespace extractor diff --git a/include/extractor/guidance/turn_lane_matcher.hpp b/include/extractor/guidance/turn_lane_matcher.hpp index fc67b036b..45c9f37ad 100644 --- a/include/extractor/guidance/turn_lane_matcher.hpp +++ b/include/extractor/guidance/turn_lane_matcher.hpp @@ -32,10 +32,10 @@ typename Intersection::const_iterator findBestMatch(const TurnLaneType::Mask tag const Intersection &intersection); // the quality of a matching to decide between first/second possibility on segregated intersections -double getMatchingQuality( const TurnLaneType::Mask tag, const ConnectedRoad &road ); +double getMatchingQuality(const TurnLaneType::Mask tag, const ConnectedRoad &road); -typename Intersection::const_iterator -findBestMatchForReverse(const TurnLaneType::Mask leftmost_tag, const Intersection &intersection); +typename Intersection::const_iterator findBestMatchForReverse(const TurnLaneType::Mask leftmost_tag, + const Intersection &intersection); // a match is trivial if all turns can be associated with their best match in a valid way and the // matches occur in order diff --git a/include/extractor/guidance/turn_lane_types.hpp b/include/extractor/guidance/turn_lane_types.hpp index 14d68567d..dbd4c5b50 100644 --- a/include/extractor/guidance/turn_lane_types.hpp +++ b/include/extractor/guidance/turn_lane_types.hpp @@ -9,7 +9,7 @@ #include #include -#include +#include #include "util/json_container.hpp" #include "util/simple_logger.hpp" @@ -90,8 +90,7 @@ struct TurnLaneDescription_hash std::size_t operator()(const TurnLaneDescription &lane_description) const { std::size_t seed = 0; - for (auto val : lane_description) - boost::hash_combine(seed, val); + boost::hash_range(seed, lane_description.begin(), lane_description.end()); return seed; } }; diff --git a/include/util/attributes.hpp b/include/util/attributes.hpp index a9ce8bc57..667d933bf 100644 --- a/include/util/attributes.hpp +++ b/include/util/attributes.hpp @@ -1,15 +1,13 @@ #ifndef OSRM_ATTRIBUTES_HPP_ #define OSRM_ATTRIBUTES_HPP_ - // OSRM_ATTR_WARN_UNUSED - caller has to use function's return value // https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html #if defined(__GNUC__) && (__GNUC__ >= 4) - #define OSRM_ATTR_WARN_UNUSED __attribute__ ((warn_unused_result)) +#define OSRM_ATTR_WARN_UNUSED __attribute__((warn_unused_result)) #else - #define OSRM_ATTR_WARN_UNUSED +#define OSRM_ATTR_WARN_UNUSED #endif - #endif diff --git a/include/util/debug.hpp b/include/util/debug.hpp index 32083e411..28cfde220 100644 --- a/include/util/debug.hpp +++ b/include/util/debug.hpp @@ -30,8 +30,7 @@ inline void print(const engine::guidance::RouteStep &step) for (const auto &intersection : step.intersections) { std::cout << "(Lanes: " << static_cast(intersection.lanes.lanes_in_turn) << " " - << static_cast(intersection.lanes.first_lane_from_the_right) - << " bearings:"; + << static_cast(intersection.lanes.first_lane_from_the_right) << " bearings:"; for (auto bearing : intersection.bearings) std::cout << " " << bearing; std::cout << ", entry: "; diff --git a/src/contractor/contractor.cpp b/src/contractor/contractor.cpp index 1f467b588..ca45a63aa 100644 --- a/src/contractor/contractor.cpp +++ b/src/contractor/contractor.cpp @@ -251,12 +251,13 @@ parse_segment_lookup_from_csv_files(const std::vector &segment_spee const auto last = end(line); // The ulong_long -> uint64_t will likely break on 32bit platforms - const auto ok = parse(it, - last, // - (ulong_long >> ',' >> ulong_long >> ',' >> uint_ >> *(',' >> *char_)), // - from_node_id, - to_node_id, - speed); // + const auto ok = + parse(it, + last, // + (ulong_long >> ',' >> ulong_long >> ',' >> uint_ >> *(',' >> *char_)), // + from_node_id, + to_node_id, + speed); // if (!ok || it != last) throw util::exception{"Segment speed file " + filename + " malformed"}; @@ -334,14 +335,14 @@ parse_turn_penalty_lookup_from_csv_files(const std::vector &turn_pe const auto last = end(line); // The ulong_long -> uint64_t will likely break on 32bit platforms - const auto ok = - parse(it, - last, // - (ulong_long >> ',' >> ulong_long >> ',' >> ulong_long >> ',' >> double_ >> *(',' >> *char_)), // - from_node_id, - via_node_id, - to_node_id, - penalty); // + const auto ok = parse(it, + last, // + (ulong_long >> ',' >> ulong_long >> ',' >> ulong_long >> ',' >> + double_ >> *(',' >> *char_)), // + from_node_id, + via_node_id, + to_node_id, + penalty); // if (!ok || it != last) throw util::exception{"Turn penalty file " + filename + " malformed"}; @@ -807,7 +808,8 @@ EdgeID Contractor::LoadEdgeExpandedGraph( // We found a zero-speed edge, so we'll skip this whole edge-based-edge which // effectively removes it from the routing network. - if (skip_this_edge) { + if (skip_this_edge) + { penaltyblock++; continue; } diff --git a/src/engine/api/json_factory.cpp b/src/engine/api/json_factory.cpp index 6ce232bfe..44d28b1d2 100644 --- a/src/engine/api/json_factory.cpp +++ b/src/engine/api/json_factory.cpp @@ -68,8 +68,8 @@ inline bool hasValidLanes(const guidance::Intersection &intersection) std::string instructionTypeToString(const TurnType::Enum type) { - static_assert(sizeof(turn_type_names)/sizeof(turn_type_names[0]) >= TurnType::MaxTurnType, - "Some turn types has not string representation."); + static_assert(sizeof(turn_type_names) / sizeof(turn_type_names[0]) >= TurnType::MaxTurnType, + "Some turn types has not string representation."); return turn_type_names[static_cast(type)]; } @@ -99,15 +99,17 @@ util::json::Array lanesFromIntersection(const guidance::Intersection &intersecti std::string instructionModifierToString(const DirectionModifier::Enum modifier) { - static_assert(sizeof(modifier_names)/sizeof(modifier_names[0]) >= DirectionModifier::MaxDirectionModifier, - "Some direction modifiers has not string representation."); + static_assert(sizeof(modifier_names) / sizeof(modifier_names[0]) >= + DirectionModifier::MaxDirectionModifier, + "Some direction modifiers has not string representation."); return modifier_names[static_cast(modifier)]; } std::string waypointTypeToString(const guidance::WaypointType waypoint_type) { - static_assert(sizeof(waypoint_type_names)/sizeof(waypoint_type_names[0]) >= static_cast(guidance::WaypointType::MaxWaypointType), - "Some waypoint types has not string representation."); + static_assert(sizeof(waypoint_type_names) / sizeof(waypoint_type_names[0]) >= + static_cast(guidance::WaypointType::MaxWaypointType), + "Some waypoint types has not string representation."); return waypoint_type_names[static_cast(waypoint_type)]; } diff --git a/src/engine/guidance/lane_processing.cpp b/src/engine/guidance/lane_processing.cpp index 51d478973..a447887da 100644 --- a/src/engine/guidance/lane_processing.cpp +++ b/src/engine/guidance/lane_processing.cpp @@ -3,8 +3,8 @@ #include "util/guidance/toolkit.hpp" #include "extractor/guidance/turn_instruction.hpp" -#include "engine/guidance/toolkit.hpp" #include "engine/guidance/post_processing.hpp" +#include "engine/guidance/toolkit.hpp" #include #include @@ -80,7 +80,8 @@ std::vector anticipateLaneChange(std::vector steps, // where lanes in the turn fan in but for example the overall lanes at that location // fan out, we would have to know the asymmetric mapping of lanes. This is currently // not possible at the moment. In the following we implement a heuristic instead. - const LaneID current_num_all_lanes = current.intersections.front().lane_description.size(); + const LaneID current_num_all_lanes = + current.intersections.front().lane_description.size(); const LaneID current_num_lanes_right_of_turn = current_lanes.first_lane_from_the_right; const LaneID current_num_lanes_left_of_turn = current_num_all_lanes - diff --git a/src/engine/guidance/post_processing.cpp b/src/engine/guidance/post_processing.cpp index b7cc5ef52..ad3d7daa4 100644 --- a/src/engine/guidance/post_processing.cpp +++ b/src/engine/guidance/post_processing.cpp @@ -1,5 +1,5 @@ -#include "extractor/guidance/turn_instruction.hpp" #include "engine/guidance/post_processing.hpp" +#include "extractor/guidance/turn_instruction.hpp" #include "engine/guidance/assemble_steps.hpp" #include "engine/guidance/lane_processing.hpp" @@ -408,8 +408,11 @@ void collapseTurnAt(std::vector &steps, if (bearingsAreReversed( util::bearing::reverseBearing(getBearing(true, one_back_step)), getBearing(false, current_step))) + { + steps[one_back_index].maneuver.instruction.type = TurnType::Continue; steps[one_back_index].maneuver.instruction.direction_modifier = DirectionModifier::UTurn; + } } else if (TurnType::Merge == one_back_step.maneuver.instruction.type && current_step.maneuver.instruction.type != @@ -550,8 +553,6 @@ RouteStep elongate(RouteStep step, const RouteStep &by_step) return step; } - - // Post processing can invalidate some instructions. For example StayOnRoundabout // is turned into exit counts. These instructions are removed by the following function @@ -764,22 +765,23 @@ std::vector collapseTurns(std::vector steps) else { // Handle possible u-turns between highways that look like slip-roads - if (steps[getPreviousIndex(one_back_index)].name_id == steps[step_index].name_id && - steps[step_index].name_id != EMPTY_NAMEID) - { - steps[one_back_index].maneuver.instruction.type = TurnType::Continue; - } - else - { - steps[one_back_index].maneuver.instruction.type = TurnType::Turn; - } if (compatible(one_back_step, current_step)) { + // Turn Types in the response depend on whether we find the same road name + // (sliproad indcating a u-turn) or if we are turning onto a different road, in + // which case we use a turn. + if (steps[getPreviousIndex(one_back_index)].name_id == + steps[step_index].name_id && + steps[step_index].name_id != EMPTY_NAMEID) + steps[one_back_index].maneuver.instruction.type = TurnType::Continue; + else + steps[one_back_index].maneuver.instruction.type = TurnType::Turn; + steps[one_back_index] = elongate(std::move(steps[one_back_index]), steps[step_index]); + steps[one_back_index].name_id = steps[step_index].name_id; steps[one_back_index].name = steps[step_index].name; - steps[one_back_index].maneuver.instruction.type = TurnType::Turn; // the turn lanes for this turn are on the sliproad itself, so we have to // remember them steps[one_back_index].intersections.front().lanes = @@ -1202,7 +1204,8 @@ std::vector buildIntersections(std::vector steps) { // count intersections. We cannot use exit, since intersections can follow directly // after a roundabout - steps[last_valid_instruction] = elongate(std::move(steps[last_valid_instruction]), step); + steps[last_valid_instruction] = + elongate(std::move(steps[last_valid_instruction]), step); step.maneuver.instruction = TurnInstruction::NO_TURN(); } else if (!isSilent(instruction)) diff --git a/src/extractor/edge_based_graph_factory.cpp b/src/extractor/edge_based_graph_factory.cpp index 184738e31..a6fa6c64e 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" diff --git a/src/extractor/extractor.cpp b/src/extractor/extractor.cpp index 8bc144183..39af53615 100644 --- a/src/extractor/extractor.cpp +++ b/src/extractor/extractor.cpp @@ -47,6 +47,7 @@ #include #include //partial_sum #include +#include #include #include #include @@ -56,6 +57,36 @@ namespace osrm namespace extractor { +namespace +{ +std::tuple, std::vector> +transformTurnLaneMapIntoArrays(const guidance::LaneDescriptionMap &turn_lane_map) +{ + // could use some additional capacity? To avoid a copy during processing, though small data so + // probably not that important. + // + // From the map, we construct an adjacency array that allows access from all IDs to the list of + // associated Turn Lane Masks. + // + // turn lane offsets points into the locations of the turn_lane_masks array. We use a standard + // adjacency array like structure to store the turn lane masks. + std::vector turn_lane_offsets(turn_lane_map.size() + 2); // empty ID + sentinel + for (auto entry = turn_lane_map.begin(); entry != turn_lane_map.end(); ++entry) + turn_lane_offsets[entry->second + 1] = entry->first.size(); + + // inplace prefix sum + std::partial_sum(turn_lane_offsets.begin(), turn_lane_offsets.end(), turn_lane_offsets.begin()); + + // allocate the current masks + std::vector turn_lane_masks(turn_lane_offsets.back()); + for (auto entry = turn_lane_map.begin(); entry != turn_lane_map.end(); ++entry) + std::copy(entry->first.begin(), + entry->first.end(), + turn_lane_masks.begin() + turn_lane_offsets[entry->second]); + return std::make_tuple(std::move(turn_lane_offsets), std::move(turn_lane_masks)); +} +} // namespace + /** * TODO: Refactor this function into smaller functions for better readability. * @@ -94,8 +125,7 @@ int Extractor::run(ScriptingEnvironment &scripting_environment) util::SimpleLogger().Write() << "Threads: " << number_of_threads; ExtractionContainers extraction_containers; - auto extractor_callbacks = - util::make_unique(extraction_containers, turn_lane_map); + auto extractor_callbacks = util::make_unique(extraction_containers); const osmium::io::File input_file(config.input_path.string()); osmium::io::Reader reader(input_file); @@ -185,6 +215,9 @@ int Extractor::run(ScriptingEnvironment &scripting_environment) << number_of_ways << " ways, and " << number_of_relations << " relations"; + // take control over the turn lane map + turn_lane_map = extractor_callbacks->moveOutLaneDescriptionMap(); + extractor_callbacks.reset(); if (extraction_containers.all_edges_list.empty()) @@ -447,19 +480,9 @@ Extractor::BuildEdgeExpandedGraph(ScriptingEnvironment &scripting_environment, // could use some additional capacity? To avoid a copy during processing, though small data so // probably not that important. - std::vector turn_lane_offsets(turn_lane_map.size() + 2); // empty ID + sentinel - for (auto entry = turn_lane_map.begin(); entry != turn_lane_map.end(); ++entry) - turn_lane_offsets[entry->second + 1] = entry->first.size(); - - // inplace prefix sum - std::partial_sum(turn_lane_offsets.begin(), turn_lane_offsets.end(), turn_lane_offsets.begin()); - - // allocate the current masks - std::vector turn_lane_masks(turn_lane_offsets.back()); - for (auto entry = turn_lane_map.begin(); entry != turn_lane_map.end(); ++entry) - std::copy(entry->first.begin(), - entry->first.end(), - turn_lane_masks.begin() + turn_lane_offsets[entry->second]); + std::vector turn_lane_offsets; + std::vector turn_lane_masks; + std::tie(turn_lane_offsets, turn_lane_masks) = transformTurnLaneMapIntoArrays(turn_lane_map); EdgeBasedGraphFactory edge_based_graph_factory( node_based_graph, @@ -649,24 +672,16 @@ void Extractor::WriteIntersectionClassificationData( void Extractor::WriteTurnLaneData(const std::string &turn_lane_file) const { // Write the turn lane data to file - std::vector turn_lane_offsets(turn_lane_map.size() + 2); // empty ID + sentinel - for (auto entry = turn_lane_map.begin(); entry != turn_lane_map.end(); ++entry) - turn_lane_offsets[entry->second + 1] = entry->first.size(); - - // inplace prefix sum - std::partial_sum(turn_lane_offsets.begin(), turn_lane_offsets.end(), turn_lane_offsets.begin()); - - // allocate the current masks - std::vector turn_lane_masks(turn_lane_offsets.back()); - for (auto entry = turn_lane_map.begin(); entry != turn_lane_map.end(); ++entry) - std::copy(entry->first.begin(), - entry->first.end(), - turn_lane_masks.begin() + turn_lane_offsets[entry->second]); + std::vector turn_lane_offsets; + std::vector turn_lane_masks; + std::tie(turn_lane_offsets, turn_lane_masks) = transformTurnLaneMapIntoArrays(turn_lane_map); util::SimpleLogger().Write() << "Writing turn lane masks..."; TIMER_START(turn_lane_timer); std::ofstream ofs(turn_lane_file, std::ios::binary); + if (!ofs) + throw osrm::util::exception("Failed to open " + turn_lane_file + " for writing."); if (!util::serializeVector(ofs, turn_lane_offsets)) { diff --git a/src/extractor/extractor_callbacks.cpp b/src/extractor/extractor_callbacks.cpp index 2a1033ddd..55bfff4a6 100644 --- a/src/extractor/extractor_callbacks.cpp +++ b/src/extractor/extractor_callbacks.cpp @@ -31,15 +31,13 @@ namespace extractor using TurnLaneDescription = guidance::TurnLaneDescription; namespace TurnLaneType = guidance::TurnLaneType; -ExtractorCallbacks::ExtractorCallbacks(ExtractionContainers &extraction_containers, - guidance::LaneDescriptionMap &lane_description_map) - : lane_description_map(lane_description_map), external_memory(extraction_containers) +ExtractorCallbacks::ExtractorCallbacks(ExtractionContainers &extraction_containers) + : external_memory(extraction_containers) { // we reserved 0, 1, 2 for the empty case string_map[MapKey("", "")] = 0; // The map should be empty before we start initializing it - BOOST_ASSERT(lane_description_map.empty()); lane_description_map[TurnLaneDescription()] = 0; } @@ -395,5 +393,10 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti OSMNodeID{static_cast(input_way.nodes()[0].ref())}}); } } + +guidance::LaneDescriptionMap &&ExtractorCallbacks::moveOutLaneDescriptionMap() +{ + return std::move(lane_description_map); } -} +} // namespace extractor +} // namespace osrm diff --git a/src/extractor/guidance/intersection_generator.cpp b/src/extractor/guidance/intersection_generator.cpp index e09fa7b48..7402dff13 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 diff --git a/src/extractor/guidance/turn_discovery.cpp b/src/extractor/guidance/turn_discovery.cpp index 5c69e11fc..1f779511b 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 0a92bc90c..564bd9d87 100644 --- a/src/extractor/guidance/turn_lane_augmentation.cpp +++ b/src/extractor/guidance/turn_lane_augmentation.cpp @@ -283,27 +283,18 @@ LaneDataVector handleNoneValueAtSimpleTurn(LaneDataVector lane_data, // we have to reduce it, assigning it to neighboring turns else if (connection_count < lane_data.size()) { - if( connection_count+1 < lane_data.size() ){ - std::cout << "[error] failed assignment" << std::endl; - util::guidance::print(lane_data); - std::cout << "Intersection:\n"; - for( auto road : intersection ) - std::cout << "\t" << toString(road) << std::endl; - } // a pgerequisite is simple turns. Larger differences should not end up here // an additional line at the side is only reasonable if it is targeting public // service vehicles. Otherwise, we should not have it - // - // TODO(mokob): #2730 have a look please - // BOOST_ASSERT(connection_count + 1 == lane_data.size()); - // - if (connection_count + 1 != lane_data.size()) + if (connection_count + 1 == lane_data.size()) { - // skip broken intersections + lane_data = mergeNoneTag(none_index, std::move(lane_data)); } else { - lane_data = mergeNoneTag(none_index, std::move(lane_data)); + // This represents a currently unhandled case. It should not even get here, but to be + // sure we return nevertheless. + return lane_data; } } // we have to rename and possibly augment existing ones. The pure count remains the diff --git a/src/extractor/guidance/turn_lane_data.cpp b/src/extractor/guidance/turn_lane_data.cpp index f08fd81b7..11c287d1f 100644 --- a/src/extractor/guidance/turn_lane_data.cpp +++ b/src/extractor/guidance/turn_lane_data.cpp @@ -154,27 +154,6 @@ bool hasTag(const TurnLaneType::Mask tag, const LaneDataVector &data) return findTag(tag, data) != data.cend(); } -bool isSubsetOf(const LaneDataVector &subset_candidate, const LaneDataVector &superset_candidate) -{ - auto location = superset_candidate.begin(); - for (const auto entry : subset_candidate) - { - location = std::find_if( - location, superset_candidate.end(), [entry](const TurnLaneData &lane_data) { - return lane_data.tag == entry.tag; - }); - - if (location == superset_candidate.end()) - return false; - - // compare the number of lanes TODO this might have be to be revisited for situations where - // a sliproad widens into multiple lanes - if ((location->to - location->from) != (entry.to - entry.from)) - return false; - } - return true; -} - } // namespace lanes } // namespace guidance } // namespace extractor diff --git a/src/extractor/guidance/turn_lane_handler.cpp b/src/extractor/guidance/turn_lane_handler.cpp index edd0cec35..2b553386a 100644 --- a/src/extractor/guidance/turn_lane_handler.cpp +++ b/src/extractor/guidance/turn_lane_handler.cpp @@ -1,9 +1,7 @@ -#include "util/debug.hpp" - +#include "extractor/guidance/turn_lane_handler.hpp" #include "extractor/guidance/constants.hpp" #include "extractor/guidance/turn_discovery.hpp" #include "extractor/guidance/turn_lane_augmentation.hpp" -#include "extractor/guidance/turn_lane_handler.hpp" #include "extractor/guidance/turn_lane_matcher.hpp" #include "util/simple_logger.hpp" #include "util/typedefs.hpp" @@ -33,8 +31,6 @@ std::size_t getNumberOfTurns(const Intersection &intersection) } } // namespace -const constexpr char *TurnLaneHandler::scenario_names[TurnLaneScenario::NUM_SCENARIOS]; - TurnLaneHandler::TurnLaneHandler(const util::NodeBasedDynamicGraph &node_based_graph, std::vector &turn_lane_offsets, std::vector &turn_lane_masks, @@ -46,18 +42,12 @@ TurnLaneHandler::TurnLaneHandler(const util::NodeBasedDynamicGraph &node_based_g turn_lane_masks(turn_lane_masks), lane_description_map(lane_description_map), node_info_list(node_info_list), turn_analysis(turn_analysis), id_map(id_map) { - count_handled = new unsigned; - count_called = new unsigned; - *count_handled = *count_called = 0; } TurnLaneHandler::~TurnLaneHandler() { - std::cout << "Handled: " << *count_handled << " of " << *count_called - << " lanes: " << (double)(*count_handled * 100) / (*count_called) << " %." - << std::endl; - delete count_called; - delete count_handled; + std::cout << "Handled: " << count_handled << " of " << count_called + << " lanes: " << (double)(count_handled * 100) / (count_called) << " %." << std::endl; } /* @@ -107,8 +97,8 @@ TurnLaneHandler::assignTurnLanes(const NodeID at, const EdgeID via_edge, Interse previous_lane_data, previous_description_id); - if (scenario != TurnLaneHandler::NONE) - (*count_called)++; + if (scenario != TurnLaneScenario::NONE) + count_called++; switch (scenario) { @@ -140,44 +130,26 @@ TurnLaneHandler::assignTurnLanes(const NodeID at, const EdgeID via_edge, Interse // case TurnLaneScenario::UNKNOWN: // case TurnLaneScenario::NONE: // case TurnLaneScenario::INVALID: - { - /* - static int print_count = 0; - if (TurnLaneScenario::NONE != scenario && print_count++ < 10) - { - std::cout << "[Unhandled] " << (int)lane_description_id << " -- " - << (int)previous_description_id << "\n" - << std::endl; - util::guidance::printTurnAssignmentData( - at, lane_data, intersection, node_info_list); - - if (previous_node != SPECIAL_NODEID) - util::guidance::printTurnAssignmentData( - previous_node, previous_lane_data, previous_intersection, node_info_list); - } - */ - } return intersection; } } // Find out which scenario we have to handle -TurnLaneHandler::TurnLaneScenario -TurnLaneHandler::deduceScenario(const NodeID at, - const EdgeID via_edge, - const Intersection &intersection, - // Output Variables - LaneDescriptionID &lane_description_id, - LaneDataVector &lane_data, - NodeID &previous_node, - EdgeID &previous_via_edge, - Intersection &previous_intersection, - LaneDataVector &previous_lane_data, - LaneDescriptionID &previous_description_id) +TurnLaneScenario TurnLaneHandler::deduceScenario(const NodeID at, + const EdgeID via_edge, + const Intersection &intersection, + // Output Variables + LaneDescriptionID &lane_description_id, + LaneDataVector &lane_data, + NodeID &previous_node, + EdgeID &previous_via_edge, + Intersection &previous_intersection, + LaneDataVector &previous_lane_data, + LaneDescriptionID &previous_description_id) { // if only a uturn exists, there is nothing we can do if (intersection.size() == 1) - return TurnLaneHandler::NONE; + return TurnLaneScenario::NONE; extractLaneData(via_edge, lane_description_id, lane_data); @@ -199,7 +171,7 @@ TurnLaneHandler::deduceScenario(const NodeID at, angularDeviation(intersection[1].turn.angle, STRAIGHT_ANGLE) < FUZZY_ANGLE_DIFFERENCE)); if (is_going_straight_and_turns_continue) - return TurnLaneHandler::NONE; + return TurnLaneScenario::NONE; // if we see an invalid conversion, we stop immediately if (lane_description_id != INVALID_LANE_DESCRIPTIONID && lane_data.empty()) @@ -694,7 +666,7 @@ Intersection TurnLaneHandler::simpleMatchTuplesToTurns(Intersection intersection !hasTag(TurnLaneType::none | TurnLaneType::merge_to_left | TurnLaneType::merge_to_right, lane_data)); - (*count_handled)++; + count_handled++; return triviallyMatchLanesToTurns( std::move(intersection), lane_data, node_based_graph, lane_description_id, id_map); diff --git a/src/extractor/guidance/turn_lane_matcher.cpp b/src/extractor/guidance/turn_lane_matcher.cpp index 19c916e9d..c15b1beb4 100644 --- a/src/extractor/guidance/turn_lane_matcher.cpp +++ b/src/extractor/guidance/turn_lane_matcher.cpp @@ -1,5 +1,5 @@ -#include "extractor/guidance/toolkit.hpp" #include "extractor/guidance/turn_lane_matcher.hpp" +#include "extractor/guidance/toolkit.hpp" #include "util/guidance/toolkit.hpp" #include @@ -102,11 +102,11 @@ bool isValidMatch(const TurnLaneType::Mask tag, const TurnInstruction instructio return false; } -double getMatchingQuality( const TurnLaneType::Mask tag, const ConnectedRoad &road) +double getMatchingQuality(const TurnLaneType::Mask tag, const ConnectedRoad &road) { const constexpr double idealized_turn_angles[] = {0, 35, 90, 135, 180, 225, 270, 315}; const auto idealized_angle = idealized_turn_angles[getMatchingModifier(tag)]; - return angularDeviation(idealized_angle,road.turn.angle); + return angularDeviation(idealized_angle, road.turn.angle); } // Every tag is somewhat idealized in form of the expected angle. A through lane should go straight @@ -116,21 +116,21 @@ double getMatchingQuality( const TurnLaneType::Mask tag, const ConnectedRoad &ro typename Intersection::const_iterator findBestMatch(const TurnLaneType::Mask tag, const Intersection &intersection) { - return std::min_element( - intersection.begin(), - intersection.end(), - [tag](const ConnectedRoad &lhs, const ConnectedRoad &rhs) { - // prefer valid matches - if (isValidMatch(tag, lhs.turn.instruction) != isValidMatch(tag, rhs.turn.instruction)) - return isValidMatch(tag, lhs.turn.instruction); + return std::min_element(intersection.begin(), + intersection.end(), + [tag](const ConnectedRoad &lhs, const ConnectedRoad &rhs) { + // prefer valid matches + if (isValidMatch(tag, lhs.turn.instruction) != + isValidMatch(tag, rhs.turn.instruction)) + return isValidMatch(tag, lhs.turn.instruction); - // if the entry allowed flags don't match, we select the one with - // entry allowed set to true - if (lhs.entry_allowed != rhs.entry_allowed) - return lhs.entry_allowed; + // if the entry allowed flags don't match, we select the one with + // entry allowed set to true + if (lhs.entry_allowed != rhs.entry_allowed) + return lhs.entry_allowed; - return getMatchingQuality(tag,lhs) < getMatchingQuality(tag,rhs); - }); + return getMatchingQuality(tag, lhs) < getMatchingQuality(tag, rhs); + }); } // Reverse is a special case, because it requires access to the leftmost tag. It has its own @@ -138,8 +138,8 @@ typename Intersection::const_iterator findBestMatch(const TurnLaneType::Mask tag // by default in OSRM. Therefor we cannot check whether a turn is allowed, since it could be // possible that it is forbidden. In addition, the best u-turn angle does not necessarily represent // the u-turn, since it could be a sharp-left turn instead on a road with a middle island. -typename Intersection::const_iterator -findBestMatchForReverse(const TurnLaneType::Mask neighbor_tag, const Intersection &intersection) +typename Intersection::const_iterator findBestMatchForReverse(const TurnLaneType::Mask neighbor_tag, + const Intersection &intersection) { const auto neighbor_itr = findBestMatch(neighbor_tag, intersection); if (neighbor_itr + 1 == intersection.cend()) @@ -159,7 +159,7 @@ findBestMatchForReverse(const TurnLaneType::Mask neighbor_tag, const Intersectio if (lhs.entry_allowed != rhs.entry_allowed) return lhs.entry_allowed; - return getMatchingQuality(tag,lhs) < getMatchingQuality(tag,rhs); + return getMatchingQuality(tag, lhs) < getMatchingQuality(tag, rhs); }); }