From a154d7184143b74800e3a53099a28baecbc8159c Mon Sep 17 00:00:00 2001 From: Moritz Kobitzsch Date: Fri, 22 Apr 2016 11:31:46 +0200 Subject: [PATCH] enable suppression name suffix changes --- CHANGELOG.md | 5 + features/guidance/suffix-changes.feature | 62 +++++++++++++ include/engine/guidance/assemble_steps.hpp | 2 +- include/engine/guidance/toolkit.hpp | 4 +- .../guidance/intersection_handler.hpp | 5 +- .../extractor/guidance/motorway_handler.hpp | 3 +- .../extractor/guidance/roundabout_handler.hpp | 3 +- include/extractor/guidance/toolkit.hpp | 53 ++++++++++- include/extractor/guidance/turn_analysis.hpp | 4 +- include/extractor/guidance/turn_handler.hpp | 3 +- include/extractor/suffix_table.hpp | 30 ++++++ profiles/car.lua | 9 ++ scripts/check_taginfo.py | 3 + src/engine/guidance/post_processing.cpp | 91 ++++++++----------- src/extractor/edge_based_graph_factory.cpp | 5 +- .../guidance/intersection_handler.cpp | 9 +- src/extractor/guidance/motorway_handler.cpp | 5 +- src/extractor/guidance/roundabout_handler.cpp | 16 ++-- src/extractor/guidance/turn_analysis.cpp | 9 +- src/extractor/guidance/turn_handler.cpp | 24 ++--- src/extractor/suffix_table.cpp | 48 ++++++++++ 21 files changed, 298 insertions(+), 95 deletions(-) create mode 100644 features/guidance/suffix-changes.feature create mode 100644 include/extractor/suffix_table.hpp create mode 100644 src/extractor/suffix_table.cpp diff --git a/CHANGELOG.md b/CHANGELOG.md index 37da17d4d..63cd9c6a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ - API: - added roundabout-turn instruction. The instruction indicates a small roundabout that is treated as an intersection (turn right at the roundabout for first exit, go straight at the roundabout...) + - reduced new name instructions for trivial changes + - combined multiple turns into a single instruction at segregated roads` + + - Profile Changes: + - introduced a suffix_list / get_name_suffix_list to specify name suffices to be suppressed in name change announcements - Infrastructure - BREAKING: reordered internal instruction types. This breaks the data format diff --git a/features/guidance/suffix-changes.feature b/features/guidance/suffix-changes.feature new file mode 100644 index 000000000..e389506db --- /dev/null +++ b/features/guidance/suffix-changes.feature @@ -0,0 +1,62 @@ +@routing @guidance +Feature: Suppress New Names on dedicated Suffices + + Background: + Given the profile "car" + Given a grid size of 10 meters + + Scenario: Suffix To Suffix + Given the node map + | a | | b | | c | + + And the ways + | nodes | name | + | ab | 42 N | + | bc | 42 S | + + When I route I should get + | waypoints | route | turns | + | a,c | 42 N,42 S | depart,arrive | + + Scenario: Suffix To Suffix - Turn + Given the node map + | a | | b | | c | + | | | d | | | + + And the ways + | nodes | name | + | ab | 42 N | + | bc | 42 S | + | bd | 42 E | + + When I route I should get + | waypoints | route | turns | + | a,c | 42 N,42 S | depart,arrive | + | a,d | 42 N,42 E,42 E | depart,turn right,arrive | + + Scenario: Suffix To No Suffix + Given the node map + | a | | b | | c | + + And the ways + | nodes | name | + | ab | 42 N | + | bc | 42 | + + When I route I should get + | waypoints | route | turns | + | a,c | 42 N,42 | depart,arrive | + + Scenario: No Suffix To Suffix + Given the node map + | a | | b | | c | + + And the ways + | nodes | name | + | ab | 42 | + | bc | 42 S | + + When I route I should get + | waypoints | route | turns | + | a,c | 42,42 S | depart,arrive | + diff --git a/include/engine/guidance/assemble_steps.hpp b/include/engine/guidance/assemble_steps.hpp index f33b6901e..d798f04ad 100644 --- a/include/engine/guidance/assemble_steps.hpp +++ b/include/engine/guidance/assemble_steps.hpp @@ -79,7 +79,7 @@ std::vector assembleSteps(const DataFacadeT &facade, // some name changes are not announced in our processing. For these, we have to keep the // first name on the segment - unsigned step_name_id = source_node.name_id; + auto step_name_id = source_node.name_id; for (std::size_t leg_data_index = 0; leg_data_index < leg_data.size(); ++leg_data_index) { const auto &path_point = leg_data[leg_data_index]; diff --git a/include/engine/guidance/toolkit.hpp b/include/engine/guidance/toolkit.hpp index 43ca72ec6..f3d534f69 100644 --- a/include/engine/guidance/toolkit.hpp +++ b/include/engine/guidance/toolkit.hpp @@ -65,8 +65,8 @@ inline extractor::guidance::DirectionModifier angleToDirectionModifier(const dou inline double angularDeviation(const double angle, const double from) { - const double deviation = std::abs(angle - from); - return std::min(360 - deviation, deviation); + const double deviation = std::abs(angle - from); + return std::min(360 - deviation, deviation); } } // namespace guidance diff --git a/include/extractor/guidance/intersection_handler.hpp b/include/extractor/guidance/intersection_handler.hpp index f532f8b07..f1d498139 100644 --- a/include/extractor/guidance/intersection_handler.hpp +++ b/include/extractor/guidance/intersection_handler.hpp @@ -3,6 +3,7 @@ #include "extractor/guidance/intersection.hpp" #include "extractor/query_node.hpp" +#include "extractor/suffix_table.hpp" #include "util/name_table.hpp" #include "util/node_based_graph.hpp" @@ -26,7 +27,8 @@ class IntersectionHandler public: IntersectionHandler(const util::NodeBasedDynamicGraph &node_based_graph, const std::vector &node_info_list, - const util::NameTable &name_table); + const util::NameTable &name_table, + const SuffixTable &street_name_suffix_table); virtual ~IntersectionHandler(); // check whether the handler can actually handle the intersection @@ -41,6 +43,7 @@ class IntersectionHandler const util::NodeBasedDynamicGraph &node_based_graph; const std::vector &node_info_list; const util::NameTable &name_table; + const SuffixTable &street_name_suffix_table; // counts the number on allowed entry roads std::size_t countValid(const Intersection &intersection) const; diff --git a/include/extractor/guidance/motorway_handler.hpp b/include/extractor/guidance/motorway_handler.hpp index 7be3bf470..42805c5cb 100644 --- a/include/extractor/guidance/motorway_handler.hpp +++ b/include/extractor/guidance/motorway_handler.hpp @@ -24,7 +24,8 @@ class MotorwayHandler : public IntersectionHandler public: MotorwayHandler(const util::NodeBasedDynamicGraph &node_based_graph, const std::vector &node_info_list, - const util::NameTable &name_table); + const util::NameTable &name_table, + const SuffixTable &street_name_suffix_table); ~MotorwayHandler() override final; // check whether the handler can actually handle the intersection diff --git a/include/extractor/guidance/roundabout_handler.hpp b/include/extractor/guidance/roundabout_handler.hpp index cd6ae5a5e..055982a82 100644 --- a/include/extractor/guidance/roundabout_handler.hpp +++ b/include/extractor/guidance/roundabout_handler.hpp @@ -40,8 +40,9 @@ class RoundaboutHandler : public IntersectionHandler public: RoundaboutHandler(const util::NodeBasedDynamicGraph &node_based_graph, const std::vector &node_info_list, + const CompressedEdgeContainer &compressed_edge_container, const util::NameTable &name_table, - const CompressedEdgeContainer &compressed_edge_container); + const SuffixTable &street_name_suffix_table); ~RoundaboutHandler() override final; diff --git a/include/extractor/guidance/toolkit.hpp b/include/extractor/guidance/toolkit.hpp index 1627105cc..c80ef4205 100644 --- a/include/extractor/guidance/toolkit.hpp +++ b/include/extractor/guidance/toolkit.hpp @@ -8,6 +8,7 @@ #include "extractor/compressed_edge_container.hpp" #include "extractor/query_node.hpp" +#include "extractor/suffix_table.hpp" #include "extractor/guidance/classification_data.hpp" #include "extractor/guidance/discrete_angle.hpp" @@ -20,6 +21,7 @@ #include #include +#include #include namespace osrm @@ -305,7 +307,9 @@ inline bool isDistinct(const DirectionModifier first, const DirectionModifier se return true; } -inline bool requiresNameAnnounced(const std::string &from, const std::string &to) +inline bool requiresNameAnnounced(const std::string &from, + const std::string &to, + const SuffixTable &suffix_table) { // FIXME, handle in profile to begin with? // this uses the encoding of references in the profile, which is very BAD @@ -332,12 +336,19 @@ inline bool requiresNameAnnounced(const std::string &from, const std::string &to } }; + const auto getCommonLength = [](const std::string &first, const std::string &second) { + BOOST_ASSERT(first.size() <= second.size()); + const auto mismatch_result = std::mismatch(first.begin(), first.end(), second.begin()); + return std::distance(first.begin(), mismatch_result.first); + }; + split(from, from_name, from_ref); split(to, to_name, to_ref); // check similarity of names const auto names_are_empty = from_name.empty() && to_name.empty(); - const auto name_is_contained = boost::starts_with(from_name,to_name) || boost::starts_with(to_name,from_name); + const auto name_is_contained = + boost::starts_with(from_name, to_name) || boost::starts_with(to_name, from_name); const auto names_are_equal = from_name == to_name || name_is_contained; const auto name_is_removed = !from_name.empty() && to_name.empty(); // references are contained in one another @@ -347,9 +358,41 @@ inline bool requiresNameAnnounced(const std::string &from, const std::string &to (from_ref.find(to_ref) != std::string::npos || to_ref.find(from_ref) != std::string::npos); const auto ref_is_removed = !from_ref.empty() && to_ref.empty(); - const auto obvious_change = - (names_are_empty && refs_are_empty) || (names_are_equal && ref_is_contained) || - (names_are_equal && refs_are_empty) || name_is_removed || ref_is_removed; + const auto checkForSuffixChange = [](const std::size_t common_length, const std::string &first, + const std::string &second, + const SuffixTable &suffix_table) { + if (0 == common_length) + return false; + + const auto endsOnSuffix = [](const std::size_t trim_length, + const std::string &string_with_possible_suffix, + const SuffixTable &suffix_table) { + auto suffix = + string_with_possible_suffix.size() > trim_length + ? string_with_possible_suffix.substr( + trim_length + (string_with_possible_suffix[trim_length] == ' ' ? 1 : 0)) + : " "; + boost::algorithm::to_lower(suffix); + return suffix.empty() || suffix_table.isSuffix(suffix); + }; + + const auto first_delta_is_suffix = endsOnSuffix(common_length, first, suffix_table); + const auto second_delta_is_suffix = endsOnSuffix(common_length, second, suffix_table); + + return first_delta_is_suffix && second_delta_is_suffix; + }; + + const auto common_length = from_name.size() < to_name.size() + ? getCommonLength(from_name, to_name) + : getCommonLength(to_name, from_name); + + const auto is_suffix_change = + checkForSuffixChange(common_length, from_name, to_name, suffix_table); + + const auto obvious_change = (names_are_empty && refs_are_empty) || + (names_are_equal && ref_is_contained) || + (names_are_equal && refs_are_empty) || name_is_removed || + ref_is_removed || is_suffix_change; return !obvious_change; } diff --git a/include/extractor/guidance/turn_analysis.hpp b/include/extractor/guidance/turn_analysis.hpp index 3356c0544..3f202f3dd 100644 --- a/include/extractor/guidance/turn_analysis.hpp +++ b/include/extractor/guidance/turn_analysis.hpp @@ -11,6 +11,7 @@ #include "extractor/guidance/turn_handler.hpp" #include "extractor/query_node.hpp" #include "extractor/restriction_map.hpp" +#include "extractor/suffix_table.hpp" #include "util/name_table.hpp" #include "util/node_based_graph.hpp" @@ -39,7 +40,8 @@ class TurnAnalysis const RestrictionMap &restriction_map, const std::unordered_set &barrier_nodes, const CompressedEdgeContainer &compressed_edge_container, - const util::NameTable &name_table); + const util::NameTable &name_table, + const SuffixTable &street_name_suffix_table); // the entry into the turn analysis std::vector getTurns(const NodeID from_node, const EdgeID via_eid) const; diff --git a/include/extractor/guidance/turn_handler.hpp b/include/extractor/guidance/turn_handler.hpp index b4876c0f4..e49e7e055 100644 --- a/include/extractor/guidance/turn_handler.hpp +++ b/include/extractor/guidance/turn_handler.hpp @@ -26,7 +26,8 @@ class TurnHandler : public IntersectionHandler public: TurnHandler(const util::NodeBasedDynamicGraph &node_based_graph, const std::vector &node_info_list, - const util::NameTable &name_table); + const util::NameTable &name_table, + const SuffixTable &street_name_suffix_table); ~TurnHandler() override final; // check whether the handler can actually handle the intersection diff --git a/include/extractor/suffix_table.hpp b/include/extractor/suffix_table.hpp new file mode 100644 index 000000000..af5f01649 --- /dev/null +++ b/include/extractor/suffix_table.hpp @@ -0,0 +1,30 @@ +#ifndef OSRM_EXTRACTOR_SUFFIX_LIST_HPP_ +#define OSRM_EXTRACTOR_SUFFIX_LIST_HPP_ + +#include +#include + +struct lua_State; + +namespace osrm +{ +namespace extractor +{ +// A table containing suffixes. +// At the moment, it is only a front for an unordered set. At some point we might want to make it +// country dependent and have it behave accordingly +class SuffixTable final +{ + public: + SuffixTable(lua_State *lua_state); + + // check whether a string is part of the know suffix list + bool isSuffix(const std::string &possible_suffix) const; + + private: + std::unordered_set suffix_set; +}; +} /* namespace extractor */ +} /* namespace osrm */ + +#endif /* OSRM_EXTRACTOR_SUFFIX_LIST_HPP_ */ diff --git a/profiles/car.lua b/profiles/car.lua index ffe62ca57..4855dcf73 100644 --- a/profiles/car.lua +++ b/profiles/car.lua @@ -11,6 +11,9 @@ access_tags_hierarchy = { "motorcar", "motor_vehicle", "vehicle", "access" } service_tag_restricted = { ["parking_aisle"] = true } restriction_exception_tags = { "motorcar", "motor_vehicle", "vehicle" } +-- A list of suffixes to suppress in name change instructions +suffix_list = { "N", "NE", "E", "SE", "S", "SW", "W", "NW" } + speed_profile = { ["motorway"] = 90, ["motorway_link"] = 45, @@ -150,6 +153,12 @@ local max = math.max local speed_reduction = 0.8 +function get_name_suffix_list(vector) + for index,suffix in ipairs(suffix_list) do + vector:Add(suffix) + end +end + function get_exceptions(vector) for i,v in ipairs(restriction_exception_tags) do vector:Add(v) diff --git a/scripts/check_taginfo.py b/scripts/check_taginfo.py index c2c4c7276..e1661b752 100755 --- a/scripts/check_taginfo.py +++ b/scripts/check_taginfo.py @@ -28,6 +28,9 @@ with open(profile_path) as f: n_errors = 0 for n, line in enumerate(profile): + # allow arbitrary suffix lists + if line.strip().startswith("suffix_list"): + continue # ignore comments if line.strip().startswith("--"): continue diff --git a/src/engine/guidance/post_processing.cpp b/src/engine/guidance/post_processing.cpp index 75ec050cd..c82c38e1a 100644 --- a/src/engine/guidance/post_processing.cpp +++ b/src/engine/guidance/post_processing.cpp @@ -29,14 +29,26 @@ namespace engine namespace guidance { +namespace +{ + +// invalidate a step and set its content to nothing +void invalidateStep(RouteStep &step) +{ + step = {}; + step.maneuver.instruction = TurnInstruction::NO_TURN(); +}; + void print(const std::vector &steps) { std::cout << "Path\n"; int segment = 0; for (const auto &step : steps) { - const auto type = static_cast(step.maneuver.instruction.type); - const auto modifier = static_cast(step.maneuver.instruction.direction_modifier); + const auto type = + static_cast::type>(step.maneuver.instruction.type); + const auto modifier = static_cast::type>( + step.maneuver.instruction.direction_modifier); std::cout << "\t[" << ++segment << "]: " << type << " " << modifier << " Duration: " << step.duration << " Distance: " << step.distance @@ -53,37 +65,6 @@ void print(const std::vector &steps) } } -namespace detail -{ - -void print(const std::vector &steps) -{ - std::cout << "Path\n"; - int segment = 0; - for (const auto &step : steps) - { - const auto type = static_cast(step.maneuver.instruction.type); - const auto modifier = static_cast(step.maneuver.instruction.direction_modifier); - - std::cout << "\t[" << ++segment << "]: " << type << " " << modifier - << " Duration: " << step.duration << " Distance: " << step.distance - << " Geometry: " << step.geometry_begin << " " << step.geometry_end - << " exit: " << step.maneuver.exit - << " Intersections: " << step.maneuver.intersections.size() << " ["; - - for (auto intersection : step.maneuver.intersections) - std::cout << "(" << intersection.duration << " " << intersection.distance << ")"; - - std::cout << "] name[" << step.name_id << "]: " << step.name << std::endl; - } -} - -bool canMergeTrivially(const RouteStep &destination, const RouteStep &source) -{ - return destination.maneuver.exit == 0 && destination.name_id == source.name_id && - isSilent(source.maneuver.instruction); -} - RouteStep forwardInto(RouteStep destination, const RouteStep &source) { // Merge a turn into a silent turn @@ -95,13 +76,6 @@ RouteStep forwardInto(RouteStep destination, const RouteStep &source) return destination; } -// invalidate a step and set its content to nothing -inline void invalidateStep(RouteStep &step) -{ - step = {}; - step.maneuver.instruction = TurnInstruction::NO_TURN(); -}; - void fixFinalRoundabout(std::vector &steps) { for (std::size_t propagation_index = steps.size() - 1; propagation_index > 0; @@ -194,7 +168,7 @@ void closeOffRoundabout(const bool on_roundabout, BOOST_ASSERT(leavesRoundabout(steps[1].maneuver.instruction) || steps[1].maneuver.instruction.type == TurnType::StayOnRoundabout); steps[0].geometry_end = 1; - steps[1] = detail::forwardInto(steps[1], steps[0]); + steps[1] = forwardInto(steps[1], steps[0]); steps[0].duration = 0; steps[0].distance = 0; const auto exitToEnter = [](const TurnType type) { @@ -223,7 +197,7 @@ void closeOffRoundabout(const bool on_roundabout, --propagation_index) { auto &propagation_step = steps[propagation_index]; - propagation_step = detail::forwardInto(propagation_step, steps[propagation_index + 1]); + propagation_step = forwardInto(propagation_step, steps[propagation_index + 1]); if (entersRoundabout(propagation_step.maneuver.instruction)) { propagation_step.maneuver.exit = step.maneuver.exit; @@ -334,7 +308,7 @@ RouteStep elongate(RouteStep step, const RouteStep &by_step) // A check whether two instructions can be treated as one. This is only the case for very short // maneuvers that can, in some form, be seen as one. The additional in_step is to find out about // a possible u-turn. -inline bool collapsable(const RouteStep &step) +bool collapsable(const RouteStep &step) { const constexpr double MAX_COLLAPSE_DISTANCE = 25; return step.distance < MAX_COLLAPSE_DISTANCE; @@ -345,6 +319,8 @@ void collapseTurnAt(std::vector &steps, const std::size_t one_back_index, const std::size_t step_index) { + BOOST_ASSERT(step_index < steps.size()); + BOOST_ASSERT(one_back_index < steps.size()); const auto ¤t_step = steps[step_index]; const auto &one_back_step = steps[one_back_index]; @@ -357,6 +333,7 @@ void collapseTurnAt(std::vector &steps, // Very Short New Name if (TurnType::NewName == one_back_step.maneuver.instruction.type) { + BOOST_ASSERT(two_back_index < steps.size()); if (one_back_step.mode == steps[two_back_index].mode) { steps[two_back_index] = elongate(std::move(steps[two_back_index]), one_back_step); @@ -387,6 +364,7 @@ void collapseTurnAt(std::vector &steps, current_step.maneuver.bearing_after)) { + BOOST_ASSERT(two_back_index < steps.size()); // the simple case is a u-turn that changes directly into the in-name again const bool direct_u_turn = steps[two_back_index].name == current_step.name; @@ -420,7 +398,7 @@ void collapseTurnAt(std::vector &steps, } } -} // namespace detail +} // namespace // Post processing can invalidate some instructions. For example StayOnRoundabout // is turned into exit counts. These instructions are removed by the following function @@ -469,7 +447,7 @@ std::vector postProcess(std::vector steps) into.maneuver.intersections.push_back( {last_step.duration, last_step.distance, intersection.maneuver.location}); - return detail::forwardInto(std::move(into), intersection); + return forwardInto(std::move(into), intersection); }; // count the exits forward. if enter/exit roundabout happen both, no further treatment is @@ -484,7 +462,7 @@ std::vector postProcess(std::vector steps) if (entersRoundabout(instruction)) { last_valid_instruction = step_index; - has_entered_roundabout = detail::setUpRoundabout(step); + has_entered_roundabout = setUpRoundabout(step); if (has_entered_roundabout && step_index + 1 < steps.size()) steps[step_index + 1].maneuver.exit = step.maneuver.exit; @@ -506,7 +484,7 @@ std::vector postProcess(std::vector steps) // the first valid instruction last_valid_instruction = 1; } - detail::closeOffRoundabout(has_entered_roundabout, steps, step_index); + closeOffRoundabout(has_entered_roundabout, steps, step_index); has_entered_roundabout = false; on_roundabout = false; } @@ -529,7 +507,7 @@ std::vector postProcess(std::vector steps) // A roundabout without exit translates to enter-roundabout. if (has_entered_roundabout || on_roundabout) { - detail::fixFinalRoundabout(steps); + fixFinalRoundabout(steps); } return removeNoTurnInstructions(std::move(steps)); @@ -541,6 +519,7 @@ std::vector collapseTurns(std::vector steps) // Get the previous non-invalid instruction const auto getPreviousIndex = [&steps](std::size_t index) { BOOST_ASSERT(index > 0); + BOOST_ASSERT(index < steps.size()); --index; while (index > 0 && steps[index].maneuver.instruction == TurnInstruction::NO_TURN()) --index; @@ -553,6 +532,7 @@ std::vector collapseTurns(std::vector steps) { const auto ¤t_step = steps[step_index]; const auto one_back_index = getPreviousIndex(step_index); + BOOST_ASSERT(one_back_index < steps.size()); // cannot collapse the depart instruction if (one_back_index == 0 || current_step.maneuver.instruction == TurnInstruction::NO_TURN()) @@ -560,6 +540,7 @@ std::vector collapseTurns(std::vector steps) const auto &one_back_step = steps[one_back_index]; const auto two_back_index = getPreviousIndex(one_back_index); + BOOST_ASSERT(two_back_index < steps.size()); // If we look at two consecutive name changes, we can check for a name oszillation. // A name oszillation changes from name A shortly to name B and back to A. @@ -574,20 +555,20 @@ std::vector collapseTurns(std::vector steps) if (current_step.mode == one_back_step.mode && one_back_step.mode == steps[two_back_index].mode) { - steps[two_back_index] = detail::elongate( - detail::elongate(std::move(steps[two_back_index]), steps[one_back_index]), - steps[step_index]); - detail::invalidateStep(steps[one_back_index]); - detail::invalidateStep(steps[step_index]); + steps[two_back_index] = + elongate(elongate(std::move(steps[two_back_index]), steps[one_back_index]), + steps[step_index]); + invalidateStep(steps[one_back_index]); + invalidateStep(steps[step_index]); } // TODO discuss: we could think about changing the new-name to a pure notification // about mode changes } } - else if (detail::collapsable(one_back_step)) + else if (collapsable(one_back_step)) { // check for one of the multiple collapse scenarios and, if possible, collapse the turn - detail::collapseTurnAt(steps, two_back_index, one_back_index, step_index); + collapseTurnAt(steps, two_back_index, one_back_index, step_index); } } return removeNoTurnInstructions(std::move(steps)); diff --git a/src/extractor/edge_based_graph_factory.cpp b/src/extractor/edge_based_graph_factory.cpp index 6264fcd84..f6193e617 100644 --- a/src/extractor/edge_based_graph_factory.cpp +++ b/src/extractor/edge_based_graph_factory.cpp @@ -9,6 +9,7 @@ #include "util/simple_logger.hpp" #include "util/timing_util.hpp" +#include "extractor/suffix_table.hpp" #include "extractor/guidance/toolkit.hpp" #include @@ -320,8 +321,10 @@ 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()); + SuffixTable street_name_suffix_table(lua_state); guidance::TurnAnalysis turn_analysis(*m_node_based_graph, m_node_info_list, *m_restriction_map, - m_barrier_nodes, m_compressed_edge_container, name_table); + m_barrier_nodes, m_compressed_edge_container, name_table, + street_name_suffix_table); for (const auto node_u : util::irange(0u, m_node_based_graph->GetNumberOfNodes())) { progress.printStatus(node_u); diff --git a/src/extractor/guidance/intersection_handler.cpp b/src/extractor/guidance/intersection_handler.cpp index 913da7842..89844312e 100644 --- a/src/extractor/guidance/intersection_handler.cpp +++ b/src/extractor/guidance/intersection_handler.cpp @@ -27,8 +27,10 @@ inline bool requiresAnnouncement(const EdgeData &from, const EdgeData &to) IntersectionHandler::IntersectionHandler(const util::NodeBasedDynamicGraph &node_based_graph, const std::vector &node_info_list, - const util::NameTable &name_table) - : node_based_graph(node_based_graph), node_info_list(node_info_list), name_table(name_table) + const util::NameTable &name_table, + const SuffixTable &street_name_suffix_table) + : node_based_graph(node_based_graph), node_info_list(node_info_list), name_table(name_table), + street_name_suffix_table(street_name_suffix_table) { } @@ -86,7 +88,8 @@ TurnInstruction IntersectionHandler::getInstructionForObvious(const std::size_t const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid); if (in_data.name_id != out_data.name_id && requiresNameAnnounced(name_table.GetNameForID(in_data.name_id), - name_table.GetNameForID(out_data.name_id))) + name_table.GetNameForID(out_data.name_id), + street_name_suffix_table)) { // obvious turn onto a through street is a merge if (through_street) diff --git a/src/extractor/guidance/motorway_handler.cpp b/src/extractor/guidance/motorway_handler.cpp index 0488a7283..d5e923b20 100644 --- a/src/extractor/guidance/motorway_handler.cpp +++ b/src/extractor/guidance/motorway_handler.cpp @@ -44,8 +44,9 @@ inline bool isRampClass(EdgeID eid, const util::NodeBasedDynamicGraph &node_base MotorwayHandler::MotorwayHandler(const util::NodeBasedDynamicGraph &node_based_graph, const std::vector &node_info_list, - const util::NameTable &name_table) - : IntersectionHandler(node_based_graph, node_info_list, name_table) + const util::NameTable &name_table, + const SuffixTable &street_name_suffix_table) + : IntersectionHandler(node_based_graph, node_info_list, name_table, street_name_suffix_table) { } diff --git a/src/extractor/guidance/roundabout_handler.cpp b/src/extractor/guidance/roundabout_handler.cpp index ac409633e..603e27d4a 100644 --- a/src/extractor/guidance/roundabout_handler.cpp +++ b/src/extractor/guidance/roundabout_handler.cpp @@ -23,9 +23,10 @@ namespace guidance RoundaboutHandler::RoundaboutHandler(const util::NodeBasedDynamicGraph &node_based_graph, const std::vector &node_info_list, + const CompressedEdgeContainer &compressed_edge_container, const util::NameTable &name_table, - const CompressedEdgeContainer &compressed_edge_container) - : IntersectionHandler(node_based_graph, node_info_list, name_table), + const SuffixTable &street_name_suffix_table) + : IntersectionHandler(node_based_graph, node_info_list, name_table, street_name_suffix_table), compressed_edge_container(compressed_edge_container) { } @@ -142,9 +143,11 @@ bool RoundaboutHandler::qualifiesAsRoundaboutIntersection( if (!has_limited_size) return false; - const bool simple_exits = !std::find_if( roundabout_nodes.begin(), roundabout_nodes.end(), [this]( const NodeID node ){ - return (node_based_graph.GetOutDegree(node) > 3); - }); + const bool simple_exits = + roundabout_nodes.end() == + std::find_if(roundabout_nodes.begin(), roundabout_nodes.end(), [this](const NodeID node) { + return (node_based_graph.GetOutDegree(node) > 3); + }); if (!simple_exits) return false; @@ -219,7 +222,8 @@ RoundaboutType RoundaboutHandler::getRoundaboutType(const NodeID nid) const // roundabout does not keep its name if (roundabout_name_id != 0 && roundabout_name_id != edge_data.name_id && requiresNameAnnounced(name_table.GetNameForID(roundabout_name_id), - name_table.GetNameForID(edge_data.name_id))) + name_table.GetNameForID(edge_data.name_id), + street_name_suffix_table)) { return SPECIAL_EDGEID; } diff --git a/src/extractor/guidance/turn_analysis.cpp b/src/extractor/guidance/turn_analysis.cpp index 12ea6abb9..a573194ab 100644 --- a/src/extractor/guidance/turn_analysis.cpp +++ b/src/extractor/guidance/turn_analysis.cpp @@ -33,15 +33,16 @@ TurnAnalysis::TurnAnalysis(const util::NodeBasedDynamicGraph &node_based_graph, const RestrictionMap &restriction_map, const std::unordered_set &barrier_nodes, const CompressedEdgeContainer &compressed_edge_container, - const util::NameTable &name_table) + const util::NameTable &name_table, + const SuffixTable &street_name_suffix_table) : node_based_graph(node_based_graph), intersection_generator(node_based_graph, restriction_map, barrier_nodes, node_info_list, compressed_edge_container), - roundabout_handler(node_based_graph, node_info_list, name_table, compressed_edge_container), - motorway_handler(node_based_graph, node_info_list, name_table), - turn_handler(node_based_graph, node_info_list, name_table) + roundabout_handler(node_based_graph, node_info_list, compressed_edge_container, name_table, street_name_suffix_table), + motorway_handler(node_based_graph, node_info_list, name_table,street_name_suffix_table), + turn_handler(node_based_graph, node_info_list, name_table,street_name_suffix_table) { } diff --git a/src/extractor/guidance/turn_handler.cpp b/src/extractor/guidance/turn_handler.cpp index dd55d44b5..2240123d9 100644 --- a/src/extractor/guidance/turn_handler.cpp +++ b/src/extractor/guidance/turn_handler.cpp @@ -24,8 +24,9 @@ namespace guidance TurnHandler::TurnHandler(const util::NodeBasedDynamicGraph &node_based_graph, const std::vector &node_info_list, - const util::NameTable &name_table) - : IntersectionHandler(node_based_graph, node_info_list, name_table) + const util::NameTable &name_table, + const SuffixTable &street_name_suffix_table) + : IntersectionHandler(node_based_graph, node_info_list, name_table, street_name_suffix_table) { } @@ -406,22 +407,23 @@ Intersection TurnHandler::assignLeftTurns(const EdgeID via_edge, Intersection intersection, const std::size_t starting_at) const { - BOOST_ASSERT(!intersection.empty()); BOOST_ASSERT(starting_at <= intersection.size()); - for (auto &road : intersection) - road = mirror(road); + const auto switch_left_and_right = []( Intersection &intersection ) + { + BOOST_ASSERT(!intersection.empty()); - std::reverse(intersection.begin() + 1, intersection.end()); + for (auto &road : intersection) + road = mirror(std::move(road)); + std::reverse(intersection.begin() + 1, intersection.end()); + }; + + switch_left_and_right(intersection); // account for the u-turn in the beginning const auto count = intersection.size() - starting_at + 1; - intersection = assignRightTurns(via_edge, std::move(intersection), count); + switch_left_and_right(intersection); - std::reverse(intersection.begin() + 1, intersection.end()); - - for (auto &road : intersection) - road = mirror(road); return intersection; } diff --git a/src/extractor/suffix_table.cpp b/src/extractor/suffix_table.cpp new file mode 100644 index 000000000..3c4bc0f97 --- /dev/null +++ b/src/extractor/suffix_table.cpp @@ -0,0 +1,48 @@ +#include "extractor/suffix_table.hpp" + +#include "util/lua_util.hpp" +#include "util/simple_logger.hpp" + +#include +#include +#include +#include + +#include +#include + +namespace osrm +{ +namespace extractor +{ + +SuffixTable::SuffixTable(lua_State *lua_state) +{ + BOOST_ASSERT(lua_state != nullptr); + if (!util::luaFunctionExists(lua_state, "get_name_suffix_list")) + return; + + std::vector suffixes_vector; + try + { + // call lua profile to compute turn penalty + luabind::call_function(lua_state, "get_name_suffix_list", + boost::ref(suffixes_vector)); + } + catch (const luabind::error &er) + { + util::SimpleLogger().Write(logWARNING) << er.what(); + } + + for (auto &suffix : suffixes_vector) + boost::algorithm::to_lower(suffix); + suffix_set.insert(std::begin(suffixes_vector), std::end(suffixes_vector)); +} + +bool SuffixTable::isSuffix(const std::string &possible_suffix) const +{ + return suffix_set.count(possible_suffix) > 0; +} + +} /* namespace extractor */ +} /* namespace osrm */