Refactors the Turn Handler's Fork Abstraction, resolves #3457.
This commit is contained in:
parent
b8beac2d00
commit
a40abacfca
@ -49,10 +49,21 @@ class TurnHandler : public IntersectionHandler
|
|||||||
private:
|
private:
|
||||||
struct Fork
|
struct Fork
|
||||||
{
|
{
|
||||||
const Intersection::iterator right;
|
const Intersection::iterator intersection_base;
|
||||||
const Intersection::iterator left;
|
const Intersection::iterator begin;
|
||||||
|
const Intersection::iterator end;
|
||||||
const std::size_t size;
|
const std::size_t size;
|
||||||
Fork(const Intersection::iterator right, const Intersection::iterator left);
|
Fork(const Intersection::iterator intersection_base,
|
||||||
|
const Intersection::iterator begin,
|
||||||
|
const Intersection::iterator end);
|
||||||
|
ConnectedRoad &getRight() const;
|
||||||
|
ConnectedRoad &getLeft() const;
|
||||||
|
ConnectedRoad &getMiddle() const;
|
||||||
|
ConnectedRoad &getRight();
|
||||||
|
ConnectedRoad &getLeft();
|
||||||
|
ConnectedRoad &getMiddle();
|
||||||
|
std::size_t getRightIndex() const;
|
||||||
|
std::size_t getLeftIndex() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool isObviousOfTwo(const EdgeID via_edge,
|
bool isObviousOfTwo(const EdgeID via_edge,
|
||||||
|
@ -52,12 +52,12 @@ bool isEndOfRoad(const ConnectedRoad &,
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename InputIt>
|
template <typename InputIt>
|
||||||
InputIt findOutermostForkCandidate(const InputIt start, const InputIt end)
|
InputIt findOutermostForkCandidate(const InputIt begin, const InputIt end)
|
||||||
{
|
{
|
||||||
static_assert(std::is_base_of<std::input_iterator_tag,
|
static_assert(std::is_base_of<std::input_iterator_tag,
|
||||||
typename std::iterator_traits<InputIt>::iterator_category>::value,
|
typename std::iterator_traits<InputIt>::iterator_category>::value,
|
||||||
"findOutermostForkCandidate() only accepts input iterators");
|
"findOutermostForkCandidate() only accepts input iterators");
|
||||||
const auto outermost = std::adjacent_find(start, end, isOutermostForkCandidate);
|
const auto outermost = std::adjacent_find(begin, end, isOutermostForkCandidate);
|
||||||
if (outermost != end)
|
if (outermost != end)
|
||||||
{
|
{
|
||||||
return outermost;
|
return outermost;
|
||||||
@ -78,12 +78,36 @@ namespace guidance
|
|||||||
{
|
{
|
||||||
|
|
||||||
// a wrapper to handle road indices of forks at intersections
|
// a wrapper to handle road indices of forks at intersections
|
||||||
TurnHandler::Fork::Fork(const Intersection::iterator right, const Intersection::iterator left)
|
TurnHandler::Fork::Fork(const Intersection::iterator intersection_base,
|
||||||
: right(right), left(left), size((left - right) + 1)
|
const Intersection::iterator begin,
|
||||||
|
const Intersection::iterator end)
|
||||||
|
: intersection_base(intersection_base), begin(begin), end(end), size(std::distance(begin, end))
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(right < left);
|
BOOST_ASSERT(begin < end);
|
||||||
BOOST_ASSERT(size >= 2);
|
BOOST_ASSERT(size == 2 || size == 3);
|
||||||
BOOST_ASSERT(size <= 3);
|
}
|
||||||
|
|
||||||
|
ConnectedRoad &TurnHandler::Fork::getRight() { return *begin; }
|
||||||
|
ConnectedRoad &TurnHandler::Fork::getLeft() { return *(end - 1); }
|
||||||
|
ConnectedRoad &TurnHandler::Fork::getMiddle()
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(size == 3);
|
||||||
|
return *(begin + 1);
|
||||||
|
}
|
||||||
|
ConnectedRoad &TurnHandler::Fork::getRight() const { return *begin; }
|
||||||
|
ConnectedRoad &TurnHandler::Fork::getLeft() const { return *(end - 1); }
|
||||||
|
ConnectedRoad &TurnHandler::Fork::getMiddle() const
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(size == 3);
|
||||||
|
return *(begin + 1);
|
||||||
|
}
|
||||||
|
std::size_t TurnHandler::Fork::getRightIndex() const
|
||||||
|
{
|
||||||
|
return std::distance(intersection_base, begin);
|
||||||
|
}
|
||||||
|
std::size_t TurnHandler::Fork::getLeftIndex() const
|
||||||
|
{
|
||||||
|
return std::distance(intersection_base, end) - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
TurnHandler::TurnHandler(const util::NodeBasedDynamicGraph &node_based_graph,
|
TurnHandler::TurnHandler(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||||
@ -191,15 +215,12 @@ bool TurnHandler::isObviousOfTwo(const EdgeID via_edge,
|
|||||||
|
|
||||||
bool TurnHandler::hasObvious(const EdgeID &via_edge, const Fork &fork) const
|
bool TurnHandler::hasObvious(const EdgeID &via_edge, const Fork &fork) const
|
||||||
{
|
{
|
||||||
for (auto road = fork.right; road < fork.left; ++road)
|
auto obvious_road =
|
||||||
{
|
std::adjacent_find(fork.begin, fork.end, [&, this](const auto &a, const auto &b) {
|
||||||
if (isObviousOfTwo(via_edge, *road, *(road + 1)) ||
|
return this->isObviousOfTwo(via_edge, a, b) || this->isObviousOfTwo(via_edge, b, a);
|
||||||
isObviousOfTwo(via_edge, *(road + 1), *road))
|
});
|
||||||
{
|
// return whether an obvious road was found
|
||||||
return true;
|
return obvious_road != fork.end;
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// handles a turn at a three-way intersection _coming from_ `via_edge`
|
// handles a turn at a three-way intersection _coming from_ `via_edge`
|
||||||
@ -220,7 +241,7 @@ Intersection TurnHandler::handleThreeWayTurn(const EdgeID via_edge, Intersection
|
|||||||
auto fork = findFork(via_edge, intersection);
|
auto fork = findFork(via_edge, intersection);
|
||||||
if (fork && obvious_index == 0)
|
if (fork && obvious_index == 0)
|
||||||
{
|
{
|
||||||
assignFork(via_edge, *fork->left, *fork->right);
|
assignFork(via_edge, fork->getLeft(), fork->getRight());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* T Intersection
|
/* T Intersection
|
||||||
@ -306,7 +327,7 @@ Intersection TurnHandler::handleComplexTurn(const EdgeID via_edge, Intersection
|
|||||||
intersection[obvious_index]);
|
intersection[obvious_index]);
|
||||||
|
|
||||||
// assign left/right turns
|
// assign left/right turns
|
||||||
intersection = assignLeftTurns(via_edge, std::move(intersection), obvious_index + 1);
|
intersection = assignLeftTurns(via_edge, std::move(intersection), obvious_index);
|
||||||
intersection = assignRightTurns(via_edge, std::move(intersection), obvious_index);
|
intersection = assignRightTurns(via_edge, std::move(intersection), obvious_index);
|
||||||
}
|
}
|
||||||
else if (fork) // found fork
|
else if (fork) // found fork
|
||||||
@ -314,59 +335,56 @@ Intersection TurnHandler::handleComplexTurn(const EdgeID via_edge, Intersection
|
|||||||
if (fork->size == 2)
|
if (fork->size == 2)
|
||||||
{
|
{
|
||||||
const auto left_classification =
|
const auto left_classification =
|
||||||
node_based_graph.GetEdgeData((*fork->left).eid).road_classification;
|
node_based_graph.GetEdgeData(fork->getLeft().eid).road_classification;
|
||||||
const auto right_classification =
|
const auto right_classification =
|
||||||
node_based_graph.GetEdgeData((*fork->right).eid).road_classification;
|
node_based_graph.GetEdgeData(fork->getRight().eid).road_classification;
|
||||||
if (canBeSeenAsFork(left_classification, right_classification))
|
if (canBeSeenAsFork(left_classification, right_classification))
|
||||||
{
|
{
|
||||||
assignFork(via_edge, *fork->left, *fork->right);
|
assignFork(via_edge, fork->getLeft(), fork->getRight());
|
||||||
}
|
}
|
||||||
else if (left_classification.GetPriority() > right_classification.GetPriority())
|
else if (left_classification.GetPriority() > right_classification.GetPriority())
|
||||||
{
|
{
|
||||||
(*fork->right).instruction =
|
fork->getRight().instruction = getInstructionForObvious(
|
||||||
getInstructionForObvious(intersection.size(), via_edge, false, *fork->right);
|
intersection.size(), via_edge, false, fork->getRight());
|
||||||
(*fork->left).instruction = {findBasicTurnType(via_edge, *fork->left),
|
fork->getLeft().instruction = {findBasicTurnType(via_edge, fork->getLeft()),
|
||||||
DirectionModifier::SlightLeft};
|
DirectionModifier::SlightLeft};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
(*fork->left).instruction =
|
fork->getLeft().instruction =
|
||||||
getInstructionForObvious(intersection.size(), via_edge, false, *fork->left);
|
getInstructionForObvious(intersection.size(), via_edge, false, fork->getLeft());
|
||||||
(*fork->right).instruction = {findBasicTurnType(via_edge, *fork->right),
|
fork->getRight().instruction = {findBasicTurnType(via_edge, fork->getRight()),
|
||||||
DirectionModifier::SlightRight};
|
DirectionModifier::SlightRight};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (fork->size == 3)
|
else if (fork->size == 3)
|
||||||
{
|
{
|
||||||
assignFork(via_edge,
|
assignFork(via_edge,
|
||||||
*fork->left,
|
fork->getLeft(),
|
||||||
// middle fork road
|
// middle fork road
|
||||||
*(fork->right + 1),
|
fork->getMiddle(),
|
||||||
*fork->right);
|
fork->getRight());
|
||||||
}
|
}
|
||||||
// assign left/right turns
|
|
||||||
const auto left_index = fork->left - intersection.begin();
|
|
||||||
const auto right_index = fork->right - intersection.begin();
|
|
||||||
|
|
||||||
intersection = assignLeftTurns(via_edge, std::move(intersection), left_index + 1);
|
intersection = assignLeftTurns(via_edge, std::move(intersection), fork->getLeftIndex());
|
||||||
intersection = assignRightTurns(via_edge, std::move(intersection), right_index);
|
intersection = assignRightTurns(via_edge, std::move(intersection), fork->getRightIndex());
|
||||||
}
|
}
|
||||||
else if (straightmost_angle_dev < FUZZY_ANGLE_DIFFERENCE && !straightmost->entry_allowed)
|
else if (straightmost_angle_dev < FUZZY_ANGLE_DIFFERENCE && !straightmost->entry_allowed)
|
||||||
{
|
{
|
||||||
// invalid straight turn
|
// invalid straight turn
|
||||||
intersection = assignLeftTurns(via_edge, std::move(intersection), straightmost_index + 1);
|
intersection = assignLeftTurns(via_edge, std::move(intersection), straightmost_index);
|
||||||
intersection = assignRightTurns(via_edge, std::move(intersection), straightmost_index);
|
intersection = assignRightTurns(via_edge, std::move(intersection), straightmost_index);
|
||||||
}
|
}
|
||||||
// no straight turn
|
// no straight turn
|
||||||
else if (straightmost->angle > 180)
|
else if (straightmost->angle > 180)
|
||||||
{
|
{
|
||||||
// at most three turns on either side
|
// at most three turns on either side
|
||||||
intersection = assignLeftTurns(via_edge, std::move(intersection), straightmost_index);
|
intersection = assignLeftTurns(via_edge, std::move(intersection), straightmost_index - 1);
|
||||||
intersection = assignRightTurns(via_edge, std::move(intersection), straightmost_index);
|
intersection = assignRightTurns(via_edge, std::move(intersection), straightmost_index);
|
||||||
}
|
}
|
||||||
else if (straightmost->angle < 180)
|
else if (straightmost->angle < 180)
|
||||||
{
|
{
|
||||||
intersection = assignLeftTurns(via_edge, std::move(intersection), straightmost_index + 1);
|
intersection = assignLeftTurns(via_edge, std::move(intersection), straightmost_index);
|
||||||
intersection = assignRightTurns(via_edge, std::move(intersection), straightmost_index + 1);
|
intersection = assignRightTurns(via_edge, std::move(intersection), straightmost_index + 1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -384,7 +402,7 @@ Intersection TurnHandler::assignLeftTurns(const EdgeID via_edge,
|
|||||||
Intersection intersection,
|
Intersection intersection,
|
||||||
const std::size_t starting_at) const
|
const std::size_t starting_at) const
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(starting_at <= intersection.size());
|
BOOST_ASSERT(starting_at < intersection.size());
|
||||||
const auto switch_left_and_right = [](Intersection &intersection) {
|
const auto switch_left_and_right = [](Intersection &intersection) {
|
||||||
BOOST_ASSERT(!intersection.empty());
|
BOOST_ASSERT(!intersection.empty());
|
||||||
|
|
||||||
@ -396,7 +414,7 @@ Intersection TurnHandler::assignLeftTurns(const EdgeID via_edge,
|
|||||||
|
|
||||||
switch_left_and_right(intersection);
|
switch_left_and_right(intersection);
|
||||||
// account for the u-turn in the beginning
|
// account for the u-turn in the beginning
|
||||||
const auto count = intersection.size() - starting_at + 1;
|
const auto count = intersection.size() - starting_at;
|
||||||
intersection = assignRightTurns(via_edge, std::move(intersection), count);
|
intersection = assignRightTurns(via_edge, std::move(intersection), count);
|
||||||
switch_left_and_right(intersection);
|
switch_left_and_right(intersection);
|
||||||
|
|
||||||
@ -575,7 +593,7 @@ TurnHandler::findForkCandidatesByGeometry(Intersection &intersection) const
|
|||||||
// find the rightmost road that might be part of a fork
|
// find the rightmost road that might be part of a fork
|
||||||
const auto right = findOutermostForkCandidate(
|
const auto right = findOutermostForkCandidate(
|
||||||
intersection.rend() - straightmost_index - 1, intersection.rend());
|
intersection.rend() - straightmost_index - 1, intersection.rend());
|
||||||
const int right_index = intersection.rend() - right - 1;
|
const std::size_t right_index = intersection.rend() - right - 1;
|
||||||
const auto forward_right = intersection.begin() + right_index;
|
const auto forward_right = intersection.begin() + right_index;
|
||||||
// find the leftmost road that might be part of a fork
|
// find the leftmost road that might be part of a fork
|
||||||
const auto left = findOutermostForkCandidate(straightmost, intersection.end());
|
const auto left = findOutermostForkCandidate(straightmost, intersection.end());
|
||||||
@ -583,9 +601,9 @@ TurnHandler::findForkCandidatesByGeometry(Intersection &intersection) const
|
|||||||
// if the leftmost and rightmost roads with the conditions above are the same
|
// if the leftmost and rightmost roads with the conditions above are the same
|
||||||
// or if there are more than three fork candidates
|
// or if there are more than three fork candidates
|
||||||
// they cannot be fork candidates
|
// they cannot be fork candidates
|
||||||
if (forward_right < left && left - forward_right + 1 <= 3)
|
if (forward_right < left && left - forward_right < 3)
|
||||||
{
|
{
|
||||||
return Fork(forward_right, left);
|
return Fork(intersection.begin(), forward_right, left + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -601,8 +619,8 @@ bool TurnHandler::isCompatibleByRoadClass(const Intersection &intersection, cons
|
|||||||
// if any of the considered roads is a link road, it cannot be a fork
|
// if any of the considered roads is a link road, it cannot be a fork
|
||||||
// except if rightmost fork candidate is also a link road
|
// except if rightmost fork candidate is also a link road
|
||||||
const auto is_right_link_class =
|
const auto is_right_link_class =
|
||||||
node_based_graph.GetEdgeData((*fork.right).eid).road_classification.IsLinkClass();
|
node_based_graph.GetEdgeData(fork.getRight().eid).road_classification.IsLinkClass();
|
||||||
if (!std::all_of(fork.right + 1, fork.left + 1, [&](ConnectedRoad &road) {
|
if (!std::all_of(fork.begin + 1, fork.end, [&](ConnectedRoad &road) {
|
||||||
return is_right_link_class ==
|
return is_right_link_class ==
|
||||||
node_based_graph.GetEdgeData(road.eid).road_classification.IsLinkClass();
|
node_based_graph.GetEdgeData(road.eid).road_classification.IsLinkClass();
|
||||||
}))
|
}))
|
||||||
@ -610,10 +628,10 @@ bool TurnHandler::isCompatibleByRoadClass(const Intersection &intersection, cons
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::all_of(fork.right, fork.left + 1, [&](ConnectedRoad &base) {
|
return std::all_of(fork.begin, fork.end, [&](ConnectedRoad &base) {
|
||||||
const auto base_class = node_based_graph.GetEdgeData(base.eid).road_classification;
|
const auto base_class = node_based_graph.GetEdgeData(base.eid).road_classification;
|
||||||
// check that there is no turn obvious == check that all turns are non-onvious
|
// check that there is no turn obvious == check that all turns are non-onvious
|
||||||
return std::all_of(fork.right, fork.left + 1, [&](ConnectedRoad &compare) {
|
return std::all_of(fork.begin, fork.end, [&](ConnectedRoad &compare) {
|
||||||
const auto compare_class =
|
const auto compare_class =
|
||||||
node_based_graph.GetEdgeData(compare.eid).road_classification;
|
node_based_graph.GetEdgeData(compare.eid).road_classification;
|
||||||
return compare.eid == base.eid ||
|
return compare.eid == base.eid ||
|
||||||
@ -632,12 +650,12 @@ boost::optional<TurnHandler::Fork> TurnHandler::findFork(const EdgeID via_edge,
|
|||||||
{
|
{
|
||||||
// makes sure that the fork is isolated from other neighbouring streets on the left and
|
// makes sure that the fork is isolated from other neighbouring streets on the left and
|
||||||
// right side
|
// right side
|
||||||
const auto next =
|
const auto next = fork->end == intersection.end() ? intersection.begin() : (fork->end);
|
||||||
(fork->left + 1) == intersection.end() ? intersection.begin() : (fork->left + 1);
|
|
||||||
const bool separated_at_left_side =
|
const bool separated_at_left_side =
|
||||||
angularDeviation(fork->left->angle, next->angle) >= GROUP_ANGLE;
|
angularDeviation(fork->getLeft().angle, next->angle) >= GROUP_ANGLE;
|
||||||
|
BOOST_ASSERT((fork->begin - 1) >= intersection.begin());
|
||||||
const bool separated_at_right_side =
|
const bool separated_at_right_side =
|
||||||
angularDeviation(fork->right->angle, (fork->right - 1)->angle) >= GROUP_ANGLE;
|
angularDeviation(fork->getRight().angle, (fork->begin - 1)->angle) >= GROUP_ANGLE;
|
||||||
|
|
||||||
// check whether there is an obvious turn to take; forks are never obvious - if there is an
|
// check whether there is an obvious turn to take; forks are never obvious - if there is an
|
||||||
// obvious turn, it's not a fork
|
// obvious turn, it's not a fork
|
||||||
@ -647,11 +665,10 @@ boost::optional<TurnHandler::Fork> TurnHandler::findFork(const EdgeID via_edge,
|
|||||||
const bool has_compatible_classes = isCompatibleByRoadClass(intersection, *fork);
|
const bool has_compatible_classes = isCompatibleByRoadClass(intersection, *fork);
|
||||||
|
|
||||||
// check if all entries in the fork range allow entry
|
// check if all entries in the fork range allow entry
|
||||||
const bool only_valid_entries =
|
const bool only_valid_entries = intersection.hasAllValidEntries(fork->begin, fork->end);
|
||||||
intersection.hasAllValidEntries(fork->right, fork->left + 1);
|
|
||||||
|
|
||||||
const auto has_compatible_modes =
|
const auto has_compatible_modes =
|
||||||
std::all_of(fork->right, fork->left + 1, [&](const auto &road) {
|
std::all_of(fork->begin, fork->end, [&](const auto &road) {
|
||||||
return node_based_graph.GetEdgeData(road.eid).travel_mode ==
|
return node_based_graph.GetEdgeData(road.eid).travel_mode ==
|
||||||
node_based_graph.GetEdgeData(via_edge).travel_mode;
|
node_based_graph.GetEdgeData(via_edge).travel_mode;
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user