Move roads re-ordering to convertToIntersectionView

This commit is contained in:
Michael Krasnyk 2017-12-02 21:55:21 +01:00
parent 4b9e3a8068
commit c64904f5ea
2 changed files with 83 additions and 59 deletions

View File

@ -1,4 +1,11 @@
# UNRELEASED
- Changes from 5.14.3:
- Bugfixes:
- FIXED #4704: Fixed regression in bearings reordering introduced in 5.13 [#4704](https://github.com/Project-OSRM/osrm-backend/issues/4704)
- Guidance:
- CHANGED #4706: Guidance refactoring step to decouple intersection connectivity analysis and turn instructions generation [#4706](https://github.com/Project-OSRM/osrm-backend/pull/4706)
# 5.14.3
- Changes from 5.14.2:
- Bugfixes:
- FIXED #4754: U-Turn penalties are applied to straight turns.

View File

@ -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;
}
}
@ -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;
// Only one of the edges must be reversed, mark it as merged to remove from
// intersection view
@ -401,7 +364,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.);
}
}
@ -428,7 +391,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.);
}
}
@ -670,9 +633,14 @@ 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;
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;
guidance::IntersectionViewData uturn{{SPECIAL_EDGEID, 0., 0.}, false, 0.};
std::size_t allowed_uturns_number = 0;
for (const auto &outgoing_edge : outgoing_edges)
@ -682,12 +650,8 @@ convertToIntersectionView(const util::NodeBasedDynamicGraph &graph,
};
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 is_merged = merged_edges.count(outgoing_edge.edge) != 0;
const auto is_turn_allowed = intersection::isTurnAllowed(graph,
node_data_container,
restriction_map,
@ -696,8 +660,25 @@ convertToIntersectionView(const util::NodeBasedDynamicGraph &graph,
turn_lanes_data,
incoming_edge,
outgoing_edge);
// Compute angles
const auto outgoing_bearing = edge_it->perceived_bearing;
const auto initial_outgoing_bearing = edge_it->initial_bearing;
auto turn_angle = std::fmod(
std::round(angleBetween(incoming_bearing, outgoing_bearing) * 1e8) / 1e8, 360.);
auto initial_angle = angleBetween(initial_incoming_bearing, initial_outgoing_bearing);
// If angle of the allowed turn is in a neighborhood of 0° (±15°) but the initial OSM angle
// is in the opposite semi-plane then assume explicitly a U-turn to avoid incorrect
// adjustments due to numerical noise in selection of representative_coordinate
if (is_turn_allowed &&
((turn_angle < 15 && initial_angle > 180) || (turn_angle > 345 && initial_angle < 180)))
{
turn_angle = 0;
initial_angle = 0;
}
const auto is_uturn_angle = is_uturn(turn_angle);
const auto is_merged = merged_edges.count(outgoing_edge.edge) != 0;
guidance::IntersectionViewData road{
{outgoing_edge.edge, outgoing_bearing, segment_length}, is_turn_allowed, turn_angle};
@ -710,20 +691,56 @@ convertToIntersectionView(const util::NodeBasedDynamicGraph &graph,
{ // Add roads that have allowed entry or not U-turns and not merged
allowed_uturns_number += is_uturn_angle;
intersection_view.push_back(road);
// 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});
}
}
BOOST_ASSERT(uturn.eid != SPECIAL_EDGEID);
if (uturn.entry_allowed || allowed_uturns_number == 0)
{ // Add the true U-turn if it is allowed or no other U-turns found
intersection_view.insert(intersection_view.begin(), uturn);
pre_intersection_view.insert(pre_intersection_view.begin(), {uturn, 0});
}
// 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; });
// 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);
});
// 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;
}