enable suppression name suffix changes

This commit is contained in:
Moritz Kobitzsch 2016-04-22 11:31:46 +02:00
parent fddb035539
commit a154d71841
21 changed files with 298 additions and 95 deletions

View File

@ -2,6 +2,11 @@
- API: - API:
- added roundabout-turn instruction. The instruction indicates a small roundabout that is treated as an intersection - 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...) (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 - Infrastructure
- BREAKING: reordered internal instruction types. This breaks the data format - BREAKING: reordered internal instruction types. This breaks the data format

View File

@ -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 |

View File

@ -79,7 +79,7 @@ std::vector<RouteStep> assembleSteps(const DataFacadeT &facade,
// some name changes are not announced in our processing. For these, we have to keep the // some name changes are not announced in our processing. For these, we have to keep the
// first name on the segment // 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) 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]; const auto &path_point = leg_data[leg_data_index];

View File

@ -65,8 +65,8 @@ inline extractor::guidance::DirectionModifier angleToDirectionModifier(const dou
inline double angularDeviation(const double angle, const double from) inline double angularDeviation(const double angle, const double from)
{ {
const double deviation = std::abs(angle - from); const double deviation = std::abs(angle - from);
return std::min(360 - deviation, deviation); return std::min(360 - deviation, deviation);
} }
} // namespace guidance } // namespace guidance

View File

@ -3,6 +3,7 @@
#include "extractor/guidance/intersection.hpp" #include "extractor/guidance/intersection.hpp"
#include "extractor/query_node.hpp" #include "extractor/query_node.hpp"
#include "extractor/suffix_table.hpp"
#include "util/name_table.hpp" #include "util/name_table.hpp"
#include "util/node_based_graph.hpp" #include "util/node_based_graph.hpp"
@ -26,7 +27,8 @@ class IntersectionHandler
public: public:
IntersectionHandler(const util::NodeBasedDynamicGraph &node_based_graph, IntersectionHandler(const util::NodeBasedDynamicGraph &node_based_graph,
const std::vector<QueryNode> &node_info_list, const std::vector<QueryNode> &node_info_list,
const util::NameTable &name_table); const util::NameTable &name_table,
const SuffixTable &street_name_suffix_table);
virtual ~IntersectionHandler(); virtual ~IntersectionHandler();
// check whether the handler can actually handle the intersection // check whether the handler can actually handle the intersection
@ -41,6 +43,7 @@ class IntersectionHandler
const util::NodeBasedDynamicGraph &node_based_graph; const util::NodeBasedDynamicGraph &node_based_graph;
const std::vector<QueryNode> &node_info_list; const std::vector<QueryNode> &node_info_list;
const util::NameTable &name_table; const util::NameTable &name_table;
const SuffixTable &street_name_suffix_table;
// counts the number on allowed entry roads // counts the number on allowed entry roads
std::size_t countValid(const Intersection &intersection) const; std::size_t countValid(const Intersection &intersection) const;

View File

@ -24,7 +24,8 @@ class MotorwayHandler : public IntersectionHandler
public: public:
MotorwayHandler(const util::NodeBasedDynamicGraph &node_based_graph, MotorwayHandler(const util::NodeBasedDynamicGraph &node_based_graph,
const std::vector<QueryNode> &node_info_list, const std::vector<QueryNode> &node_info_list,
const util::NameTable &name_table); const util::NameTable &name_table,
const SuffixTable &street_name_suffix_table);
~MotorwayHandler() override final; ~MotorwayHandler() override final;
// check whether the handler can actually handle the intersection // check whether the handler can actually handle the intersection

View File

@ -40,8 +40,9 @@ class RoundaboutHandler : public IntersectionHandler
public: public:
RoundaboutHandler(const util::NodeBasedDynamicGraph &node_based_graph, RoundaboutHandler(const util::NodeBasedDynamicGraph &node_based_graph,
const std::vector<QueryNode> &node_info_list, const std::vector<QueryNode> &node_info_list,
const CompressedEdgeContainer &compressed_edge_container,
const util::NameTable &name_table, const util::NameTable &name_table,
const CompressedEdgeContainer &compressed_edge_container); const SuffixTable &street_name_suffix_table);
~RoundaboutHandler() override final; ~RoundaboutHandler() override final;

View File

@ -8,6 +8,7 @@
#include "extractor/compressed_edge_container.hpp" #include "extractor/compressed_edge_container.hpp"
#include "extractor/query_node.hpp" #include "extractor/query_node.hpp"
#include "extractor/suffix_table.hpp"
#include "extractor/guidance/classification_data.hpp" #include "extractor/guidance/classification_data.hpp"
#include "extractor/guidance/discrete_angle.hpp" #include "extractor/guidance/discrete_angle.hpp"
@ -20,6 +21,7 @@
#include <map> #include <map>
#include <string> #include <string>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/predicate.hpp> #include <boost/algorithm/string/predicate.hpp>
namespace osrm namespace osrm
@ -305,7 +307,9 @@ inline bool isDistinct(const DirectionModifier first, const DirectionModifier se
return true; 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? // FIXME, handle in profile to begin with?
// this uses the encoding of references in the profile, which is very BAD // 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(from, from_name, from_ref);
split(to, to_name, to_ref); split(to, to_name, to_ref);
// check similarity of names // check similarity of names
const auto names_are_empty = from_name.empty() && to_name.empty(); 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 names_are_equal = from_name == to_name || name_is_contained;
const auto name_is_removed = !from_name.empty() && to_name.empty(); const auto name_is_removed = !from_name.empty() && to_name.empty();
// references are contained in one another // 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); (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 ref_is_removed = !from_ref.empty() && to_ref.empty();
const auto obvious_change = const auto checkForSuffixChange = [](const std::size_t common_length, const std::string &first,
(names_are_empty && refs_are_empty) || (names_are_equal && ref_is_contained) || const std::string &second,
(names_are_equal && refs_are_empty) || name_is_removed || ref_is_removed; 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; return !obvious_change;
} }

View File

@ -11,6 +11,7 @@
#include "extractor/guidance/turn_handler.hpp" #include "extractor/guidance/turn_handler.hpp"
#include "extractor/query_node.hpp" #include "extractor/query_node.hpp"
#include "extractor/restriction_map.hpp" #include "extractor/restriction_map.hpp"
#include "extractor/suffix_table.hpp"
#include "util/name_table.hpp" #include "util/name_table.hpp"
#include "util/node_based_graph.hpp" #include "util/node_based_graph.hpp"
@ -39,7 +40,8 @@ class TurnAnalysis
const RestrictionMap &restriction_map, const RestrictionMap &restriction_map,
const std::unordered_set<NodeID> &barrier_nodes, const std::unordered_set<NodeID> &barrier_nodes,
const CompressedEdgeContainer &compressed_edge_container, 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 // the entry into the turn analysis
std::vector<TurnOperation> getTurns(const NodeID from_node, const EdgeID via_eid) const; std::vector<TurnOperation> getTurns(const NodeID from_node, const EdgeID via_eid) const;

View File

@ -26,7 +26,8 @@ class TurnHandler : public IntersectionHandler
public: public:
TurnHandler(const util::NodeBasedDynamicGraph &node_based_graph, TurnHandler(const util::NodeBasedDynamicGraph &node_based_graph,
const std::vector<QueryNode> &node_info_list, const std::vector<QueryNode> &node_info_list,
const util::NameTable &name_table); const util::NameTable &name_table,
const SuffixTable &street_name_suffix_table);
~TurnHandler() override final; ~TurnHandler() override final;
// check whether the handler can actually handle the intersection // check whether the handler can actually handle the intersection

View File

@ -0,0 +1,30 @@
#ifndef OSRM_EXTRACTOR_SUFFIX_LIST_HPP_
#define OSRM_EXTRACTOR_SUFFIX_LIST_HPP_
#include <string>
#include <unordered_set>
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<std::string> suffix_set;
};
} /* namespace extractor */
} /* namespace osrm */
#endif /* OSRM_EXTRACTOR_SUFFIX_LIST_HPP_ */

View File

@ -11,6 +11,9 @@ access_tags_hierarchy = { "motorcar", "motor_vehicle", "vehicle", "access" }
service_tag_restricted = { ["parking_aisle"] = true } service_tag_restricted = { ["parking_aisle"] = true }
restriction_exception_tags = { "motorcar", "motor_vehicle", "vehicle" } 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 = { speed_profile = {
["motorway"] = 90, ["motorway"] = 90,
["motorway_link"] = 45, ["motorway_link"] = 45,
@ -150,6 +153,12 @@ local max = math.max
local speed_reduction = 0.8 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) function get_exceptions(vector)
for i,v in ipairs(restriction_exception_tags) do for i,v in ipairs(restriction_exception_tags) do
vector:Add(v) vector:Add(v)

View File

@ -28,6 +28,9 @@ with open(profile_path) as f:
n_errors = 0 n_errors = 0
for n, line in enumerate(profile): for n, line in enumerate(profile):
# allow arbitrary suffix lists
if line.strip().startswith("suffix_list"):
continue
# ignore comments # ignore comments
if line.strip().startswith("--"): if line.strip().startswith("--"):
continue continue

View File

@ -29,14 +29,26 @@ namespace engine
namespace guidance 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<RouteStep> &steps) void print(const std::vector<RouteStep> &steps)
{ {
std::cout << "Path\n"; std::cout << "Path\n";
int segment = 0; int segment = 0;
for (const auto &step : steps) for (const auto &step : steps)
{ {
const auto type = static_cast<int>(step.maneuver.instruction.type); const auto type =
const auto modifier = static_cast<int>(step.maneuver.instruction.direction_modifier); static_cast<std::underlying_type<TurnType>::type>(step.maneuver.instruction.type);
const auto modifier = static_cast<std::underlying_type<DirectionModifier>::type>(
step.maneuver.instruction.direction_modifier);
std::cout << "\t[" << ++segment << "]: " << type << " " << modifier std::cout << "\t[" << ++segment << "]: " << type << " " << modifier
<< " Duration: " << step.duration << " Distance: " << step.distance << " Duration: " << step.duration << " Distance: " << step.distance
@ -53,37 +65,6 @@ void print(const std::vector<RouteStep> &steps)
} }
} }
namespace detail
{
void print(const std::vector<RouteStep> &steps)
{
std::cout << "Path\n";
int segment = 0;
for (const auto &step : steps)
{
const auto type = static_cast<int>(step.maneuver.instruction.type);
const auto modifier = static_cast<int>(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) RouteStep forwardInto(RouteStep destination, const RouteStep &source)
{ {
// Merge a turn into a silent turn // Merge a turn into a silent turn
@ -95,13 +76,6 @@ RouteStep forwardInto(RouteStep destination, const RouteStep &source)
return destination; 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<RouteStep> &steps) void fixFinalRoundabout(std::vector<RouteStep> &steps)
{ {
for (std::size_t propagation_index = steps.size() - 1; propagation_index > 0; 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) || BOOST_ASSERT(leavesRoundabout(steps[1].maneuver.instruction) ||
steps[1].maneuver.instruction.type == TurnType::StayOnRoundabout); steps[1].maneuver.instruction.type == TurnType::StayOnRoundabout);
steps[0].geometry_end = 1; 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].duration = 0;
steps[0].distance = 0; steps[0].distance = 0;
const auto exitToEnter = [](const TurnType type) { const auto exitToEnter = [](const TurnType type) {
@ -223,7 +197,7 @@ void closeOffRoundabout(const bool on_roundabout,
--propagation_index) --propagation_index)
{ {
auto &propagation_step = steps[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)) if (entersRoundabout(propagation_step.maneuver.instruction))
{ {
propagation_step.maneuver.exit = step.maneuver.exit; 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 // 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 // maneuvers that can, in some form, be seen as one. The additional in_step is to find out about
// a possible u-turn. // a possible u-turn.
inline bool collapsable(const RouteStep &step) bool collapsable(const RouteStep &step)
{ {
const constexpr double MAX_COLLAPSE_DISTANCE = 25; const constexpr double MAX_COLLAPSE_DISTANCE = 25;
return step.distance < MAX_COLLAPSE_DISTANCE; return step.distance < MAX_COLLAPSE_DISTANCE;
@ -345,6 +319,8 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
const std::size_t one_back_index, const std::size_t one_back_index,
const std::size_t step_index) const std::size_t step_index)
{ {
BOOST_ASSERT(step_index < steps.size());
BOOST_ASSERT(one_back_index < steps.size());
const auto &current_step = steps[step_index]; const auto &current_step = steps[step_index];
const auto &one_back_step = steps[one_back_index]; const auto &one_back_step = steps[one_back_index];
@ -357,6 +333,7 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
// Very Short New Name // Very Short New Name
if (TurnType::NewName == one_back_step.maneuver.instruction.type) 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) if (one_back_step.mode == steps[two_back_index].mode)
{ {
steps[two_back_index] = elongate(std::move(steps[two_back_index]), one_back_step); steps[two_back_index] = elongate(std::move(steps[two_back_index]), one_back_step);
@ -387,6 +364,7 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
current_step.maneuver.bearing_after)) 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 // 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; const bool direct_u_turn = steps[two_back_index].name == current_step.name;
@ -420,7 +398,7 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
} }
} }
} // namespace detail } // namespace
// Post processing can invalidate some instructions. For example StayOnRoundabout // Post processing can invalidate some instructions. For example StayOnRoundabout
// is turned into exit counts. These instructions are removed by the following function // is turned into exit counts. These instructions are removed by the following function
@ -469,7 +447,7 @@ std::vector<RouteStep> postProcess(std::vector<RouteStep> steps)
into.maneuver.intersections.push_back( into.maneuver.intersections.push_back(
{last_step.duration, last_step.distance, intersection.maneuver.location}); {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 // count the exits forward. if enter/exit roundabout happen both, no further treatment is
@ -484,7 +462,7 @@ std::vector<RouteStep> postProcess(std::vector<RouteStep> steps)
if (entersRoundabout(instruction)) if (entersRoundabout(instruction))
{ {
last_valid_instruction = step_index; 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()) if (has_entered_roundabout && step_index + 1 < steps.size())
steps[step_index + 1].maneuver.exit = step.maneuver.exit; steps[step_index + 1].maneuver.exit = step.maneuver.exit;
@ -506,7 +484,7 @@ std::vector<RouteStep> postProcess(std::vector<RouteStep> steps)
// the first valid instruction // the first valid instruction
last_valid_instruction = 1; last_valid_instruction = 1;
} }
detail::closeOffRoundabout(has_entered_roundabout, steps, step_index); closeOffRoundabout(has_entered_roundabout, steps, step_index);
has_entered_roundabout = false; has_entered_roundabout = false;
on_roundabout = false; on_roundabout = false;
} }
@ -529,7 +507,7 @@ std::vector<RouteStep> postProcess(std::vector<RouteStep> steps)
// A roundabout without exit translates to enter-roundabout. // A roundabout without exit translates to enter-roundabout.
if (has_entered_roundabout || on_roundabout) if (has_entered_roundabout || on_roundabout)
{ {
detail::fixFinalRoundabout(steps); fixFinalRoundabout(steps);
} }
return removeNoTurnInstructions(std::move(steps)); return removeNoTurnInstructions(std::move(steps));
@ -541,6 +519,7 @@ std::vector<RouteStep> collapseTurns(std::vector<RouteStep> steps)
// Get the previous non-invalid instruction // Get the previous non-invalid instruction
const auto getPreviousIndex = [&steps](std::size_t index) { const auto getPreviousIndex = [&steps](std::size_t index) {
BOOST_ASSERT(index > 0); BOOST_ASSERT(index > 0);
BOOST_ASSERT(index < steps.size());
--index; --index;
while (index > 0 && steps[index].maneuver.instruction == TurnInstruction::NO_TURN()) while (index > 0 && steps[index].maneuver.instruction == TurnInstruction::NO_TURN())
--index; --index;
@ -553,6 +532,7 @@ std::vector<RouteStep> collapseTurns(std::vector<RouteStep> steps)
{ {
const auto &current_step = steps[step_index]; const auto &current_step = steps[step_index];
const auto one_back_index = getPreviousIndex(step_index); const auto one_back_index = getPreviousIndex(step_index);
BOOST_ASSERT(one_back_index < steps.size());
// cannot collapse the depart instruction // cannot collapse the depart instruction
if (one_back_index == 0 || current_step.maneuver.instruction == TurnInstruction::NO_TURN()) if (one_back_index == 0 || current_step.maneuver.instruction == TurnInstruction::NO_TURN())
@ -560,6 +540,7 @@ std::vector<RouteStep> collapseTurns(std::vector<RouteStep> steps)
const auto &one_back_step = steps[one_back_index]; const auto &one_back_step = steps[one_back_index];
const auto two_back_index = getPreviousIndex(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. // 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. // A name oszillation changes from name A shortly to name B and back to A.
@ -574,20 +555,20 @@ std::vector<RouteStep> collapseTurns(std::vector<RouteStep> steps)
if (current_step.mode == one_back_step.mode && if (current_step.mode == one_back_step.mode &&
one_back_step.mode == steps[two_back_index].mode) one_back_step.mode == steps[two_back_index].mode)
{ {
steps[two_back_index] = detail::elongate( steps[two_back_index] =
detail::elongate(std::move(steps[two_back_index]), steps[one_back_index]), elongate(elongate(std::move(steps[two_back_index]), steps[one_back_index]),
steps[step_index]); steps[step_index]);
detail::invalidateStep(steps[one_back_index]); invalidateStep(steps[one_back_index]);
detail::invalidateStep(steps[step_index]); invalidateStep(steps[step_index]);
} }
// TODO discuss: we could think about changing the new-name to a pure notification // TODO discuss: we could think about changing the new-name to a pure notification
// about mode changes // 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 // 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)); return removeNoTurnInstructions(std::move(steps));

View File

@ -9,6 +9,7 @@
#include "util/simple_logger.hpp" #include "util/simple_logger.hpp"
#include "util/timing_util.hpp" #include "util/timing_util.hpp"
#include "extractor/suffix_table.hpp"
#include "extractor/guidance/toolkit.hpp" #include "extractor/guidance/toolkit.hpp"
#include <boost/assert.hpp> #include <boost/assert.hpp>
@ -320,8 +321,10 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
// Three nested loop look super-linear, but we are dealing with a (kind of) // Three nested loop look super-linear, but we are dealing with a (kind of)
// linear number of turns only. // linear number of turns only.
util::Percent progress(m_node_based_graph->GetNumberOfNodes()); 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, 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())) for (const auto node_u : util::irange(0u, m_node_based_graph->GetNumberOfNodes()))
{ {
progress.printStatus(node_u); progress.printStatus(node_u);

View File

@ -27,8 +27,10 @@ inline bool requiresAnnouncement(const EdgeData &from, const EdgeData &to)
IntersectionHandler::IntersectionHandler(const util::NodeBasedDynamicGraph &node_based_graph, IntersectionHandler::IntersectionHandler(const util::NodeBasedDynamicGraph &node_based_graph,
const std::vector<QueryNode> &node_info_list, const std::vector<QueryNode> &node_info_list,
const util::NameTable &name_table) const util::NameTable &name_table,
: node_based_graph(node_based_graph), node_info_list(node_info_list), name_table(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); const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
if (in_data.name_id != out_data.name_id && if (in_data.name_id != out_data.name_id &&
requiresNameAnnounced(name_table.GetNameForID(in_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 // obvious turn onto a through street is a merge
if (through_street) if (through_street)

View File

@ -44,8 +44,9 @@ inline bool isRampClass(EdgeID eid, const util::NodeBasedDynamicGraph &node_base
MotorwayHandler::MotorwayHandler(const util::NodeBasedDynamicGraph &node_based_graph, MotorwayHandler::MotorwayHandler(const util::NodeBasedDynamicGraph &node_based_graph,
const std::vector<QueryNode> &node_info_list, const std::vector<QueryNode> &node_info_list,
const util::NameTable &name_table) const util::NameTable &name_table,
: 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)
{ {
} }

View File

@ -23,9 +23,10 @@ namespace guidance
RoundaboutHandler::RoundaboutHandler(const util::NodeBasedDynamicGraph &node_based_graph, RoundaboutHandler::RoundaboutHandler(const util::NodeBasedDynamicGraph &node_based_graph,
const std::vector<QueryNode> &node_info_list, const std::vector<QueryNode> &node_info_list,
const CompressedEdgeContainer &compressed_edge_container,
const util::NameTable &name_table, const util::NameTable &name_table,
const CompressedEdgeContainer &compressed_edge_container) const SuffixTable &street_name_suffix_table)
: IntersectionHandler(node_based_graph, node_info_list, name_table), : IntersectionHandler(node_based_graph, node_info_list, name_table, street_name_suffix_table),
compressed_edge_container(compressed_edge_container) compressed_edge_container(compressed_edge_container)
{ {
} }
@ -142,9 +143,11 @@ bool RoundaboutHandler::qualifiesAsRoundaboutIntersection(
if (!has_limited_size) if (!has_limited_size)
return false; return false;
const bool simple_exits = !std::find_if( roundabout_nodes.begin(), roundabout_nodes.end(), [this]( const NodeID node ){ const bool simple_exits =
return (node_based_graph.GetOutDegree(node) > 3); 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) if (!simple_exits)
return false; return false;
@ -219,7 +222,8 @@ RoundaboutType RoundaboutHandler::getRoundaboutType(const NodeID nid) const
// roundabout does not keep its name // roundabout does not keep its name
if (roundabout_name_id != 0 && roundabout_name_id != edge_data.name_id && if (roundabout_name_id != 0 && roundabout_name_id != edge_data.name_id &&
requiresNameAnnounced(name_table.GetNameForID(roundabout_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; return SPECIAL_EDGEID;
} }

View File

@ -33,15 +33,16 @@ TurnAnalysis::TurnAnalysis(const util::NodeBasedDynamicGraph &node_based_graph,
const RestrictionMap &restriction_map, const RestrictionMap &restriction_map,
const std::unordered_set<NodeID> &barrier_nodes, const std::unordered_set<NodeID> &barrier_nodes,
const CompressedEdgeContainer &compressed_edge_container, 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, : node_based_graph(node_based_graph), intersection_generator(node_based_graph,
restriction_map, restriction_map,
barrier_nodes, barrier_nodes,
node_info_list, node_info_list,
compressed_edge_container), compressed_edge_container),
roundabout_handler(node_based_graph, node_info_list, name_table, compressed_edge_container), 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), motorway_handler(node_based_graph, node_info_list, name_table,street_name_suffix_table),
turn_handler(node_based_graph, node_info_list, name_table) turn_handler(node_based_graph, node_info_list, name_table,street_name_suffix_table)
{ {
} }

View File

@ -24,8 +24,9 @@ namespace guidance
TurnHandler::TurnHandler(const util::NodeBasedDynamicGraph &node_based_graph, TurnHandler::TurnHandler(const util::NodeBasedDynamicGraph &node_based_graph,
const std::vector<QueryNode> &node_info_list, const std::vector<QueryNode> &node_info_list,
const util::NameTable &name_table) const util::NameTable &name_table,
: 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)
{ {
} }
@ -406,22 +407,23 @@ Intersection TurnHandler::assignLeftTurns(const EdgeID via_edge,
Intersection intersection, Intersection intersection,
const std::size_t starting_at) const const std::size_t starting_at) const
{ {
BOOST_ASSERT(!intersection.empty());
BOOST_ASSERT(starting_at <= intersection.size()); BOOST_ASSERT(starting_at <= intersection.size());
for (auto &road : intersection) const auto switch_left_and_right = []( Intersection &intersection )
road = mirror(road); {
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 // account for the u-turn in the beginning
const auto count = intersection.size() - starting_at + 1; const auto count = intersection.size() - starting_at + 1;
intersection = assignRightTurns(via_edge, std::move(intersection), count); 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; return intersection;
} }

View File

@ -0,0 +1,48 @@
#include "extractor/suffix_table.hpp"
#include "util/lua_util.hpp"
#include "util/simple_logger.hpp"
#include <boost/algorithm/string.hpp>
#include <boost/assert.hpp>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/ref.hpp>
#include <iterator>
#include <vector>
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<std::string> suffixes_vector;
try
{
// call lua profile to compute turn penalty
luabind::call_function<void>(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 */