correctly handle roundabouts in a wide set of special cases
This commit is contained in:
parent
09931d7ad8
commit
2219b6507c
@ -129,8 +129,8 @@ class RouteAPI : public BaseAPI
|
|||||||
* the overall response consistent.
|
* the overall response consistent.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
guidance::trimShortSegments(steps, leg_geometry);
|
||||||
leg.steps = guidance::postProcess(std::move(steps));
|
leg.steps = guidance::postProcess(std::move(steps));
|
||||||
guidance::trimShortSegments(leg.steps, leg_geometry);
|
|
||||||
leg.steps = guidance::assignRelativeLocations(std::move(leg.steps), leg_geometry,
|
leg.steps = guidance::assignRelativeLocations(std::move(leg.steps), leg_geometry,
|
||||||
phantoms.source_phantom,
|
phantoms.source_phantom,
|
||||||
phantoms.target_phantom);
|
phantoms.target_phantom);
|
||||||
|
@ -50,7 +50,7 @@ void fixFinalRoundabout(std::vector<RouteStep> &steps)
|
|||||||
--propagation_index)
|
--propagation_index)
|
||||||
{
|
{
|
||||||
auto &propagation_step = steps[propagation_index];
|
auto &propagation_step = steps[propagation_index];
|
||||||
if (entersRoundabout(propagation_step.maneuver.instruction))
|
if (propagation_index == 0 || entersRoundabout(propagation_step.maneuver.instruction))
|
||||||
{
|
{
|
||||||
propagation_step.maneuver.exit = 0;
|
propagation_step.maneuver.exit = 0;
|
||||||
propagation_step.geometry_end = steps.back().geometry_begin;
|
propagation_step.geometry_end = steps.back().geometry_begin;
|
||||||
@ -141,6 +141,7 @@ void closeOffRoundabout(const bool on_roundabout,
|
|||||||
{
|
{
|
||||||
// TODO at this point, we can remember the additional name for a rotary
|
// TODO at this point, we can remember the additional name for a rotary
|
||||||
// This requires some initial thought on the data format, though
|
// This requires some initial thought on the data format, though
|
||||||
|
|
||||||
propagation_step.maneuver.exit = step.maneuver.exit;
|
propagation_step.maneuver.exit = step.maneuver.exit;
|
||||||
propagation_step.geometry_end = step.geometry_end;
|
propagation_step.geometry_end = step.geometry_end;
|
||||||
propagation_step.name = step.name;
|
propagation_step.name = step.name;
|
||||||
@ -205,6 +206,7 @@ std::vector<RouteStep> postProcess(std::vector<RouteStep> steps)
|
|||||||
#endif
|
#endif
|
||||||
// Count Street Exits forward
|
// Count Street Exits forward
|
||||||
bool on_roundabout = false;
|
bool on_roundabout = false;
|
||||||
|
bool has_entered_roundabout = false;
|
||||||
|
|
||||||
// adds an intersection to the initial route step
|
// adds an intersection to the initial route step
|
||||||
// It includes the length of the last step, until the intersection
|
// It includes the length of the last step, until the intersection
|
||||||
@ -230,12 +232,14 @@ std::vector<RouteStep> postProcess(std::vector<RouteStep> steps)
|
|||||||
if (entersRoundabout(instruction))
|
if (entersRoundabout(instruction))
|
||||||
{
|
{
|
||||||
last_valid_instruction = step_index;
|
last_valid_instruction = step_index;
|
||||||
on_roundabout = detail::setUpRoundabout(step);
|
has_entered_roundabout = detail::setUpRoundabout(step);
|
||||||
if (on_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;
|
||||||
}
|
}
|
||||||
else if (instruction.type == TurnType::StayOnRoundabout)
|
else if (instruction.type == TurnType::StayOnRoundabout)
|
||||||
{
|
{
|
||||||
|
on_roundabout = true;
|
||||||
// increase the exit number we require passing the exit
|
// increase the exit number we require passing the exit
|
||||||
step.maneuver.exit += 1;
|
step.maneuver.exit += 1;
|
||||||
if (step_index + 1 < steps.size())
|
if (step_index + 1 < steps.size())
|
||||||
@ -243,14 +247,15 @@ std::vector<RouteStep> postProcess(std::vector<RouteStep> steps)
|
|||||||
}
|
}
|
||||||
else if (leavesRoundabout(instruction))
|
else if (leavesRoundabout(instruction))
|
||||||
{
|
{
|
||||||
if (!on_roundabout)
|
if (!has_entered_roundabout)
|
||||||
{
|
{
|
||||||
// in case the we are not on a roundabout, the very first instruction
|
// in case the we are not on a roundabout, the very first instruction
|
||||||
// after the depart will be transformed into a roundabout and become
|
// after the depart will be transformed into a roundabout and become
|
||||||
// the first valid instruction
|
// the first valid instruction
|
||||||
last_valid_instruction = 1;
|
last_valid_instruction = 1;
|
||||||
}
|
}
|
||||||
detail::closeOffRoundabout(on_roundabout, steps, step_index);
|
detail::closeOffRoundabout(has_entered_roundabout, steps, step_index);
|
||||||
|
has_entered_roundabout = false;
|
||||||
on_roundabout = false;
|
on_roundabout = false;
|
||||||
}
|
}
|
||||||
else if (instruction.type == TurnType::Suppressed)
|
else if (instruction.type == TurnType::Suppressed)
|
||||||
@ -270,7 +275,7 @@ std::vector<RouteStep> postProcess(std::vector<RouteStep> steps)
|
|||||||
// unterminated roundabout
|
// unterminated roundabout
|
||||||
// Move backwards through the instructions until the start and remove the exit number
|
// Move backwards through the instructions until the start and remove the exit number
|
||||||
// A roundabout without exit translates to enter-roundabout.
|
// A roundabout without exit translates to enter-roundabout.
|
||||||
if (on_roundabout)
|
if (has_entered_roundabout || on_roundabout)
|
||||||
{
|
{
|
||||||
detail::fixFinalRoundabout(steps);
|
detail::fixFinalRoundabout(steps);
|
||||||
}
|
}
|
||||||
@ -298,6 +303,10 @@ std::vector<RouteStep> postProcess(std::vector<RouteStep> steps)
|
|||||||
|
|
||||||
void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry)
|
void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry)
|
||||||
{
|
{
|
||||||
|
#if OSRM_POST_PROCESSING_PRINT_DEBUG
|
||||||
|
std::cout << "[Pre-Trimming]" << std::endl;
|
||||||
|
print(steps);
|
||||||
|
#endif
|
||||||
// Doing this step in post-processing provides a few challenges we cannot overcome.
|
// Doing this step in post-processing provides a few challenges we cannot overcome.
|
||||||
// The removal of an initial step imposes some copy overhead in the steps, moving all later
|
// The removal of an initial step imposes some copy overhead in the steps, moving all later
|
||||||
// steps to the front.
|
// steps to the front.
|
||||||
@ -319,11 +328,10 @@ void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry)
|
|||||||
// If a route from b to c is requested, both a--b and b--c could be selected as start segment.
|
// If a route from b to c is requested, both a--b and b--c could be selected as start segment.
|
||||||
// In case of a--b, we end up with an unwanted turn saying turn-right onto b-c.
|
// In case of a--b, we end up with an unwanted turn saying turn-right onto b-c.
|
||||||
// These cases start off with an initial segment which is of zero length.
|
// These cases start off with an initial segment which is of zero length.
|
||||||
// We have to be careful though, since routing that starts in a roundabout has a valid
|
// We have to be careful though, since routing that starts in a roundabout has a valid.
|
||||||
// initial segment of length zero and we cannot delete the upcoming segment.
|
// To catch these cases correctly, we have to perform trimming prior to the post-processing
|
||||||
|
|
||||||
if (steps.front().distance <= std::numeric_limits<double>::epsilon() &&
|
if (steps.front().distance <= std::numeric_limits<double>::epsilon())
|
||||||
!entersRoundabout((steps.begin() + 1)->maneuver.instruction))
|
|
||||||
{
|
{
|
||||||
// We have to adjust the first step both for its name and the bearings
|
// We have to adjust the first step both for its name and the bearings
|
||||||
const auto ¤t_depart = steps.front();
|
const auto ¤t_depart = steps.front();
|
||||||
@ -392,8 +400,8 @@ std::vector<RouteStep> assignRelativeLocations(std::vector<RouteStep> steps,
|
|||||||
{
|
{
|
||||||
// We report the relative position of source/target to the road only within a range that is
|
// We report the relative position of source/target to the road only within a range that is
|
||||||
// sufficiently different but not full of the path
|
// sufficiently different but not full of the path
|
||||||
BOOST_ASSERT(steps.size() >= 2 );
|
BOOST_ASSERT(steps.size() >= 2);
|
||||||
BOOST_ASSERT(leg_geometry.locations.size() >= 2 );
|
BOOST_ASSERT(leg_geometry.locations.size() >= 2);
|
||||||
const constexpr double MINIMAL_RELATIVE_DISTANCE = 5., MAXIMAL_RELATIVE_DISTANCE = 300.;
|
const constexpr double MINIMAL_RELATIVE_DISTANCE = 5., MAXIMAL_RELATIVE_DISTANCE = 300.;
|
||||||
const auto distance_to_start = util::coordinate_calculation::haversineDistance(
|
const auto distance_to_start = util::coordinate_calculation::haversineDistance(
|
||||||
source_node.input_location, leg_geometry.locations[0]);
|
source_node.input_location, leg_geometry.locations[0]);
|
||||||
@ -401,7 +409,8 @@ std::vector<RouteStep> assignRelativeLocations(std::vector<RouteStep> steps,
|
|||||||
distance_to_start >= MINIMAL_RELATIVE_DISTANCE &&
|
distance_to_start >= MINIMAL_RELATIVE_DISTANCE &&
|
||||||
distance_to_start <= MAXIMAL_RELATIVE_DISTANCE
|
distance_to_start <= MAXIMAL_RELATIVE_DISTANCE
|
||||||
? angleToDirectionModifier(util::coordinate_calculation::computeAngle(
|
? angleToDirectionModifier(util::coordinate_calculation::computeAngle(
|
||||||
source_node.input_location, leg_geometry.locations.at(0), leg_geometry.locations.at(1)))
|
source_node.input_location, leg_geometry.locations.at(0),
|
||||||
|
leg_geometry.locations.at(1)))
|
||||||
: extractor::guidance::DirectionModifier::UTurn;
|
: extractor::guidance::DirectionModifier::UTurn;
|
||||||
|
|
||||||
steps.front().maneuver.instruction.direction_modifier = initial_modifier;
|
steps.front().maneuver.instruction.direction_modifier = initial_modifier;
|
||||||
|
@ -105,7 +105,7 @@ std::vector<TurnOperation> TurnAnalysis::getTurns(const NodeID from, const EdgeI
|
|||||||
// main priority: roundabouts
|
// main priority: roundabouts
|
||||||
bool on_roundabout = in_edge_data.roundabout;
|
bool on_roundabout = in_edge_data.roundabout;
|
||||||
bool can_enter_roundabout = false;
|
bool can_enter_roundabout = false;
|
||||||
bool can_exit_roundabout = false;
|
bool can_exit_roundabout_separately = false;
|
||||||
for (const auto &road : intersection)
|
for (const auto &road : intersection)
|
||||||
{
|
{
|
||||||
const auto &edge_data = node_based_graph.GetEdgeData(road.turn.eid);
|
const auto &edge_data = node_based_graph.GetEdgeData(road.turn.eid);
|
||||||
@ -117,14 +117,22 @@ std::vector<TurnOperation> TurnAnalysis::getTurns(const NodeID from, const EdgeI
|
|||||||
{
|
{
|
||||||
can_enter_roundabout = true;
|
can_enter_roundabout = true;
|
||||||
}
|
}
|
||||||
else
|
// Exiting roundabouts at an entry point is technically a data-modelling issue.
|
||||||
|
// This workaround handles cases in which an exit follows the entry.
|
||||||
|
// To correctly represent perceived exits, we only count exits leading to a
|
||||||
|
// separate vertex than the one we are coming from that are in the direction of
|
||||||
|
// the roundabout.
|
||||||
|
// The sorting of the angles represents a problem for left-sided driving, though.
|
||||||
|
// FIXME in case of left-sided driving, we have to check whether we can enter the
|
||||||
|
// roundabout later in the cycle, rather than prior.
|
||||||
|
else if (node_based_graph.GetTarget(road.turn.eid) != from && !can_enter_roundabout)
|
||||||
{
|
{
|
||||||
can_exit_roundabout = true;
|
can_exit_roundabout_separately = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (on_roundabout || can_enter_roundabout)
|
if (on_roundabout || can_enter_roundabout)
|
||||||
{
|
{
|
||||||
intersection = handleRoundabouts(via_edge, on_roundabout, can_exit_roundabout,
|
intersection = handleRoundabouts(via_edge, on_roundabout, can_exit_roundabout_separately,
|
||||||
std::move(intersection));
|
std::move(intersection));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -174,7 +182,7 @@ inline std::size_t countValid(const std::vector<ConnectedRoad> &intersection)
|
|||||||
std::vector<ConnectedRoad>
|
std::vector<ConnectedRoad>
|
||||||
TurnAnalysis::handleRoundabouts(const EdgeID via_edge,
|
TurnAnalysis::handleRoundabouts(const EdgeID via_edge,
|
||||||
const bool on_roundabout,
|
const bool on_roundabout,
|
||||||
const bool can_exit_roundabout,
|
const bool can_exit_roundabout_separately,
|
||||||
std::vector<ConnectedRoad> intersection) const
|
std::vector<ConnectedRoad> intersection) const
|
||||||
{
|
{
|
||||||
// TODO requires differentiation between roundabouts and rotaries
|
// TODO requires differentiation between roundabouts and rotaries
|
||||||
@ -220,7 +228,7 @@ TurnAnalysis::handleRoundabouts(const EdgeID via_edge,
|
|||||||
if (out_data.roundabout)
|
if (out_data.roundabout)
|
||||||
{
|
{
|
||||||
turn.instruction = TurnInstruction::ENTER_ROUNDABOUT(getTurnDirection(turn.angle));
|
turn.instruction = TurnInstruction::ENTER_ROUNDABOUT(getTurnDirection(turn.angle));
|
||||||
if (can_exit_roundabout)
|
if (can_exit_roundabout_separately)
|
||||||
{
|
{
|
||||||
if (turn.instruction.type == TurnType::EnterRotary)
|
if (turn.instruction.type == TurnType::EnterRotary)
|
||||||
turn.instruction.type = TurnType::EnterRotaryAtExit;
|
turn.instruction.type = TurnType::EnterRotaryAtExit;
|
||||||
|
Loading…
Reference in New Issue
Block a user