prepare solution
This commit is contained in:
parent
b6c3d1d5bf
commit
5a9eb6ef72
@ -50,6 +50,12 @@ class IntersectionGenerator
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
Intersection getConnectedRoads(const NodeID from_node, const EdgeID via_eid) const;
|
||||
|
||||
// check if two indices in an intersection can be seen as a single road in the perceived
|
||||
// intersection representation
|
||||
bool canMerge(const Intersection &intersection,
|
||||
std::size_t first_index,
|
||||
std::size_t second_index) const;
|
||||
|
||||
// Merge segregated roads to omit invalid turns in favor of treating segregated roads as
|
||||
// one.
|
||||
// This function combines roads the following way:
|
||||
@ -63,6 +69,20 @@ class IntersectionGenerator
|
||||
// 160
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
Intersection mergeSegregatedRoads(Intersection intersection) const;
|
||||
|
||||
// The counterpiece to mergeSegregatedRoads. While we can adjust roads that split up at the
|
||||
// intersection itself, it can also happen that intersections are connected to joining roads.
|
||||
//
|
||||
// * *
|
||||
// * is converted to *
|
||||
// v a --- a ---
|
||||
// v ^ +
|
||||
// v ^ +
|
||||
// b
|
||||
//
|
||||
// for the local view of b at a.
|
||||
Intersection adjustForJoiningRoads(const NodeID node_at_intersection,
|
||||
Intersection intersection) const;
|
||||
};
|
||||
|
||||
} // namespace guidance
|
||||
|
@ -30,7 +30,9 @@ IntersectionGenerator::IntersectionGenerator(
|
||||
|
||||
Intersection IntersectionGenerator::operator()(const NodeID from_node, const EdgeID via_eid) const
|
||||
{
|
||||
return getConnectedRoads(from_node, via_eid);
|
||||
auto intersection = getConnectedRoads(from_node, via_eid);
|
||||
return adjustForJoiningRoads(node_based_graph.GetTarget(via_eid),
|
||||
mergeSegregatedRoads(std::move(intersection)));
|
||||
}
|
||||
|
||||
// a
|
||||
@ -161,6 +163,40 @@ Intersection IntersectionGenerator::getConnectedRoads(const NodeID from_node,
|
||||
return mergeSegregatedRoads(std::move(intersection));
|
||||
}
|
||||
|
||||
bool IntersectionGenerator::canMerge(const Intersection &intersection,
|
||||
std::size_t first_index,
|
||||
std::size_t second_index) const
|
||||
{
|
||||
const auto &first_data = node_based_graph.GetEdgeData(intersection[first_index].turn.eid);
|
||||
const auto &second_data = node_based_graph.GetEdgeData(intersection[second_index].turn.eid);
|
||||
|
||||
// only merge named ids
|
||||
if (first_data.name_id == EMPTY_NAMEID)
|
||||
return false;
|
||||
|
||||
// need to be same name
|
||||
if (first_data.name_id != second_data.name_id)
|
||||
return false;
|
||||
|
||||
// compatibility is required
|
||||
if (first_data.travel_mode != second_data.travel_mode)
|
||||
return false;
|
||||
if (first_data.road_classification != second_data.road_classification)
|
||||
return false;
|
||||
|
||||
//may not be on a roundabout
|
||||
if( first_data.roundabout || second_data.roundabout)
|
||||
return false;
|
||||
|
||||
// exactly one of them has to be reversed
|
||||
if (first_data.reversed == second_data.reversed)
|
||||
return false;
|
||||
|
||||
// mergeable if the angle is not too big
|
||||
return angularDeviation(intersection[first_index].turn.angle,
|
||||
intersection[second_index].turn.angle) < 60;
|
||||
}
|
||||
|
||||
/*
|
||||
* Segregated Roads often merge onto a single intersection.
|
||||
* While technically representing different roads, they are
|
||||
@ -190,20 +226,6 @@ Intersection IntersectionGenerator::mergeSegregatedRoads(Intersection intersecti
|
||||
return (index + intersection.size() - 1) % intersection.size();
|
||||
};
|
||||
|
||||
const auto mergable = [&](std::size_t first, std::size_t second) -> bool {
|
||||
const auto &first_data = node_based_graph.GetEdgeData(intersection[first].turn.eid);
|
||||
const auto &second_data = node_based_graph.GetEdgeData(intersection[second].turn.eid);
|
||||
|
||||
return first_data.name_id != EMPTY_NAMEID && first_data.name_id == second_data.name_id &&
|
||||
!first_data.roundabout && !second_data.roundabout &&
|
||||
first_data.travel_mode == second_data.travel_mode &&
|
||||
first_data.road_classification == second_data.road_classification &&
|
||||
// compatible threshold
|
||||
angularDeviation(intersection[first].turn.angle, intersection[second].turn.angle) <
|
||||
60 &&
|
||||
first_data.reversed != second_data.reversed;
|
||||
};
|
||||
|
||||
const auto merge = [](const ConnectedRoad &first,
|
||||
const ConnectedRoad &second) -> ConnectedRoad {
|
||||
if (!first.entry_allowed)
|
||||
@ -275,7 +297,8 @@ Intersection IntersectionGenerator::mergeSegregatedRoads(Intersection intersecti
|
||||
// with respect to the now changed perceived location of a. If we move (a) to the left, we add
|
||||
// the difference to all angles. Otherwise we subtract it.
|
||||
bool merged_first = false;
|
||||
if (mergable(0, intersection.size() - 1))
|
||||
// these result in an adjustment of all other angles
|
||||
if (canMerge(intersection, 0, intersection.size() - 1))
|
||||
{
|
||||
merged_first = true;
|
||||
// moving `a` to the left
|
||||
@ -290,7 +313,7 @@ Intersection IntersectionGenerator::mergeSegregatedRoads(Intersection intersecti
|
||||
|
||||
intersection.pop_back();
|
||||
}
|
||||
else if (mergable(0, 1))
|
||||
else if (canMerge(intersection, 0, 1))
|
||||
{
|
||||
merged_first = true;
|
||||
// moving `a` to the right
|
||||
@ -321,7 +344,7 @@ Intersection IntersectionGenerator::mergeSegregatedRoads(Intersection intersecti
|
||||
// therefore these are handled prior to this step
|
||||
for (std::size_t index = 2; index < intersection.size(); ++index)
|
||||
{
|
||||
if (mergable(index, getRight(index)))
|
||||
if (canMerge(intersection, index, getRight(index)))
|
||||
{
|
||||
intersection[getRight(index)] =
|
||||
merge(intersection[getRight(index)], intersection[index]);
|
||||
@ -337,6 +360,53 @@ Intersection IntersectionGenerator::mergeSegregatedRoads(Intersection intersecti
|
||||
return intersection;
|
||||
}
|
||||
|
||||
// OSM can have some very steep angles for joining roads. Considering the following intersection:
|
||||
// x
|
||||
// |__________c
|
||||
// /
|
||||
// a ---d
|
||||
// \ __________b
|
||||
//
|
||||
// with c->d as a oneway
|
||||
// and d->b as a oneway, the turn von x->d is actually a turn from x->a. So when looking at the
|
||||
// intersection coming from x, we want to interpret the situation as
|
||||
// x
|
||||
// a __ d __ |__________c
|
||||
// |
|
||||
// |_______________b
|
||||
//
|
||||
// Where we see the turn to `d` as a right turn, rather than going straight.
|
||||
// We do this by adjusting the local turn angle at `x` to turn onto `d` to be reflective of this
|
||||
// situation.
|
||||
Intersection IntersectionGenerator::adjustForJoiningRoads(const NodeID node_at_intersection,
|
||||
Intersection intersection) const
|
||||
{
|
||||
for (auto &road : intersection)
|
||||
{
|
||||
// prune to short intersections to save on compute overhead
|
||||
if (node_based_graph.GetEdgeData(road.turn.eid).distance > 10)
|
||||
continue;
|
||||
|
||||
// to find out about the above situation, we need to look at the next intersection (at d in
|
||||
// the example). If the initial road can be merged to the left/right, we are about to adjust
|
||||
// the angle.
|
||||
const auto next_intersection_along_road =
|
||||
getConnectedRoads(node_at_intersection, road.turn.eid);
|
||||
if (next_intersection_along_road.size() <= 1)
|
||||
continue;
|
||||
|
||||
if (canMerge(next_intersection_along_road, 0, 1))
|
||||
{
|
||||
std::cout << "Merge at next intersection" << std::endl;
|
||||
}
|
||||
else if (canMerge(next_intersection_along_road, 0, next_intersection_along_road.size() - 1))
|
||||
{
|
||||
std::cout << "Merge at next intersection (2)" << std::endl;
|
||||
}
|
||||
}
|
||||
return intersection;
|
||||
}
|
||||
|
||||
} // namespace guidance
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
Loading…
Reference in New Issue
Block a user