From ee5020baf3ee83b06320b95ecef16ec18eab4e75 Mon Sep 17 00:00:00 2001 From: Moritz Kobitzsch Date: Wed, 16 Mar 2016 15:47:33 +0100 Subject: [PATCH] less new names, forks consider road classes, api clean-up --- features/guidance/roundabout.feature | 140 ++++++++++++++++++ .../extractor/edge_based_graph_factory.hpp | 6 +- include/extractor/guidance/toolkit.hpp | 70 +++++++++ include/extractor/guidance/turn_analysis.hpp | 6 +- include/util/name_table.hpp | 26 ++++ src/engine/api/json_factory.cpp | 39 ++--- src/extractor/edge_based_graph_factory.cpp | 16 +- src/extractor/extractor.cpp | 5 +- src/extractor/guidance/turn_analysis.cpp | 76 +++++++++- src/util/name_table.cpp | 52 +++++++ 10 files changed, 392 insertions(+), 44 deletions(-) create mode 100644 features/guidance/roundabout.feature create mode 100644 include/util/name_table.hpp create mode 100644 src/util/name_table.cpp diff --git a/features/guidance/roundabout.feature b/features/guidance/roundabout.feature new file mode 100644 index 000000000..04a92eab4 --- /dev/null +++ b/features/guidance/roundabout.feature @@ -0,0 +1,140 @@ +@routing @guidance +Feature: Basic Roundabout + + Background: + Given the profile "testbot" + Given a grid size of 10 meters + + Scenario: Enter and Exit + Given the node map + | | | a | | | + | | | b | | | + | h | g | | c | d | + | | | e | | | + | | | f | | | + + And the ways + | nodes | roundabout | + | ab | false | + | cd | false | + | ef | false | + | gh | false | + | bcegb | true | + + When I route I should get + | waypoints | route | turns | + | a,d | ab,cd,cd | depart, roundabout-exit-1, arrive | + | a,f | ab,ef,ef | depart, roundabout-exit-2, arrive | + | a,h | ab,gh,gh | depart, roundabout-exit-3, arrive | + | d,f | cd,ef,ef | depart, roundabout-exit-1, arrive | + | d,h | cd,gh,gh | depart, roundabout-exit-2, arrive | + | d,a | cd,ab,ab | depart, roundabout-exit-3, arrive | + | f,h | ef,gh,gh | depart, roundabout-exit-1, arrive | + | f,a | ef,ab,ab | depart, roundabout-exit-2, arrive | + | f,d | ef,cd,cd | depart, roundabout-exit-3, arrive | + | h,a | gh,ab,ab | depart, roundabout-exit-1, arrive | + | h,d | gh,cd,cd | depart, roundabout-exit-2, arrive | + | h,f | gh,ef,ef | depart, roundabout-exit-3, arrive | + + Scenario: Only Enter + Given the node map + | | | a | | | + | | | b | | | + | h | g | | c | d | + | | | e | | | + | | | f | | | + + And the ways + | nodes | roundabout | + | ab | false | + | cd | false | + | ef | false | + | gh | false | + | bcegb | true | + + When I route I should get + | waypoints | route | turns | + | a,b | ab,ab | depart, arrive | + | a,c | ab,bcegb | depart, roundabout-enter, arrive | + | a,e | ab,bcegb | depart, roundabout-enter, arrive | + | a,g | ab,bcegb | depart, roundabout-enter, arrive | + | d,c | cd,cd | depart, arrive | + | d,e | cd,bcegb | depart, roundabout-enter, arrive | + | d,g | cd,bcegb | depart, roundabout-enter, arrive | + | d,b | cd,bcegb | depart, roundabout-enter, arrive | + | f,e | ef,ef | depart, arrive | + | f,g | ef,bcegb | depart, roundabout-enter, arrive | + | f,b | ef,bcegb | depart, roundabout-enter, arrive | + | f,c | ef,bcegb | depart, roundabout-enter, arrive | + | h,g | gh,gh | depart, arrive | + | h,b | gh,bcegb | depart, roundabout-enter, arrive | + | h,c | gh,bcegb | depart, roundabout-enter, arrive | + | h,e | gh,bcegb | depart, roundabout-enter, arrive | + + Scenario: Only Exit + Given the node map + | | | a | | | + | | | b | | | + | h | g | | c | d | + | | | e | | | + | | | f | | | + + And the ways + | nodes | roundabout | + | ab | false | + | cd | false | + | ef | false | + | gh | false | + | bcegb | true | + + When I route I should get + | waypoints | route | turns | + | b,a | ab,ab | depart, arrive | + | b,d | bcegb,cd,cd | depart, roundabout-exit-1, arrive | + | b,f | bcegb,ef,ef | depart, roundabout-exit-2, arrive | + | b,h | bcegb,gh,gh | depart, roundabout-exit-3, arrive | + | c,d | cd,cd | depart, arrive | + | c,f | bcegb,ef,ef | depart, roundabout-exit-1, arrive | + | c,h | bcegb,gh,gh | depart, roundabout-exit-2, arrive | + | c,a | bcegb,ab,ab | depart, roundabout-exit-3, arrive | + | e,f | ef,ef | depart, arrive | + | e,h | bcegb,gh,gh | depart, roundabout-exit-1, arrive | + | e,a | bcegb,ab,ab | depart, roundabout-exit-2, arrive | + | e,d | bcegb,cd,cd | depart, roundabout-exit-3, arrive | + | g,h | gh,gh | depart, arrive | + | g,a | bcegb,ab,ab | depart, roundabout-exit-1, arrive | + | g,d | bcegb,cd,cd | depart, roundabout-exit-2, arrive | + | g,f | bcegb,ef,ef | depart, roundabout-exit-3, arrive | + + Scenario: Drive Around + Given the node map + | | | a | | | + | | | b | | | + | h | g | | c | d | + | | | e | | | + | | | f | | | + + And the ways + | nodes | roundabout | + | ab | false | + | cd | false | + | ef | false | + | gh | false | + | bcegb | true | + + When I route I should get + | waypoints | route | turns | + | b,c | bcegb,bcegb | depart, arrive | + | b,e | bcegb,bcegb | depart, arrive | + | b,g | bcegb,bcegb | depart, arrive | + | c,e | bcegb,bcegb | depart, arrive | + | c,g | bcegb,bcegb | depart, arrive | + | c,b | bcegb,bcegb | depart, arrive | + | e,g | bcegb,bcegb | depart, arrive | + | e,b | bcegb,bcegb | depart, arrive | + | e,c | bcegb,bcegb | depart, arrive | + | g,b | bcegb,bcegb | depart, arrive | + | g,c | bcegb,bcegb | depart, arrive | + | g,e | bcegb,bcegb | depart, arrive | + + Scenario: Mixed Entry and Exit diff --git a/include/extractor/edge_based_graph_factory.hpp b/include/extractor/edge_based_graph_factory.hpp index ede4deb02..a6765dc67 100644 --- a/include/extractor/edge_based_graph_factory.hpp +++ b/include/extractor/edge_based_graph_factory.hpp @@ -17,6 +17,7 @@ #include "util/node_based_graph.hpp" #include "util/typedefs.hpp" #include "util/deallocating_vector.hpp" +#include "util/name_table.hpp" #include #include @@ -51,7 +52,8 @@ class EdgeBasedGraphFactory const std::unordered_set &traffic_lights, std::shared_ptr restriction_map, const std::vector &node_info_list, - SpeedProfileProperties speed_profile); + SpeedProfileProperties speed_profile, + const util::NameTable &name_table); void Run(const std::string &original_edge_data_filename, lua_State *lua_state, @@ -106,6 +108,8 @@ class EdgeBasedGraphFactory SpeedProfileProperties speed_profile; + const util::NameTable &name_table; + void CompressGeometry(); unsigned RenumberEdges(); void GenerateEdgeExpandedNodes(); diff --git a/include/extractor/guidance/toolkit.hpp b/include/extractor/guidance/toolkit.hpp index 54ee38430..43d168d8a 100644 --- a/include/extractor/guidance/toolkit.hpp +++ b/include/extractor/guidance/toolkit.hpp @@ -12,9 +12,12 @@ #include "extractor/guidance/classification_data.hpp" #include "extractor/guidance/turn_instruction.hpp" +#include #include #include #include +#include +#include namespace osrm { @@ -331,6 +334,73 @@ inline bool isDistinct(const DirectionModifier first, const DirectionModifier se return true; } +inline bool requiresNameAnnounced(const std::string &from, const std::string &to) +{ + // FIXME, handle in profile to begin with? + // this uses the encoding of references in the profile, which is very BAD + // Input for this function should be a struct separating streetname, suffix (e.g. road, + // boulevard, North, West ...), and a list of references + std::string from_name = "", from_ref = "", to_name = "", to_ref = ""; + + auto split = [](const std::string &name, std::string &out_name, std::string &out_ref) + { + const auto ref_begin = name.find_first_of('('); + if (ref_begin != std::string::npos) + { + out_name = name.substr(0, ref_begin); + out_ref = name.substr(ref_begin + 1, name.find_first_of(')') - 1); + } + else + { + out_name = name; + out_ref = ""; + } + }; + + split(from, from_name, from_ref); + split(to, to_name, to_ref); + + // check similarity of names + if (from_name != "" && to_name != "") + { + if ((from_name.back() >= '0' && from_name.back() <= '9') || + (to_name.back() >= '0' && to_name.back() <= '9')) + return from_name != to_name; + if (from.find("Weg ") == 0 && to_name.find("Weg ") == 0) + return from_name != to_name; + auto from_itr = from_name.begin(); + auto to_itr = to_name.begin(); + for (; from_itr != from_name.end() && to_itr != to_name.end() && *from_itr == *to_itr; + ++to_itr, ++from_itr) + { + /* do nothing */ + } + + const auto common_length = std::distance(from_name.begin(), from_itr); + return (100 * common_length / std::min(to_name.length(), from_name.length())) < 80; + } + else if (from_ref != "" && to_ref != "") + { + // references are contained in one another + if (from_ref.find(to_ref) != std::string::npos || + to_ref.find(from_ref) != std::string::npos) + return false; + } + return true; +} + +inline int getPriority( const FunctionalRoadClass road_class ) +{ + const constexpr int road_priority[] = {10, 0, 10, 2, 10, 4, 10, 6, 10, 8, 10, 11, 10, 12, 10, 14}; + return road_priority[static_cast(road_class)]; +} + +inline bool canBeSeenAsFork(const FunctionalRoadClass first, const FunctionalRoadClass second) +{ + // forks require similar road categories + return std::abs(getPriority(first) - getPriority(second)) <= 1; +} + } // namespace guidance } // namespace extractor } // namespace osrm diff --git a/include/extractor/guidance/turn_analysis.hpp b/include/extractor/guidance/turn_analysis.hpp index ddbce9e3a..a2c3a4a08 100644 --- a/include/extractor/guidance/turn_analysis.hpp +++ b/include/extractor/guidance/turn_analysis.hpp @@ -6,6 +6,8 @@ #include "extractor/restriction_map.hpp" #include "extractor/compressed_edge_container.hpp" +#include "util/name_table.hpp" + #include #include @@ -53,7 +55,8 @@ class TurnAnalysis const std::vector &node_info_list, const RestrictionMap &restriction_map, const std::unordered_set &barrier_nodes, - const CompressedEdgeContainer &compressed_edge_container); + const CompressedEdgeContainer &compressed_edge_container, + const util::NameTable &name_table); // the entry into the turn analysis std::vector getTurns(const NodeID from_node, const EdgeID via_eid) const; @@ -64,6 +67,7 @@ class TurnAnalysis const RestrictionMap &restriction_map; const std::unordered_set &barrier_nodes; const CompressedEdgeContainer &compressed_edge_container; + const util::NameTable &name_table; // Check for restrictions/barriers and generate a list of valid and invalid turns present at the // node reached diff --git a/include/util/name_table.hpp b/include/util/name_table.hpp new file mode 100644 index 000000000..83cde87a3 --- /dev/null +++ b/include/util/name_table.hpp @@ -0,0 +1,26 @@ +#ifndef OSRM_UTIL_NAME_TABLE_HPP +#define OSRM_UTIL_NAME_TABLE_HPP + +#include "util/shared_memory_vector_wrapper.hpp" +#include "util/range_table.hpp" + +#include + +namespace osrm +{ +namespace util +{ +class NameTable +{ + private: + //FIXME should this use shared memory + RangeTable<16, false> m_name_table; + ShM::vector m_names_char_list; + public: + NameTable( const std::string &filename ); + std::string get_name_for_id(const unsigned name_id) const; +}; +} // namespace util +} // namespace osrm + +#endif // OSRM_UTIL_NAME_TABLE_HPP diff --git a/src/engine/api/json_factory.cpp b/src/engine/api/json_factory.cpp index 93723cf87..85f8e8478 100644 --- a/src/engine/api/json_factory.cpp +++ b/src/engine/api/json_factory.cpp @@ -28,17 +28,23 @@ namespace json namespace detail { -const constexpr char *modifier_names[] = {"uturn", "sharp right", "right", "slight right", - "straight", "slight left", "left", "sharp left"}; +const constexpr char *modifier_names[] = {"uturn", + "sharp right", + "right", + "slight right", + "straight", + "slight left", + "left", + "sharp left"}; // translations of TurnTypes. Not all types are exposed to the outside world. // invalid types should never be returned as part of the API const constexpr char *turn_type_names[] = { - "invalid", "no turn", "invalid", "new name", "continue", "turn", - "turn", "turn", "turn", "merge", "ramp", "ramp", - "ramp", "ramp", "fork", "end of road", "roundabout", "invalid", - "roundabout", "invalid", "traffic circle", "invalid", "traffic circle", "invalid", - "invalid", "restriction", "notification"}; + "invalid", "no turn", "invalid", "new name", "continue", "turn", + "turn", "turn", "turn", "turn", "merge", "ramp", + "ramp", "ramp", "ramp", "ramp", "fork", "end of road", + "roundabout", "invalid", "roundabout", "invalid", "traffic circle", "invalid", + "traffic circle", "invalid", "invalid", "restriction", "notification"}; const constexpr char *waypoint_type_names[] = {"invalid", "arrive", "depart"}; // Check whether to include a modifier in the result of the API @@ -50,23 +56,6 @@ inline bool isValidModifier(const guidance::StepManeuver maneuver) return true; } -inline bool isMultiTurn(const TurnType type) -{ - return (type == TurnType::FirstTurn || type == TurnType::SecondTurn || - type == TurnType::ThirdTurn); -} - -inline std::string getCount(const TurnType type) -{ - if (type == TurnType::FirstTurn) - return "1"; - if (type == TurnType::SecondTurn) - return "2"; - if (type == TurnType::ThirdTurn) - return "3"; - return "0"; -} - std::string instructionTypeToString(const TurnType type) { return turn_type_names[static_cast(type)]; @@ -152,8 +141,6 @@ util::json::Object makeStepManeuver(const guidance::StepManeuver &maneuver) else step_maneuver.values["type"] = detail::waypointTypeToString(maneuver.waypoint_type); - if (detail::isMultiTurn(maneuver.instruction.type)) - step_maneuver.values["count"] = detail::getCount(maneuver.instruction.type); if (detail::isValidModifier(maneuver)) step_maneuver.values["modifier"] = detail::instructionModifierToString(maneuver.instruction.direction_modifier); diff --git a/src/extractor/edge_based_graph_factory.cpp b/src/extractor/edge_based_graph_factory.cpp index 5c2626736..1b3dea5bb 100644 --- a/src/extractor/edge_based_graph_factory.cpp +++ b/src/extractor/edge_based_graph_factory.cpp @@ -34,12 +34,13 @@ EdgeBasedGraphFactory::EdgeBasedGraphFactory( const std::unordered_set &traffic_lights, std::shared_ptr restriction_map, const std::vector &node_info_list, - SpeedProfileProperties speed_profile) + SpeedProfileProperties speed_profile, + const util::NameTable &name_table) : m_max_edge_id(0), m_node_info_list(node_info_list), m_node_based_graph(std::move(node_based_graph)), m_restriction_map(std::move(restriction_map)), m_barrier_nodes(barrier_nodes), m_traffic_lights(traffic_lights), m_compressed_edge_container(compressed_edge_container), - speed_profile(std::move(speed_profile)) + speed_profile(std::move(speed_profile)), name_table(name_table) { } @@ -123,10 +124,9 @@ void EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u, const NodeI // traverse arrays from start and end respectively for (const auto i : util::irange(0UL, geometry_size)) { - BOOST_ASSERT( - current_edge_source_coordinate_id == - m_compressed_edge_container.GetBucketReference(edge_id_2)[geometry_size - 1 - i] - .node_id); + BOOST_ASSERT(current_edge_source_coordinate_id == + m_compressed_edge_container.GetBucketReference( + edge_id_2)[geometry_size - 1 - i].node_id); const NodeID current_edge_target_coordinate_id = forward_geometry[i].node_id; BOOST_ASSERT(current_edge_target_coordinate_id != current_edge_source_coordinate_id); @@ -302,8 +302,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( // Three nested loop look super-linear, but we are dealing with a (kind of) // linear number of turns only. util::Percent progress(m_node_based_graph->GetNumberOfNodes()); - guidance::TurnAnalysis turn_analysis( *m_node_based_graph, m_node_info_list, - *m_restriction_map, m_barrier_nodes, m_compressed_edge_container ); + guidance::TurnAnalysis turn_analysis(*m_node_based_graph, m_node_info_list, *m_restriction_map, + m_barrier_nodes, m_compressed_edge_container, name_table); for (const auto node_u : util::irange(0u, m_node_based_graph->GetNumberOfNodes())) { // progress.printStatus(node_u); diff --git a/src/extractor/extractor.cpp b/src/extractor/extractor.cpp index 7123bfce7..3e84fd30d 100644 --- a/src/extractor/extractor.cpp +++ b/src/extractor/extractor.cpp @@ -15,6 +15,7 @@ #include "util/timing_util.hpp" #include "util/lua_util.hpp" #include "util/graph_loader.hpp" +#include "util/name_table.hpp" #include "util/typedefs.hpp" @@ -521,10 +522,12 @@ Extractor::BuildEdgeExpandedGraph(std::vector &internal_to_external_n compressed_edge_container.SerializeInternalVector(config.geometry_output_path); + util::NameTable name_table(config.names_file_name); + EdgeBasedGraphFactory edge_based_graph_factory( node_based_graph, compressed_edge_container, barrier_nodes, traffic_lights, std::const_pointer_cast(restriction_map), - internal_to_external_node_map, speed_profile); + internal_to_external_node_map, speed_profile, name_table); edge_based_graph_factory.Run(config.edge_output_path, lua_state, config.edge_segment_lookup_path, config.edge_penalty_path, diff --git a/src/extractor/guidance/turn_analysis.cpp b/src/extractor/guidance/turn_analysis.cpp index afbefadb5..2e7a0e1ed 100644 --- a/src/extractor/guidance/turn_analysis.cpp +++ b/src/extractor/guidance/turn_analysis.cpp @@ -55,10 +55,11 @@ TurnAnalysis::TurnAnalysis(const util::NodeBasedDynamicGraph &node_based_graph, const std::vector &node_info_list, const RestrictionMap &restriction_map, const std::unordered_set &barrier_nodes, - const CompressedEdgeContainer &compressed_edge_container) + const CompressedEdgeContainer &compressed_edge_container, + const util::NameTable &name_table) : node_based_graph(node_based_graph), node_info_list(node_info_list), restriction_map(restriction_map), barrier_nodes(barrier_nodes), - compressed_edge_container(compressed_edge_container) + compressed_edge_container(compressed_edge_container), name_table(name_table) { } @@ -784,7 +785,9 @@ TurnInstruction TurnAnalysis::getInstructionForObvious(const std::size_t num_can { const auto &in_data = node_based_graph.GetEdgeData(via_edge); const auto &out_data = node_based_graph.GetEdgeData(candidate.eid); - if (in_data.name_id != out_data.name_id) + if (in_data.name_id != out_data.name_id && + requiresNameAnnounced(name_table.get_name_for_id(in_data.name_id), + name_table.get_name_for_id(out_data.name_id))) return {TurnType::NewName, getTurnDirection(candidate.angle)}; else return {TurnType::Suppressed, getTurnDirection(candidate.angle)}; @@ -859,6 +862,7 @@ std::vector TurnAnalysis::handleThreeWayTurn( angularDeviation(turn.angle, STRAIGHT_ANGLE) > 1.4); }; + /* Two nearly straight turns -> FORK OOOOOOO / @@ -871,7 +875,26 @@ std::vector TurnAnalysis::handleThreeWayTurn( { if (turn_candidates[1].valid && turn_candidates[2].valid) { - assignFork(via_edge, turn_candidates[2], turn_candidates[1]); + const auto left_class = + node_based_graph.GetEdgeData(turn_candidates[2].eid).road_classification.road_class; + const auto right_class = + node_based_graph.GetEdgeData(turn_candidates[1].eid).road_classification.road_class; + if (canBeSeenAsFork(left_class, right_class)) + assignFork(via_edge, turn_candidates[2], turn_candidates[1]); + else if (getPriority(left_class) > getPriority(right_class)) + { + turn_candidates[1].instruction = + getInstructionForObvious(turn_candidates.size(), via_edge, turn_candidates[1]); + turn_candidates[2].instruction = {findBasicTurnType(via_edge, turn_candidates[2]), + DirectionModifier::SlightLeft}; + } + else + { + turn_candidates[2].instruction = + getInstructionForObvious(turn_candidates.size(), via_edge, turn_candidates[2]); + turn_candidates[1].instruction = {findBasicTurnType(via_edge, turn_candidates[1]), + DirectionModifier::SlightRight}; + } } else { @@ -1073,7 +1096,27 @@ void TurnAnalysis::handleDistinctConflict(const EdgeID via_edge, if (getTurnDirection(left.angle) == DirectionModifier::Straight || getTurnDirection(left.angle) == DirectionModifier::SlightLeft || getTurnDirection(right.angle) == DirectionModifier::SlightRight) - assignFork(via_edge, left, right); + { + const auto left_class = + node_based_graph.GetEdgeData(left.eid).road_classification.road_class; + const auto right_class = + node_based_graph.GetEdgeData(right.eid).road_classification.road_class; + if (canBeSeenAsFork(left_class, right_class)) + assignFork(via_edge, left, right); + else if (getPriority(left_class) > getPriority(right_class)) + { + // FIXME this should possibly know about the actual candidates? + right.instruction = getInstructionForObvious(4, via_edge, right); + left.instruction = {findBasicTurnType(via_edge, left), DirectionModifier::SlightLeft}; + } + else + { + // FIXME this should possibly know about the actual candidates? + left.instruction = getInstructionForObvious(4, via_edge, left); + right.instruction = {findBasicTurnType(via_edge, right), + DirectionModifier::SlightRight}; + } + } const auto left_type = findBasicTurnType(via_edge, left); const auto right_type = findBasicTurnType(via_edge, right); @@ -1196,8 +1239,27 @@ std::vector TurnAnalysis::handleComplexTurn( { if (fork_range.second - fork_range.first == 1) { - assignFork(via_edge, turn_candidates[fork_range.second], - turn_candidates[fork_range.first]); + auto &left = turn_candidates[fork_range.second]; + auto &right = turn_candidates[fork_range.first]; + const auto left_class = + node_based_graph.GetEdgeData(left.eid).road_classification.road_class; + const auto right_class = + node_based_graph.GetEdgeData(right.eid).road_classification.road_class; + if (canBeSeenAsFork(left_class, right_class)) + assignFork(via_edge, left, right); + else if (getPriority(left_class) > getPriority(right_class)) + { + right.instruction = + getInstructionForObvious(turn_candidates.size(), via_edge, right); + left.instruction = {findBasicTurnType(via_edge, left), + DirectionModifier::SlightLeft}; + } + else + { + left.instruction = getInstructionForObvious(turn_candidates.size(), via_edge, left); + right.instruction = {findBasicTurnType(via_edge, right), + DirectionModifier::SlightRight}; + } } else if (fork_range.second - fork_range.second == 2) { diff --git a/src/util/name_table.cpp b/src/util/name_table.cpp new file mode 100644 index 000000000..ca42f8b14 --- /dev/null +++ b/src/util/name_table.cpp @@ -0,0 +1,52 @@ +#include "util/name_table.hpp" +#include "util/simple_logger.hpp" + +#include +#include +#include + +#include + +namespace osrm +{ +namespace util +{ + +NameTable::NameTable(const std::string &filename) +{ + boost::filesystem::ifstream name_stream(filename, std::ios::binary); + + name_stream >> m_name_table; + + unsigned number_of_chars = 0; + name_stream.read(reinterpret_cast(&number_of_chars), sizeof(number_of_chars)); + BOOST_ASSERT_MSG(0 != number_of_chars, "name file broken"); + m_names_char_list.resize(number_of_chars + 1); //+1 gives sentinel element + name_stream.read(reinterpret_cast(&m_names_char_list[0]), + number_of_chars * sizeof(m_names_char_list[0])); + if (0 == m_names_char_list.size()) + { + util::SimpleLogger().Write(logWARNING) << "list of street names is empty"; + } +} + +std::string NameTable::get_name_for_id(const unsigned name_id) const +{ + if (std::numeric_limits::max() == name_id) + { + return ""; + } + auto range = m_name_table.GetRange(name_id); + + std::string result; + result.reserve(range.size()); + if (range.begin() != range.end()) + { + result.resize(range.back() - range.front() + 1); + std::copy(m_names_char_list.begin() + range.front(), + m_names_char_list.begin() + range.back() + 1, result.begin()); + } + return result; +} +} // namespace util +} // namespace osrm