Skip to content

Commit

Permalink
Move roads re-ordering to convertToIntersectionView
Browse files Browse the repository at this point in the history
  • Loading branch information
oxidase committed Dec 5, 2017
1 parent e88d784 commit 2f47634
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 74 deletions.
6 changes: 4 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# UNRELEASED
- Changes from 5.14
- Internals
- Guidance refactoring step to decouple intersection connectivity analysis and turn instructions generation
- Guidance:
- CHANGED: Guidance refactoring step to decouple intersection connectivity analysis and turn instructions generation [#4706](https://github.com/Project-OSRM/osrm-backend/pull/4706)
- Bugfixes:
- FIXED: Fixed regression in bearings reordering introduced in 5.13 [#4704](https://github.com/Project-OSRM/osrm-backend/issues/4704)

# 5.14.1
- Changes from 5.14.0
Expand Down
151 changes: 79 additions & 72 deletions src/extractor/intersection/intersection_analysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -254,47 +254,10 @@ getIntersectionOutgoingGeometries(const util::NodeBasedDynamicGraph &graph,
edge_geometries.push_back({outgoing_edge, initial_bearing, perceived_bearing, edge_length});
}

// TODO: remove to fix https://github.com/Project-OSRM/osrm-backend/issues/4704
if (!edge_geometries.empty())
{ // Adjust perceived bearings to keep the initial order with respect to the first edge
// Sort geometries by initial bearings
std::sort(edge_geometries.begin(),
edge_geometries.end(),
[base_bearing = util::bearing::reverse(edge_geometries.front().initial_bearing)](
const auto &lhs, const auto &rhs) {
return (util::bearing::angleBetween(lhs.initial_bearing, base_bearing) <
util::bearing::angleBetween(rhs.initial_bearing, base_bearing)) ||
(lhs.initial_bearing == rhs.initial_bearing &&
util::bearing::angleBetween(lhs.perceived_bearing,
rhs.perceived_bearing) < 180.);
});

// Make a bearings ordering functor
const auto base_bearing = util::bearing::reverse(edge_geometries.front().perceived_bearing);
const auto bearings_order = [base_bearing](const auto &lhs, const auto &rhs) {
return util::bearing::angleBetween(lhs.perceived_bearing, base_bearing) <
util::bearing::angleBetween(rhs.perceived_bearing, base_bearing);
};

// Check the perceived bearings order is the same as the initial one
for (auto curr = edge_geometries.begin(), next = std::next(curr);
next != edge_geometries.end();
++curr, ++next)
{
if (bearings_order(*next, *curr))
{ // If the true bearing is out of the initial order (next before current) then
// adjust the next bearing to keep the order. The adjustment angle is at most
// 0.5° or a half-angle between the current bearing and the base bearing.
// to prevent overlapping over base bearing + 360°.
const auto angle_adjustment = std::min(
.5,
util::restrictAngleToValidRange(base_bearing - curr->perceived_bearing) / 2.);
next->perceived_bearing =
util::restrictAngleToValidRange(curr->perceived_bearing + angle_adjustment);
}
}
}

// Sort edges in the clockwise bearings order
std::sort(edge_geometries.begin(), edge_geometries.end(), [](const auto &lhs, const auto &rhs) {
return lhs.perceived_bearing < rhs.perceived_bearing;
});
return edge_geometries;
}
}
Expand Down Expand Up @@ -332,8 +295,8 @@ getIntersectionGeometries(const util::NodeBasedDynamicGraph &graph,

const auto merge = findMergedBearing(graph, edge_geometries, index, next, false);

lhs.perceived_bearing = merge.second;
rhs.perceived_bearing = merge.second;
lhs.perceived_bearing = lhs.initial_bearing = merge.second;
rhs.perceived_bearing = rhs.initial_bearing = merge.second;
merged_edge_ids.insert(lhs.edge);
merged_edge_ids.insert(rhs.edge);
}
Expand Down Expand Up @@ -397,7 +360,7 @@ getIntersectionGeometries(const util::NodeBasedDynamicGraph &graph,
// b --- B ---
// /
// C
edge_geometry.perceived_bearing =
edge_geometry.perceived_bearing = edge_geometry.initial_bearing =
std::fmod(edge_geometry.perceived_bearing + 360. - offset, 360.);
}
}
Expand All @@ -424,7 +387,7 @@ getIntersectionGeometries(const util::NodeBasedDynamicGraph &graph,
// --- B --- b
//
// C
edge_geometry.perceived_bearing =
edge_geometry.perceived_bearing = edge_geometry.initial_bearing =
std::fmod(edge_geometry.perceived_bearing + offset, 360.);
}
}
Expand Down Expand Up @@ -666,15 +629,25 @@ convertToIntersectionView(const util::NodeBasedDynamicGraph &graph,
const IntersectionEdges &outgoing_edges,
const std::unordered_set<EdgeID> &merged_edges)
{
const auto incoming_bearing = findEdgeBearing(edge_geometries, incoming_edge.edge);
using util::bearing::angleBetween;

guidance::IntersectionView intersection_view;
guidance::IntersectionViewData uturn_road{{SPECIAL_EDGEID, 0., 0.}, false, 0.};
const auto edge_it = findEdge(edge_geometries, incoming_edge.edge);
const auto incoming_bearing = edge_it->perceived_bearing;
const auto initial_incoming_bearing = edge_it->initial_bearing;

using IntersectionViewDataWithAngle = std::pair<guidance::IntersectionViewData, double>;
std::vector<IntersectionViewDataWithAngle> pre_intersection_view{
{{{SPECIAL_EDGEID, 0., 0.}, false, 0.}, 0.}};
for (const auto &outgoing_edge : outgoing_edges)
{
const auto outgoing_bearing = findEdgeBearing(edge_geometries, outgoing_edge.edge);
const auto segment_length = findEdgeLength(edge_geometries, outgoing_edge.edge);
const auto turn_angle = util::bearing::angleBetween(incoming_bearing, outgoing_bearing);
const auto edge_it = findEdge(edge_geometries, outgoing_edge.edge);
const auto outgoing_bearing = edge_it->perceived_bearing;
const auto initial_outgoing_bearing = edge_it->initial_bearing;
const auto segment_length = edge_it->length;
const auto turn_angle = std::fmod(
std::round(util::bearing::angleBetween(incoming_bearing, outgoing_bearing) * 1e8) / 1e8,
360.);
const auto initial_angle = angleBetween(initial_incoming_bearing, initial_outgoing_bearing);
const auto is_turn_allowed = intersection::isTurnAllowed(graph,
node_data_container,
restriction_map,
Expand All @@ -684,38 +657,72 @@ convertToIntersectionView(const util::NodeBasedDynamicGraph &graph,
incoming_edge,
outgoing_edge);

const auto is_uturn = [](const auto angle) {
return std::fabs(angle) < std::numeric_limits<double>::epsilon();
};

// Don't include merged edges that have no entry but always include U-turn roads
const auto is_uturn = std::fabs(turn_angle) < std::numeric_limits<double>::epsilon();
if (graph.GetEdgeData(outgoing_edge.edge).reversed &&
merged_edges.count(outgoing_edge.edge) != 0 && !is_uturn)
merged_edges.count(outgoing_edge.edge) != 0 && !is_uturn(turn_angle))
continue;

if (is_uturn)
guidance::IntersectionViewData road{
{outgoing_edge.edge, outgoing_bearing, segment_length}, is_turn_allowed, turn_angle};
if (is_uturn(turn_angle))
{ // Prefer U-turns that have allowed entry
if (!uturn_road.entry_allowed)
if (!pre_intersection_view.front().first.entry_allowed)
{
uturn_road = {{outgoing_edge.edge, outgoing_bearing, segment_length},
is_turn_allowed,
turn_angle};
pre_intersection_view.front() = {road, 0.};
}
continue;
}

intersection_view.push_back({{outgoing_edge.edge,
outgoing_bearing,
findEdgeLength(edge_geometries, outgoing_edge.edge)},
is_turn_allowed,
turn_angle});
else
{
// Adjust computed initial turn angle for non-U-turn road edge cases:
// 1) use 0° or 360° if the road has 0° initial angle
// 2) use turn angle if the smallest arc between turn and initial angles passes 0°
const auto use_turn_angle = (turn_angle > 270 && initial_angle < 90) ||
(turn_angle < 90 && initial_angle > 270);
const auto adjusted_angle = is_uturn(initial_angle)
? (turn_angle > 180. ? 360. : 0.)
: use_turn_angle ? turn_angle : initial_angle;
pre_intersection_view.push_back({road, adjusted_angle});
}
}

// Add the U-turn road
BOOST_ASSERT(uturn_road.eid != SPECIAL_EDGEID);
intersection_view.push_back(uturn_road);
BOOST_ASSERT(pre_intersection_view.front().first.eid != SPECIAL_EDGEID);

// Order roads in counter-clockwise order starting from the U-turn edge in the OSM order
std::stable_sort(pre_intersection_view.begin(),
pre_intersection_view.end(),
[](const auto &lhs, const auto &rhs) {
return std::tie(lhs.second, lhs.first.angle) <
std::tie(rhs.second, rhs.first.angle);
});

// Order roads in counter-clockwise order starting from the U-turn edge
std::sort(intersection_view.begin(),
intersection_view.end(),
[](const auto &lhs, const auto &rhs) { return lhs.angle < rhs.angle; });
// Adjust perceived bearings to keep the initial OSM order with respect to the first edge
for (auto curr = pre_intersection_view.begin(), next = std::next(curr);
next != pre_intersection_view.end();
++curr, ++next)
{
// Check the the perceived angles order is the same as the initial OSM one
if (next->first.angle < curr->first.angle)
{ // If the true bearing is out of the initial order (next before current) then
// adjust the next road angle to keep the order. The adjustment angle is at most
// 0.5° or a half-angle between the current angle and 360° to prevent overlapping
const auto angle_adjustment =
std::min(.5, util::restrictAngleToValidRange(360. - curr->first.angle) / 2.);
next->first.angle =
util::restrictAngleToValidRange(curr->first.angle + angle_adjustment);
}
}

// Copy intersection view data
guidance::IntersectionView intersection_view;
intersection_view.reserve(pre_intersection_view.size());
std::transform(pre_intersection_view.begin(),
pre_intersection_view.end(),
std::back_inserter(intersection_view),
[](const auto &road) { return road.first; });

return intersection_view;
}
Expand Down

0 comments on commit 2f47634

Please sign in to comment.