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

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
// 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];

View File

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

View File

@ -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<QueryNode> &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<QueryNode> &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;

View File

@ -24,7 +24,8 @@ class MotorwayHandler : public IntersectionHandler
public:
MotorwayHandler(const util::NodeBasedDynamicGraph &node_based_graph,
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;
// check whether the handler can actually handle the intersection

View File

@ -40,8 +40,9 @@ class RoundaboutHandler : public IntersectionHandler
public:
RoundaboutHandler(const util::NodeBasedDynamicGraph &node_based_graph,
const std::vector<QueryNode> &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;

View File

@ -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 <map>
#include <string>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/predicate.hpp>
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;
}

View File

@ -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<NodeID> &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<TurnOperation> getTurns(const NodeID from_node, const EdgeID via_eid) const;

View File

@ -26,7 +26,8 @@ class TurnHandler : public IntersectionHandler
public:
TurnHandler(const util::NodeBasedDynamicGraph &node_based_graph,
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;
// 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 }
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)

View File

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

View File

@ -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<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);
const auto type =
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
<< " 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)
{
// 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<RouteStep> &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<RouteStep> &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 &current_step = steps[step_index];
const auto &one_back_step = steps[one_back_index];
@ -357,6 +333,7 @@ void collapseTurnAt(std::vector<RouteStep> &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<RouteStep> &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<RouteStep> &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<RouteStep> postProcess(std::vector<RouteStep> 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<RouteStep> postProcess(std::vector<RouteStep> 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<RouteStep> postProcess(std::vector<RouteStep> 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<RouteStep> postProcess(std::vector<RouteStep> 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<RouteStep> collapseTurns(std::vector<RouteStep> 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<RouteStep> collapseTurns(std::vector<RouteStep> steps)
{
const auto &current_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<RouteStep> collapseTurns(std::vector<RouteStep> 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<RouteStep> collapseTurns(std::vector<RouteStep> 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));

View File

@ -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 <boost/assert.hpp>
@ -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);

View File

@ -27,8 +27,10 @@ inline bool requiresAnnouncement(const EdgeData &from, const EdgeData &to)
IntersectionHandler::IntersectionHandler(const util::NodeBasedDynamicGraph &node_based_graph,
const std::vector<QueryNode> &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)

View File

@ -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<QueryNode> &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)
{
}

View File

@ -23,9 +23,10 @@ namespace guidance
RoundaboutHandler::RoundaboutHandler(const util::NodeBasedDynamicGraph &node_based_graph,
const std::vector<QueryNode> &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;
}

View File

@ -33,15 +33,16 @@ TurnAnalysis::TurnAnalysis(const util::NodeBasedDynamicGraph &node_based_graph,
const RestrictionMap &restriction_map,
const std::unordered_set<NodeID> &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)
{
}

View File

@ -24,8 +24,9 @@ namespace guidance
TurnHandler::TurnHandler(const util::NodeBasedDynamicGraph &node_based_graph,
const std::vector<QueryNode> &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;
}

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 */