refactor of post-processing
- moves collapse into a dedicated set of functions / files - make collapse scenarios distinct (slight performance cost) - reduce verbosity for short name segments (now actually working, was supposed to do so before)
This commit is contained in:
committed by
Patrick Niklaus
parent
8d83c3adbb
commit
6c3390f14d
@@ -0,0 +1,133 @@
|
||||
#include "engine/guidance/verbosity_reduction.hpp"
|
||||
#include "engine/guidance/collapsing_utility.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <iterator>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace engine
|
||||
{
|
||||
namespace guidance
|
||||
{
|
||||
std::vector<RouteStep> suppressShortNameSegments(std::vector<RouteStep> steps)
|
||||
{
|
||||
// guard against empty routes, even though they shouldn't happen
|
||||
if (steps.empty())
|
||||
return steps;
|
||||
|
||||
// we remove only name changes that don't offer additional information
|
||||
const auto name_change_without_lanes = [](const RouteStep &step) {
|
||||
return hasTurnType(step, TurnType::NewName) && !hasLanes(step);
|
||||
};
|
||||
|
||||
// check if the next step is not important enough to announce
|
||||
const auto can_be_extended_to = [](const RouteStep &step) {
|
||||
const auto is_not_arrive = !hasWaypointType(step);
|
||||
const auto is_silent = !hasTurnType(step) || hasTurnType(step, TurnType::Suppressed);
|
||||
|
||||
return is_not_arrive && is_silent;
|
||||
};
|
||||
|
||||
const auto suppress = [](RouteStep &from_step, RouteStep &onto_step) {
|
||||
from_step.ElongateBy(onto_step);
|
||||
onto_step.Invalidate();
|
||||
};
|
||||
|
||||
// suppresses name segments that announce already known names or announce a name that will be
|
||||
// only available for a very short time
|
||||
const auto reduce_verbosity_if_possible = [suppress, can_be_extended_to](
|
||||
RouteStepIterator ¤t_turn_itr, RouteStepIterator &previous_turn_itr) {
|
||||
if (haveSameName(*previous_turn_itr, *current_turn_itr))
|
||||
suppress(*previous_turn_itr, *current_turn_itr);
|
||||
else
|
||||
{
|
||||
// remember the location of the name change so we can advance the previous turn
|
||||
const auto location_of_name_change = current_turn_itr;
|
||||
auto distance = current_turn_itr->distance;
|
||||
// sum up all distances that can be relevant to the name change
|
||||
while (can_be_extended_to(*(current_turn_itr + 1)) &&
|
||||
distance < NAME_SEGMENT_CUTOFF_LENGTH)
|
||||
{
|
||||
++current_turn_itr;
|
||||
distance += current_turn_itr->distance;
|
||||
}
|
||||
|
||||
if (distance < NAME_SEGMENT_CUTOFF_LENGTH)
|
||||
suppress(*previous_turn_itr, *current_turn_itr);
|
||||
else
|
||||
previous_turn_itr = location_of_name_change;
|
||||
}
|
||||
};
|
||||
|
||||
BOOST_ASSERT(!hasTurnType(steps.back()) && hasWaypointType(steps.back()));
|
||||
for (auto previous_turn_itr = steps.begin(), current_turn_itr = std::next(previous_turn_itr);
|
||||
!hasWaypointType(*current_turn_itr);
|
||||
++current_turn_itr)
|
||||
{
|
||||
BOOST_ASSERT(hasTurnType(*current_turn_itr) &&
|
||||
!hasTurnType(*current_turn_itr, TurnType::Suppressed));
|
||||
if (name_change_without_lanes(*current_turn_itr) &&
|
||||
haveSameMode(*previous_turn_itr, *current_turn_itr))
|
||||
{
|
||||
// check if the name can be reduced, also sets previous_turn_itr if update is necessary
|
||||
reduce_verbosity_if_possible(current_turn_itr, previous_turn_itr);
|
||||
}
|
||||
else
|
||||
{
|
||||
// remember the current (non-suppressed) item as a new start of a segment
|
||||
previous_turn_itr = current_turn_itr;
|
||||
}
|
||||
}
|
||||
return removeNoTurnInstructions(std::move(steps));
|
||||
}
|
||||
|
||||
// `useLane` steps are only returned on `straight` maneuvers when there
|
||||
// are surrounding lanes also tagged as `straight`. If there are no other `straight`
|
||||
// lanes, it is not an ambiguous maneuver, and we can collapse the `useLane` step.
|
||||
std::vector<RouteStep> collapseUseLane(std::vector<RouteStep> steps)
|
||||
{
|
||||
const auto containsTag = [](const extractor::guidance::TurnLaneType::Mask mask,
|
||||
const extractor::guidance::TurnLaneType::Mask tag) {
|
||||
return (mask & tag) != extractor::guidance::TurnLaneType::empty;
|
||||
};
|
||||
|
||||
const auto canCollapseUseLane = [containsTag](const RouteStep &step) {
|
||||
// the lane description is given left to right, lanes are counted from the right.
|
||||
// Therefore we access the lane description using the reverse iterator
|
||||
|
||||
auto right_most_lanes = step.LanesToTheRight();
|
||||
if (!right_most_lanes.empty() && containsTag(right_most_lanes.front(),
|
||||
(extractor::guidance::TurnLaneType::straight |
|
||||
extractor::guidance::TurnLaneType::none)))
|
||||
return false;
|
||||
|
||||
auto left_most_lanes = step.LanesToTheLeft();
|
||||
if (!left_most_lanes.empty() && containsTag(left_most_lanes.back(),
|
||||
(extractor::guidance::TurnLaneType::straight |
|
||||
extractor::guidance::TurnLaneType::none)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
BOOST_ASSERT(steps.size() > 1);
|
||||
for (auto step_itr = steps.begin() + 1; step_itr != steps.end(); ++step_itr)
|
||||
{
|
||||
if (step_itr->maneuver.instruction.type == TurnType::UseLane &&
|
||||
canCollapseUseLane(*step_itr))
|
||||
{
|
||||
auto previous_turn_itr = findPreviousTurn(step_itr);
|
||||
if (haveSameMode(*previous_turn_itr, *step_itr))
|
||||
{
|
||||
previous_turn_itr->ElongateBy(*step_itr);
|
||||
step_itr->Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
return removeNoTurnInstructions(std::move(steps));
|
||||
}
|
||||
|
||||
} // namespace guidance
|
||||
} // namespace engine
|
||||
} // namespace osrm
|
||||
Reference in New Issue
Block a user