Turn Angles in OSRM were computed using a lookahead of 10 meters.

This PR adds more advanced coordinate extraction, analysing the road
to detect offsets due to OSM way modelling.

In addition it improves the handling of bearings. Right now OSM reports
bearings simply based on the very first coordinate along a way.
With this PR, we store the bearings for a turn correctly, making the
bearings for turns correct.
This commit is contained in:
Moritz Kobitzsch
2016-08-17 09:49:19 +02:00
parent 1f8ca2879f
commit 5e167b8745
62 changed files with 3451 additions and 679 deletions
-16
View File
@@ -13,22 +13,6 @@ namespace guidance
{
namespace detail
{
std::pair<short, short> getIntermediateBearings(const LegGeometry &leg_geometry,
const std::size_t segment_index)
{
auto turn_index = leg_geometry.BackIndex(segment_index);
BOOST_ASSERT(turn_index > 0);
BOOST_ASSERT(turn_index + 1 < leg_geometry.locations.size());
// TODO chose a bigger look-a-head to smooth complex geometry
const auto pre_turn_coordinate = leg_geometry.locations[turn_index - 1];
const auto turn_coordinate = leg_geometry.locations[turn_index];
const auto post_turn_coordinate = leg_geometry.locations[turn_index + 1];
return std::make_pair<short, short>(
std::round(util::coordinate_calculation::bearing(pre_turn_coordinate, turn_coordinate)),
std::round(util::coordinate_calculation::bearing(turn_coordinate, post_turn_coordinate)));
}
std::pair<short, short> getDepartBearings(const LegGeometry &leg_geometry)
{
+348 -183
View File
@@ -1,6 +1,6 @@
#include "engine/guidance/post_processing.hpp"
#include "extractor/guidance/toolkit.hpp"
#include "extractor/guidance/turn_instruction.hpp"
#include "engine/guidance/post_processing.hpp"
#include "engine/guidance/assemble_steps.hpp"
#include "engine/guidance/lane_processing.hpp"
@@ -42,8 +42,10 @@ const constexpr double MAX_COLLAPSE_DISTANCE = 30;
// check if at least one of the turns is actually a maneuver
inline bool hasManeuver(const RouteStep &first, const RouteStep &second)
{
return first.maneuver.instruction.type != TurnType::Suppressed ||
second.maneuver.instruction.type != TurnType::Suppressed;
return (first.maneuver.instruction.type != TurnType::Suppressed ||
second.maneuver.instruction.type != TurnType::Suppressed) &&
(first.maneuver.instruction.type != TurnType::NoTurn &&
second.maneuver.instruction.type != TurnType::NoTurn);
}
// forward all signage/name data from one step to another.
@@ -67,6 +69,7 @@ inline bool choiceless(const RouteStep &step, const RouteStep &previous)
1 >= std::count(step.intersections.front().entry.begin(),
step.intersections.front().entry.end(),
true);
return is_without_choice;
}
@@ -330,8 +333,9 @@ void closeOffRoundabout(const bool on_roundabout,
entry_intersection.bearings[entry_intersection.in]),
exit_bearing);
auto bearings = propagation_step.intersections.front().bearings;
propagation_step.maneuver.instruction.direction_modifier =
::osrm::util::guidance::getTurnDirection(angle);
util::guidance::getTurnDirection(angle);
}
forwardStepSignage(propagation_step, destination_copy);
@@ -347,6 +351,142 @@ void closeOffRoundabout(const bool on_roundabout,
}
}
bool bearingsAreReversed(const double bearing_in, const double bearing_out)
{
// Nearly perfectly reversed angles have a difference close to 180 degrees (straight)
const double left_turn_angle = [&]() {
if (0 <= bearing_out && bearing_out <= bearing_in)
return bearing_in - bearing_out;
return bearing_in + 360 - bearing_out;
}();
return angularDeviation(left_turn_angle, 180) <= 35;
}
bool isLinkroad(const RouteStep &step)
{
const constexpr double MAX_LINK_ROAD_LENGTH = 60.0;
return step.distance <= MAX_LINK_ROAD_LENGTH && step.name_id == EMPTY_NAMEID;
}
bool isUTurn(const RouteStep &in_step, const RouteStep &out_step, const RouteStep &pre_in_step)
{
const bool is_possible_candidate = in_step.distance <= MAX_COLLAPSE_DISTANCE ||
choiceless(out_step, in_step) ||
(isLinkroad(in_step) && out_step.name_id != EMPTY_NAMEID &&
pre_in_step.name_id == out_step.name_id);
const bool takes_u_turn = bearingsAreReversed(
util::bearing::reverseBearing(
in_step.intersections.front().bearings[in_step.intersections.front().in]),
out_step.intersections.front().bearings[out_step.intersections.front().out]);
return is_possible_candidate && takes_u_turn && compatible(in_step, out_step);
}
double findTotalTurnAngle(const RouteStep &entry_step, const RouteStep &exit_step)
{
const auto exit_intersection = exit_step.intersections.front();
const auto exit_step_exit_bearing = exit_intersection.bearings[exit_intersection.out];
const auto exit_step_entry_bearing =
util::bearing::reverseBearing(exit_intersection.bearings[exit_intersection.in]);
const auto entry_intersection = entry_step.intersections.front();
const auto entry_step_entry_bearing =
util::bearing::reverseBearing(entry_intersection.bearings[entry_intersection.in]);
const auto entry_step_exit_bearing = entry_intersection.bearings[entry_intersection.out];
const auto exit_angle = turn_angle(exit_step_entry_bearing, exit_step_exit_bearing);
const auto entry_angle = turn_angle(entry_step_entry_bearing, entry_step_exit_bearing);
const double total_angle = turn_angle(entry_step_entry_bearing, exit_step_exit_bearing);
// We allow for minor deviations from a straight line
if (((entry_step.distance < MAX_COLLAPSE_DISTANCE && exit_step.intersections.size() == 1) ||
(entry_angle <= 185 && exit_angle <= 185) || (entry_angle >= 175 && exit_angle >= 175)) &&
angularDeviation(total_angle, 180) > 20)
{
// both angles are in the same direction, the total turn gets increased
//
// a ---- b
// \
// c
// |
// d
//
// Will be considered just like
// a -----b
// |
// c
// |
// d
return total_angle;
}
else
{
// to prevent ignoring angles like
// a -- b
// |
// c -- d
// We don't combine both turn angles here but keep the very first turn angle.
// We choose the first one, since we consider the first maneuver in a merge range the
// important one
return entry_angle;
}
}
std::size_t getPreviousIndex(std::size_t index, const std::vector<RouteStep> &steps)
{
BOOST_ASSERT(index > 0);
BOOST_ASSERT(index < steps.size());
--index;
while (index > 0 && steps[index].maneuver.instruction.type == TurnType::NoTurn)
--index;
return index;
};
void collapseUTurn(std::vector<RouteStep> &steps,
const std::size_t two_back_index,
const std::size_t one_back_index,
const std::size_t step_index)
{
BOOST_ASSERT(two_back_index < steps.size());
BOOST_ASSERT(step_index < steps.size());
BOOST_ASSERT(one_back_index < steps.size());
const auto &current_step = steps[step_index];
// the simple case is a u-turn that changes directly into the in-name again
const bool direct_u_turn = !isNoticeableNameChange(steps[two_back_index], current_step);
// however, we might also deal with a dual-collapse scenario in which we have to
// additionall collapse a name-change as welll
const auto next_step_index = step_index + 1;
const bool continues_with_name_change =
(next_step_index < steps.size()) &&
((steps[next_step_index].maneuver.instruction.type == TurnType::UseLane &&
steps[next_step_index].maneuver.instruction.direction_modifier ==
DirectionModifier::Straight) ||
isCollapsableInstruction(steps[next_step_index].maneuver.instruction));
const bool u_turn_with_name_change =
continues_with_name_change && steps[next_step_index].name_id != EMPTY_NAMEID &&
!isNoticeableNameChange(steps[two_back_index], steps[next_step_index]);
if (direct_u_turn || u_turn_with_name_change)
{
steps[one_back_index] = elongate(std::move(steps[one_back_index]), steps[step_index]);
invalidateStep(steps[step_index]);
if (u_turn_with_name_change)
{
steps[one_back_index] =
elongate(std::move(steps[one_back_index]), steps[next_step_index]);
invalidateStep(steps[next_step_index]); // will be skipped due to the
// continue statement at the
// beginning of this function
}
forwardStepSignage(steps[one_back_index], steps[two_back_index]);
steps[one_back_index].maneuver.instruction.type = TurnType::Continue;
steps[one_back_index].maneuver.instruction.direction_modifier = DirectionModifier::UTurn;
}
}
void collapseTurnAt(std::vector<RouteStep> &steps,
const std::size_t two_back_index,
const std::size_t one_back_index,
@@ -357,45 +497,81 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
const auto &current_step = steps[step_index];
const auto &one_back_step = steps[one_back_index];
// FIXME: this function assumes driving on the right hand side of the streat
const auto bearingsAreReversed = [](const double bearing_in, const double bearing_out) {
// Nearly perfectly reversed angles have a difference close to 180 degrees (straight)
const double left_turn_angle = [&]() {
if (0 <= bearing_out && bearing_out <= bearing_in)
return bearing_in - bearing_out;
return bearing_in + 360 - bearing_out;
}();
return angularDeviation(left_turn_angle, 180) <= 35;
};
// This function assumes driving on the right hand side of the streat
BOOST_ASSERT(!one_back_step.intersections.empty() && !current_step.intersections.empty());
if (!hasManeuver(one_back_step, current_step))
return;
// Very Short New Name
if (((collapsable(one_back_step, current_step) ||
(isCollapsableInstruction(one_back_step.maneuver.instruction) &&
choiceless(current_step, one_back_step))) &&
!(one_back_step.maneuver.instruction.type == TurnType::Merge)))
// the check against merge is a workaround for motorways
// A maneuver is preceded by a name change if the instruction just before can be collapsed
// normally or the instruction itself is collapsable and does not actually present a choice
const auto maneuverPrecededByNameChange = [](const RouteStep &turning_point,
const RouteStep &possible_name_change_location,
const RouteStep &preceeding_step) {
// the check against merge is a workaround for motorways
if (possible_name_change_location.maneuver.instruction.type == TurnType::Merge ||
!compatible(possible_name_change_location, preceeding_step))
return false;
return collapsable(possible_name_change_location, turning_point) ||
(isCollapsableInstruction(possible_name_change_location.maneuver.instruction) &&
choiceless(possible_name_change_location, preceeding_step));
};
// check if the actual turn we wan't to announce is delayed. This situation describes a turn
// that is expressed by two turns,
const auto isDelayedTurn = [](const RouteStep &openining_turn,
const RouteStep &finishing_turn) {
// only possible if both are compatible
if (!compatible(openining_turn, finishing_turn))
return false;
else
{
const auto is_short_and_collapsable =
openining_turn.distance <= MAX_COLLAPSE_DISTANCE &&
isCollapsableInstruction(finishing_turn.maneuver.instruction);
const auto without_choice = choiceless(finishing_turn, openining_turn);
const auto is_not_too_long_and_choiceless =
openining_turn.distance <= 2 * MAX_COLLAPSE_DISTANCE && without_choice;
// for ramps we allow longer stretches, since they are often on some major brides/large
// roads. A combined distance of of 4 intersections would be to long for a normal
// collapse. In case of a ramp though, we also account for situations that have the ramp
// tagged late
const auto is_delayed_turn_onto_a_ramp =
openining_turn.distance <= 4 * MAX_COLLAPSE_DISTANCE && without_choice &&
util::guidance::hasRampType(finishing_turn.maneuver.instruction);
return !util::guidance::hasRampType(openining_turn.maneuver.instruction) &&
(is_short_and_collapsable || is_not_too_long_and_choiceless ||
isLinkroad(openining_turn) || is_delayed_turn_onto_a_ramp);
}
};
// Handle possible u-turns
if (isUTurn(one_back_step, current_step, steps[two_back_index]))
collapseUTurn(steps, two_back_index, one_back_index, step_index);
// Very Short New Name that will be suppressed. Turn location remains at current_step
else if (maneuverPrecededByNameChange(current_step, one_back_step, steps[two_back_index]))
{
BOOST_ASSERT(two_back_index < steps.size());
if (compatible(one_back_step, steps[two_back_index]))
BOOST_ASSERT(!one_back_step.intersections.empty());
if (TurnType::Merge == current_step.maneuver.instruction.type)
{
steps[step_index].maneuver.instruction.direction_modifier =
util::guidance::mirrorDirectionModifier(
steps[step_index].maneuver.instruction.direction_modifier);
steps[step_index].maneuver.instruction.type = TurnType::Turn;
}
else
{
BOOST_ASSERT(!one_back_step.intersections.empty());
if (TurnType::Continue == current_step.maneuver.instruction.type ||
(TurnType::Suppressed == current_step.maneuver.instruction.type &&
current_step.maneuver.instruction.direction_modifier !=
DirectionModifier::Straight))
steps[step_index].maneuver.instruction.type = TurnType::Turn;
else if (TurnType::Merge == current_step.maneuver.instruction.type)
{
steps[step_index].maneuver.instruction.direction_modifier =
util::guidance::mirrorDirectionModifier(
steps[step_index].maneuver.instruction.direction_modifier);
steps[step_index].maneuver.instruction.type = TurnType::Turn;
}
else if (TurnType::NewName == current_step.maneuver.instruction.type &&
current_step.maneuver.instruction.direction_modifier !=
DirectionModifier::Straight &&
@@ -407,111 +583,100 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
one_back_step.intersections.front().bearings.size() > 2)
steps[step_index].maneuver.instruction.type = TurnType::Turn;
steps[two_back_index] = elongate(std::move(steps[two_back_index]), one_back_step);
// If the previous instruction asked to continue, the name change will have to
// be changed into a turn
invalidateStep(steps[one_back_index]);
const auto total_angle = findTotalTurnAngle(steps[one_back_index], current_step);
steps[step_index].maneuver.instruction.direction_modifier =
getTurnDirection(total_angle);
}
steps[two_back_index] = elongate(std::move(steps[two_back_index]), one_back_step);
// If the previous instruction asked to continue, the name change will have to
// be changed into a turn
invalidateStep(steps[one_back_index]);
}
// very short segment after turn
else if (one_back_step.distance <= MAX_COLLAPSE_DISTANCE &&
isCollapsableInstruction(current_step.maneuver.instruction))
// very short segment after turn, turn location remains at one_back_step
else if (isDelayedTurn(one_back_step, current_step))
{
steps[one_back_index] = elongate(std::move(steps[one_back_index]), steps[step_index]);
// TODO check for lanes (https://github.com/Project-OSRM/osrm-backend/issues/2553)
if (compatible(one_back_step, current_step))
if (TurnType::Continue == one_back_step.maneuver.instruction.type &&
isNoticeableNameChange(steps[two_back_index], current_step))
{
steps[one_back_index] = elongate(std::move(steps[one_back_index]), steps[step_index]);
if ((TurnType::Continue == one_back_step.maneuver.instruction.type ||
TurnType::Suppressed == one_back_step.maneuver.instruction.type) &&
isNoticeableNameChange(steps[two_back_index], current_step))
{
if (current_step.maneuver.instruction.type == TurnType::OnRamp ||
current_step.maneuver.instruction.type == TurnType::OffRamp)
steps[one_back_index].maneuver.instruction.type =
current_step.maneuver.instruction.type;
else
steps[one_back_index].maneuver.instruction.type = TurnType::Turn;
}
else if (TurnType::Turn == one_back_step.maneuver.instruction.type &&
!isNoticeableNameChange(steps[two_back_index], current_step))
{
steps[one_back_index].maneuver.instruction.type = TurnType::Continue;
}
else if (TurnType::Turn == one_back_step.maneuver.instruction.type &&
!isNoticeableNameChange(steps[two_back_index], current_step))
{
steps[one_back_index].maneuver.instruction.type = TurnType::Continue;
const auto getBearing = [](bool in, const RouteStep &step) {
const auto index =
in ? step.intersections.front().in : step.intersections.front().out;
return step.intersections.front().bearings[index];
};
const auto getBearing = [](bool in, const RouteStep &step) {
const auto index =
in ? step.intersections.front().in : step.intersections.front().out;
return step.intersections.front().bearings[index];
};
// If we Merge onto the same street, we end up with a u-turn in some cases
if (bearingsAreReversed(
util::bearing::reverseBearing(getBearing(true, one_back_step)),
getBearing(false, current_step)))
{
steps[one_back_index].maneuver.instruction.type = TurnType::Continue;
steps[one_back_index].maneuver.instruction.direction_modifier =
DirectionModifier::UTurn;
}
}
else if (TurnType::Merge == one_back_step.maneuver.instruction.type &&
current_step.maneuver.instruction.type !=
TurnType::Suppressed) // This suppressed is a check for highways. We might
// need a highway-suppressed to get the turn onto a
// highway...
// If we Merge onto the same street, we end up with a u-turn in some cases
if (bearingsAreReversed(util::bearing::reverseBearing(getBearing(true, one_back_step)),
getBearing(false, current_step)))
{
steps[one_back_index].maneuver.instruction.direction_modifier =
util::guidance::mirrorDirectionModifier(
steps[one_back_index].maneuver.instruction.direction_modifier);
DirectionModifier::UTurn;
}
forwardStepSignage(steps[one_back_index], current_step);
invalidateStep(steps[step_index]);
}
}
// Potential U-Turn
else if ((one_back_step.distance <= MAX_COLLAPSE_DISTANCE ||
choiceless(current_step, one_back_step)) &&
bearingsAreReversed(util::bearing::reverseBearing(
one_back_step.intersections.front()
.bearings[one_back_step.intersections.front().in]),
current_step.intersections.front()
.bearings[current_step.intersections.front().out]) &&
compatible(one_back_step, current_step))
{
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 = !isNoticeableNameChange(steps[two_back_index], current_step);
else if (TurnType::NewName == one_back_step.maneuver.instruction.type ||
(TurnType::NewName == current_step.maneuver.instruction.type &&
steps[one_back_index].maneuver.instruction.type == TurnType::Suppressed))
steps[one_back_index].maneuver.instruction.type = TurnType::Turn;
// however, we might also deal with a dual-collapse scenario in which we have to
// additionall collapse a name-change as welll
const auto next_step_index = step_index + 1;
const bool continues_with_name_change =
(next_step_index < steps.size()) &&
((steps[next_step_index].maneuver.instruction.type == TurnType::UseLane &&
steps[next_step_index].maneuver.instruction.direction_modifier ==
DirectionModifier::Straight) ||
isCollapsableInstruction(steps[next_step_index].maneuver.instruction));
const bool u_turn_with_name_change =
continues_with_name_change && steps[next_step_index].name_id != EMPTY_NAMEID &&
!isNoticeableNameChange(steps[two_back_index], steps[next_step_index]);
if (direct_u_turn || u_turn_with_name_change)
if (TurnType::Merge == one_back_step.maneuver.instruction.type &&
current_step.maneuver.instruction.type !=
TurnType::Suppressed) // This suppressed is a check for highways. We might
// need a highway-suppressed to get the turn onto a
// highway...
{
steps[one_back_index] = elongate(std::move(steps[one_back_index]), steps[step_index]);
invalidateStep(steps[step_index]);
if (u_turn_with_name_change &&
compatible(steps[one_back_index], steps[next_step_index]))
{
steps[one_back_index] =
elongate(std::move(steps[one_back_index]), steps[next_step_index]);
invalidateStep(steps[next_step_index]); // will be skipped due to the
// continue statement at the
// beginning of this function
forwardStepSignage(steps[one_back_index], steps[two_back_index]);
}
if (direct_u_turn)
forwardStepSignage(steps[one_back_index], steps[two_back_index]);
steps[one_back_index].maneuver.instruction.type = TurnType::Continue;
steps[one_back_index].maneuver.instruction.direction_modifier =
DirectionModifier::UTurn;
util::guidance::mirrorDirectionModifier(
steps[one_back_index].maneuver.instruction.direction_modifier);
}
// on non merge-types, we check for a combined turn angle
else if (TurnType::Merge != one_back_step.maneuver.instruction.type)
{
const auto combined_angle = findTotalTurnAngle(one_back_step, current_step);
steps[one_back_index].maneuver.instruction.direction_modifier =
getTurnDirection(combined_angle);
}
steps[one_back_index].name = current_step.name;
steps[one_back_index].name_id = current_step.name_id;
invalidateStep(steps[step_index]);
}
else if (TurnType::Suppressed == current_step.maneuver.instruction.type &&
!isNoticeableNameChange(one_back_step, current_step))
{
steps[one_back_index] = elongate(std::move(steps[one_back_index]), current_step);
const auto angle = findTotalTurnAngle(one_back_step, current_step);
steps[one_back_index].maneuver.instruction.direction_modifier =
util::guidance::getTurnDirection(angle);
invalidateStep(steps[step_index]);
}
else if (TurnType::Turn == one_back_step.maneuver.instruction.type &&
TurnType::OnRamp == current_step.maneuver.instruction.type)
{
// turning onto a ramp makes the first turn into a ramp
steps[one_back_index] = elongate(std::move(steps[one_back_index]), current_step);
steps[one_back_index].maneuver.instruction.type = TurnType::OnRamp;
const auto angle = findTotalTurnAngle(one_back_step, current_step);
steps[one_back_index].maneuver.instruction.direction_modifier =
util::guidance::getTurnDirection(angle);
forwardStepSignage(steps[one_back_index], current_step);
invalidateStep(steps[step_index]);
}
}
@@ -559,10 +724,33 @@ bool isStaggeredIntersection(const RouteStep &previous, const RouteStep &current
} // namespace
// 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. Lookahead of one step.
bool collapsable(const RouteStep &step, const RouteStep &next)
{
const auto is_short_step = step.distance < MAX_COLLAPSE_DISTANCE;
const auto instruction_can_be_collapsed = isCollapsableInstruction(step.maneuver.instruction);
const auto is_use_lane = step.maneuver.instruction.type == TurnType::UseLane;
const auto lanes_dont_change =
step.intersections.front().lanes == next.intersections.front().lanes;
if (is_short_step && instruction_can_be_collapsed)
return true;
// Prevent collapsing away important lane change steps
if (is_short_step && is_use_lane && lanes_dont_change)
return true;
return false;
}
// elongate a step by another. the data is added either at the front, or the back
OSRM_ATTR_WARN_UNUSED
RouteStep elongate(RouteStep step, const RouteStep &by_step)
{
BOOST_ASSERT(step.mode == by_step.mode);
step.duration += by_step.duration;
step.distance += by_step.distance;
BOOST_ASSERT(step.mode == by_step.mode);
@@ -597,27 +785,6 @@ RouteStep elongate(RouteStep step, const RouteStep &by_step)
// Post processing can invalidate some instructions. For example StayOnRoundabout
// is turned into exit counts. These instructions are removed by the following function
// 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. Lookahead of one step.
bool collapsable(const RouteStep &step, const RouteStep &next)
{
const auto is_short_step = step.distance < MAX_COLLAPSE_DISTANCE;
const auto instruction_can_be_collapsed = isCollapsableInstruction(step.maneuver.instruction);
const auto is_use_lane = step.maneuver.instruction.type == TurnType::UseLane;
const auto lanes_dont_change =
step.intersections.front().lanes == next.intersections.front().lanes;
if (is_short_step && instruction_can_be_collapsed)
return true;
// Prevent collapsing away important lane change steps
if (is_short_step && is_use_lane && lanes_dont_change)
return true;
return false;
}
std::vector<RouteStep> removeNoTurnInstructions(std::vector<RouteStep> steps)
{
// finally clean up the post-processed instructions.
@@ -733,17 +900,6 @@ std::vector<RouteStep> collapseTurns(std::vector<RouteStep> steps)
if (steps.size() <= 2)
return 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.type == TurnType::NoTurn)
--index;
return index;
};
const auto getPreviousNameIndex = [&steps](std::size_t index) {
BOOST_ASSERT(index > 0);
BOOST_ASSERT(index < steps.size());
@@ -774,9 +930,7 @@ std::vector<RouteStep> collapseTurns(std::vector<RouteStep> steps)
{
const auto &current_step = steps[step_index];
const auto next_step_index = step_index + 1;
if (current_step.maneuver.instruction.type == TurnType::NoTurn)
continue;
const auto one_back_index = getPreviousIndex(step_index);
const auto one_back_index = getPreviousIndex(step_index, steps);
BOOST_ASSERT(one_back_index < steps.size());
const auto &one_back_step = steps[one_back_index];
@@ -808,13 +962,24 @@ std::vector<RouteStep> collapseTurns(std::vector<RouteStep> steps)
else
{
// Handle possible u-turns between highways that look like slip-roads
if (steps[getPreviousIndex(one_back_index, steps)].name_id ==
steps[step_index].name_id &&
steps[step_index].name_id != EMPTY_NAMEID)
{
steps[one_back_index].maneuver.instruction.type = TurnType::Continue;
}
else
{
steps[one_back_index].maneuver.instruction.type = TurnType::Turn;
}
if (compatible(one_back_step, current_step))
{
// Turn Types in the response depend on whether we find the same road name
// (sliproad indcating a u-turn) or if we are turning onto a different road, in
// which case we use a turn.
if (!isNoticeableNameChange(steps[getPreviousIndex(one_back_index)],
steps[step_index]))
if (!isNoticeableNameChange(steps[getPreviousIndex(one_back_index, steps)],
current_step) &&
current_step.name_id != EMPTY_NAMEID)
steps[one_back_index].maneuver.instruction.type = TurnType::Continue;
else
steps[one_back_index].maneuver.instruction.type = TurnType::Turn;
@@ -830,16 +995,9 @@ std::vector<RouteStep> collapseTurns(std::vector<RouteStep> steps)
steps[one_back_index].intersections.front().lane_description =
current_step.intersections.front().lane_description;
const auto exit_intersection = steps[step_index].intersections.front();
const auto exit_bearing = exit_intersection.bearings[exit_intersection.out];
const auto entry_intersection = steps[one_back_index].intersections.front();
const auto entry_bearing = entry_intersection.bearings[entry_intersection.in];
const double angle =
turn_angle(util::bearing::reverseBearing(entry_bearing), exit_bearing);
const auto angle = findTotalTurnAngle(one_back_step, current_step);
steps[one_back_index].maneuver.instruction.direction_modifier =
::osrm::util::guidance::getTurnDirection(angle);
util::guidance::getTurnDirection(angle);
invalidateStep(steps[step_index]);
}
else
@@ -875,7 +1033,7 @@ std::vector<RouteStep> collapseTurns(std::vector<RouteStep> steps)
isCollapsableInstruction(one_back_step.maneuver.instruction)) ||
isStaggeredIntersection(one_back_step, current_step)))
{
const auto two_back_index = getPreviousIndex(one_back_index);
const auto two_back_index = getPreviousIndex(one_back_index, steps);
BOOST_ASSERT(two_back_index < steps.size());
// valid, since one_back is collapsable or a turn and therefore not depart:
if (!isNoticeableNameChange(steps[two_back_index], current_step))
@@ -930,27 +1088,44 @@ std::vector<RouteStep> collapseTurns(std::vector<RouteStep> steps)
{
// check for one of the multiple collapse scenarios and, if possible, collapse the
// turn
const auto two_back_index = getPreviousIndex(one_back_index);
const auto two_back_index = getPreviousIndex(one_back_index, steps);
BOOST_ASSERT(two_back_index < steps.size());
collapseTurnAt(steps, two_back_index, one_back_index, step_index);
}
}
else if (one_back_index > 0 && (one_back_step.distance <= MAX_COLLAPSE_DISTANCE ||
choiceless(current_step, one_back_step)))
else if (one_back_index > 0 &&
(one_back_step.distance <= MAX_COLLAPSE_DISTANCE ||
choiceless(current_step, one_back_step) || isLinkroad(one_back_step)))
{
// check for one of the multiple collapse scenarios and, if possible, collapse the turn
const auto two_back_index = getPreviousIndex(one_back_index);
const auto two_back_index = getPreviousIndex(one_back_index, steps);
BOOST_ASSERT(two_back_index < steps.size());
// all turns that are handled lower down are also compatible
collapseTurnAt(steps, two_back_index, one_back_index, step_index);
}
if (steps[step_index].maneuver.instruction.type == TurnType::Turn)
{
const auto u_turn_one_back_index = getPreviousIndex(step_index, steps);
if (u_turn_one_back_index > 0)
{
const auto u_turn_two_back_index = getPreviousIndex(u_turn_one_back_index, steps);
if (isUTurn(steps[u_turn_one_back_index],
steps[step_index],
steps[u_turn_two_back_index]))
{
collapseUTurn(steps, u_turn_two_back_index, u_turn_one_back_index, step_index);
}
}
}
}
// handle final sliproad
if (steps.size() >= 3 &&
steps[getPreviousIndex(steps.size() - 1)].maneuver.instruction.type == TurnType::Sliproad)
steps[getPreviousIndex(steps.size() - 1, steps)].maneuver.instruction.type ==
TurnType::Sliproad)
{
steps[getPreviousIndex(steps.size() - 1)].maneuver.instruction.type = TurnType::Turn;
steps[getPreviousIndex(steps.size() - 1, steps)].maneuver.instruction.type = TurnType::Turn;
}
BOOST_ASSERT(steps.front().intersections.size() >= 1);
@@ -1260,6 +1435,7 @@ std::vector<RouteStep> buildIntersections(std::vector<RouteStep> steps)
steps[last_valid_instruction] =
elongate(std::move(steps[last_valid_instruction]), step);
step.maneuver.instruction = TurnInstruction::NO_TURN();
invalidateStep(steps[step_index]);
}
else if (!isSilent(instruction))
{
@@ -1296,16 +1472,6 @@ std::vector<RouteStep> collapseUseLane(std::vector<RouteStep> steps)
return (mask & tag) != extractor::guidance::TurnLaneType::empty;
};
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.type == TurnType::NoTurn)
--index;
return index;
};
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
@@ -1330,9 +1496,8 @@ std::vector<RouteStep> collapseUseLane(std::vector<RouteStep> steps)
const auto &step = steps[step_index];
if (step.maneuver.instruction.type == TurnType::UseLane && canCollapseUseLane(step))
{
const auto previous = getPreviousIndex(step_index);
const auto previous = getPreviousIndex(step_index, steps);
steps[previous] = elongate(std::move(steps[previous]), steps[step_index]);
// elongate(steps[step_index-1], steps[step_index]);
invalidateStep(steps[step_index]);
}
}
+4 -2
View File
@@ -467,7 +467,8 @@ Status TilePlugin::HandleRequest(const std::shared_ptr<datafacade::BaseDataFacad
for (const auto &source_ebn : edge_based_node_info)
{
// Grab a copy of the geometry leading up to the intersection.
first_geometry = facade->GetUncompressedForwardGeometry(source_ebn.second.packed_geometry_id);
first_geometry =
facade->GetUncompressedForwardGeometry(source_ebn.second.packed_geometry_id);
// We earlier saved the source and target intersection nodes for every road section.
// We can use the target node to find all road sections that lead away from
@@ -534,7 +535,8 @@ Status TilePlugin::HandleRequest(const std::shared_ptr<datafacade::BaseDataFacad
edge_based_node_info.at(target_ebn).packed_geometry_id);
// Now, calculate the sum of the weight of all the segments.
forward_weight_vector = facade->GetUncompressedForwardWeights(source_ebn.second.packed_geometry_id);
forward_weight_vector =
facade->GetUncompressedForwardWeights(source_ebn.second.packed_geometry_id);
const auto sum_node_weight = std::accumulate(
forward_weight_vector.begin(), forward_weight_vector.end(), EdgeWeight{0});