improve slipway handling to allow multiple styles of turn lanes / turn roads
This commit is contained in:
committed by
Patrick Niklaus
parent
e9a0beb4e8
commit
2b5355edca
@@ -33,6 +33,16 @@ namespace
|
||||
{
|
||||
const constexpr double MAX_COLLAPSE_DISTANCE = 25;
|
||||
|
||||
inline bool choiceless(const RouteStep &step, const RouteStep &previous)
|
||||
{
|
||||
// if the next turn is choiceless, we consider longer turn roads collapsable than usually
|
||||
// accepted. We might need to improve this to find out whether we merge onto a through-street.
|
||||
return previous.distance < 3 * MAX_COLLAPSE_DISTANCE &&
|
||||
1 >= std::count(step.intersections.front().entry.begin(),
|
||||
step.intersections.front().entry.end(),
|
||||
true);
|
||||
}
|
||||
|
||||
// List of types that can be collapsed, if all other restrictions pass
|
||||
bool isCollapsableInstruction(const TurnInstruction instruction)
|
||||
{
|
||||
@@ -41,6 +51,8 @@ bool isCollapsableInstruction(const TurnInstruction instruction)
|
||||
instruction.direction_modifier == DirectionModifier::Straight) ||
|
||||
(instruction.type == TurnType::Turn &&
|
||||
instruction.direction_modifier == DirectionModifier::Straight) ||
|
||||
(instruction.type == TurnType::Continue &&
|
||||
instruction.direction_modifier == DirectionModifier::Straight) ||
|
||||
(instruction.type == TurnType::Merge);
|
||||
}
|
||||
|
||||
@@ -387,7 +399,11 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
|
||||
|
||||
BOOST_ASSERT(!one_back_step.intersections.empty() && !current_step.intersections.empty());
|
||||
// Very Short New Name
|
||||
if (collapsable(one_back_step))
|
||||
if (((collapsable(one_back_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
|
||||
{
|
||||
BOOST_ASSERT(two_back_index < steps.size());
|
||||
if (compatible(one_back_step, steps[two_back_index]))
|
||||
@@ -433,7 +449,11 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
|
||||
{
|
||||
steps[one_back_index].maneuver.instruction.type = TurnType::Continue;
|
||||
}
|
||||
else if (TurnType::Merge == one_back_step.maneuver.instruction.type)
|
||||
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...
|
||||
{
|
||||
steps[one_back_index].maneuver.instruction.direction_modifier =
|
||||
util::guidance::mirrorDirectionModifier(
|
||||
@@ -445,7 +465,8 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
|
||||
}
|
||||
}
|
||||
// Potential U-Turn
|
||||
else if (one_back_step.distance <= MAX_COLLAPSE_DISTANCE &&
|
||||
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]),
|
||||
@@ -529,6 +550,7 @@ std::vector<RouteStep> removeNoTurnInstructions(std::vector<RouteStep> steps)
|
||||
// that we come across.
|
||||
std::vector<RouteStep> postProcess(std::vector<RouteStep> steps)
|
||||
{
|
||||
print(steps);
|
||||
// the steps should always include the first/last step in form of a location
|
||||
BOOST_ASSERT(steps.size() >= 2);
|
||||
if (steps.size() == 2)
|
||||
@@ -542,14 +564,12 @@ std::vector<RouteStep> postProcess(std::vector<RouteStep> steps)
|
||||
// required. We might end up with only one of them (e.g. starting within a roundabout)
|
||||
// or having a via-point in the roundabout.
|
||||
// In this case, exits are numbered from the start of the lag.
|
||||
std::size_t last_valid_instruction = 0;
|
||||
for (std::size_t step_index = 0; step_index < steps.size(); ++step_index)
|
||||
{
|
||||
auto &step = steps[step_index];
|
||||
const auto instruction = step.maneuver.instruction;
|
||||
if (entersRoundabout(instruction))
|
||||
{
|
||||
last_valid_instruction = step_index;
|
||||
has_entered_roundabout = setUpRoundabout(step);
|
||||
|
||||
if (has_entered_roundabout && step_index + 1 < steps.size())
|
||||
@@ -570,17 +590,11 @@ std::vector<RouteStep> postProcess(std::vector<RouteStep> steps)
|
||||
// in case the we are not on a roundabout, the very first instruction
|
||||
// after the depart will be transformed into a roundabout and become
|
||||
// the first valid instruction
|
||||
last_valid_instruction = 1;
|
||||
}
|
||||
closeOffRoundabout(has_entered_roundabout, steps, step_index);
|
||||
has_entered_roundabout = false;
|
||||
on_roundabout = false;
|
||||
}
|
||||
else if (!isSilent(instruction))
|
||||
{
|
||||
// Remember the last non silent instruction
|
||||
last_valid_instruction = step_index;
|
||||
}
|
||||
}
|
||||
|
||||
// unterminated roundabout
|
||||
@@ -648,6 +662,8 @@ std::vector<RouteStep> collapseTurns(std::vector<RouteStep> steps)
|
||||
for (std::size_t step_index = 1; step_index + 1 < steps.size(); ++step_index)
|
||||
{
|
||||
const auto ¤t_step = steps[step_index];
|
||||
if( current_step.maneuver.instruction.type == TurnType::NoTurn )
|
||||
continue;
|
||||
const auto one_back_index = getPreviousIndex(step_index);
|
||||
BOOST_ASSERT(one_back_index < steps.size());
|
||||
|
||||
@@ -748,7 +764,8 @@ std::vector<RouteStep> collapseTurns(std::vector<RouteStep> steps)
|
||||
invalidateStep(steps[step_index]);
|
||||
}
|
||||
}
|
||||
else if (one_back_step.distance <= MAX_COLLAPSE_DISTANCE)
|
||||
else if (choiceless(current_step, one_back_step) ||
|
||||
one_back_step.distance <= MAX_COLLAPSE_DISTANCE)
|
||||
{
|
||||
// check for one of the multiple collapse scenarios and, if possible, collapse the
|
||||
// turn
|
||||
@@ -757,7 +774,8 @@ std::vector<RouteStep> collapseTurns(std::vector<RouteStep> steps)
|
||||
collapseTurnAt(steps, two_back_index, one_back_index, step_index);
|
||||
}
|
||||
}
|
||||
else if (one_back_index > 0 && one_back_step.distance <= MAX_COLLAPSE_DISTANCE)
|
||||
else if (one_back_index > 0 && (one_back_step.distance <= MAX_COLLAPSE_DISTANCE ||
|
||||
choiceless(current_step, 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);
|
||||
|
||||
@@ -385,7 +385,7 @@ Intersection MotorwayHandler::fromRamp(const EdgeID via_eid, Intersection inters
|
||||
{
|
||||
// circular order indicates a merge to the left (0-3 onto 4
|
||||
if (angularDeviation(intersection[1].turn.angle, STRAIGHT_ANGLE) <
|
||||
NARROW_TURN_ANGLE)
|
||||
2*NARROW_TURN_ANGLE)
|
||||
intersection[1].turn.instruction = {TurnType::Merge,
|
||||
DirectionModifier::SlightLeft};
|
||||
else // fallback
|
||||
@@ -407,12 +407,12 @@ Intersection MotorwayHandler::fromRamp(const EdgeID via_eid, Intersection inters
|
||||
if (detail::isMotorwayClass(intersection[2].turn.eid, node_based_graph) &&
|
||||
node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id !=
|
||||
EMPTY_NAMEID &&
|
||||
node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id ==
|
||||
node_based_graph.GetEdgeData(intersection[0].turn.eid).name_id)
|
||||
node_based_graph.GetEdgeData(intersection[2].turn.eid).name_id ==
|
||||
node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id)
|
||||
{
|
||||
// circular order (5-0) onto 4
|
||||
if (angularDeviation(intersection[2].turn.angle, STRAIGHT_ANGLE) <
|
||||
NARROW_TURN_ANGLE)
|
||||
2 * NARROW_TURN_ANGLE)
|
||||
intersection[2].turn.instruction = {TurnType::Merge,
|
||||
DirectionModifier::SlightRight};
|
||||
else // fallback
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "extractor/guidance/turn_analysis.hpp"
|
||||
#include "extractor/guidance/constants.hpp"
|
||||
#include "extractor/guidance/turn_analysis.hpp"
|
||||
|
||||
#include "util/coordinate.hpp"
|
||||
#include "util/coordinate_calculation.hpp"
|
||||
@@ -127,15 +127,15 @@ Intersection TurnAnalysis::handleSliproads(const EdgeID source_edge_id,
|
||||
auto intersection_node_id = node_based_graph.GetTarget(source_edge_id);
|
||||
|
||||
const auto linkTest = [this](const ConnectedRoad &road) {
|
||||
return isLinkClass(
|
||||
node_based_graph.GetEdgeData(road.turn.eid).road_classification.road_class) &&
|
||||
road.entry_allowed &&
|
||||
angularDeviation(road.turn.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE;
|
||||
return // isLinkClass(
|
||||
// node_based_graph.GetEdgeData(road.turn.eid).road_classification.road_class) &&
|
||||
!node_based_graph.GetEdgeData(road.turn.eid).roundabout && road.entry_allowed &&
|
||||
angularDeviation(road.turn.angle, STRAIGHT_ANGLE) <= 2 * NARROW_TURN_ANGLE;
|
||||
};
|
||||
|
||||
bool hasRamp =
|
||||
bool hasNarrow =
|
||||
std::find_if(intersection.begin(), intersection.end(), linkTest) != intersection.end();
|
||||
if (!hasRamp)
|
||||
if (!hasNarrow)
|
||||
return intersection;
|
||||
|
||||
const auto source_edge_data = node_based_graph.GetEdgeData(source_edge_id);
|
||||
@@ -171,6 +171,8 @@ Intersection TurnAnalysis::handleSliproads(const EdgeID source_edge_id,
|
||||
const auto next_road_next_intersection =
|
||||
intersection_generator(intersection_node_id, next_road->turn.eid);
|
||||
|
||||
const auto next_intersection_node = node_based_graph.GetTarget(next_road->turn.eid);
|
||||
|
||||
std::unordered_set<NameID> target_road_names;
|
||||
|
||||
for (const auto &road : next_road_next_intersection)
|
||||
@@ -187,7 +189,8 @@ Intersection TurnAnalysis::handleSliproads(const EdgeID source_edge_id,
|
||||
for (const auto &candidate_road : target_intersection)
|
||||
{
|
||||
const auto &candidate_data = node_based_graph.GetEdgeData(candidate_road.turn.eid);
|
||||
if (target_road_names.count(candidate_data.name_id) > 0)
|
||||
if (target_road_names.count(candidate_data.name_id) > 0 &&
|
||||
node_based_graph.GetTarget(candidate_road.turn.eid) == next_intersection_node)
|
||||
{
|
||||
road.turn.instruction.type = TurnType::Sliproad;
|
||||
break;
|
||||
@@ -196,6 +199,30 @@ Intersection TurnAnalysis::handleSliproads(const EdgeID source_edge_id,
|
||||
}
|
||||
}
|
||||
|
||||
if (next_road->turn.instruction.type == TurnType::Fork)
|
||||
{
|
||||
const auto &next_data = node_based_graph.GetEdgeData(next_road->turn.eid);
|
||||
if (next_data.name_id == source_edge_data.name_id)
|
||||
{
|
||||
if (angularDeviation(next_road->turn.angle, STRAIGHT_ANGLE) < 5)
|
||||
next_road->turn.instruction.type = TurnType::Suppressed;
|
||||
else
|
||||
next_road->turn.instruction.type = TurnType::Continue;
|
||||
next_road->turn.instruction.direction_modifier =
|
||||
getTurnDirection(next_road->turn.angle);
|
||||
}
|
||||
else if (next_data.name_id != EMPTY_NAMEID)
|
||||
{
|
||||
next_road->turn.instruction.type = TurnType::NewName;
|
||||
next_road->turn.instruction.direction_modifier =
|
||||
getTurnDirection(next_road->turn.angle);
|
||||
}
|
||||
else
|
||||
{
|
||||
next_road->turn.instruction.type = TurnType::Suppressed;
|
||||
}
|
||||
}
|
||||
|
||||
return intersection;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "extractor/guidance/turn_handler.hpp"
|
||||
#include "extractor/guidance/constants.hpp"
|
||||
#include "extractor/guidance/intersection_scenario_three_way.hpp"
|
||||
#include "extractor/guidance/toolkit.hpp"
|
||||
#include "extractor/guidance/turn_handler.hpp"
|
||||
|
||||
#include "util/guidance/toolkit.hpp"
|
||||
|
||||
@@ -377,8 +377,12 @@ std::size_t TurnHandler::findObviousTurn(const EdgeID via_edge,
|
||||
}
|
||||
|
||||
const auto out_data = node_based_graph.GetEdgeData(intersection[i].turn.eid);
|
||||
auto continue_class = node_based_graph.GetEdgeData(intersection[best_continue].turn.eid)
|
||||
.road_classification.road_class;
|
||||
if (intersection[i].entry_allowed && out_data.name_id == in_data.name_id &&
|
||||
deviation < best_continue_deviation)
|
||||
(best_continue == 0 || continue_class > out_data.road_classification.road_class ||
|
||||
(deviation < best_continue_deviation &&
|
||||
out_data.road_classification.road_class == continue_class)))
|
||||
{
|
||||
best_continue_deviation = deviation;
|
||||
best_continue = i;
|
||||
@@ -392,7 +396,12 @@ std::size_t TurnHandler::findObviousTurn(const EdgeID via_edge,
|
||||
return 0;
|
||||
|
||||
// has no obvious continued road
|
||||
if (best_continue == 0 || true)
|
||||
if (best_continue == 0 || best_continue_deviation >= 2 * NARROW_TURN_ANGLE ||
|
||||
(node_based_graph.GetEdgeData(intersection[best_continue].turn.eid)
|
||||
.road_classification.road_class ==
|
||||
node_based_graph.GetEdgeData(intersection[best].turn.eid)
|
||||
.road_classification.road_class &&
|
||||
std::abs(best_continue_deviation) > 1 && best_deviation / best_continue_deviation < 0.75))
|
||||
{
|
||||
// Find left/right deviation
|
||||
const double left_deviation = angularDeviation(
|
||||
@@ -422,8 +431,31 @@ std::size_t TurnHandler::findObviousTurn(const EdgeID via_edge,
|
||||
return best;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const double deviation =
|
||||
angularDeviation(intersection[best_continue].turn.angle, STRAIGHT_ANGLE);
|
||||
const auto &continue_data =
|
||||
node_based_graph.GetEdgeData(intersection[best_continue].turn.eid);
|
||||
if (std::abs(deviation) < 1)
|
||||
return best_continue;
|
||||
|
||||
return 0; // no obvious turn
|
||||
// check if any other similar best continues exist
|
||||
for (std::size_t i = 1; i < intersection.size(); ++i)
|
||||
{
|
||||
if (i == best_continue || !intersection[i].entry_allowed)
|
||||
continue;
|
||||
|
||||
if (angularDeviation(intersection[i].turn.angle, STRAIGHT_ANGLE) / deviation < 1.1 &&
|
||||
continue_data.road_classification.road_class ==
|
||||
node_based_graph.GetEdgeData(intersection[i].turn.eid)
|
||||
.road_classification.road_class)
|
||||
return 0;
|
||||
}
|
||||
return best_continue; // no obvious turn
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Assignment of left turns hands of to right turns.
|
||||
|
||||
Reference in New Issue
Block a user