add support for junction=circular, allowing named circular junctions to be treated as rotaries

This commit is contained in:
Moritz Kobitzsch
2016-11-24 13:29:17 +01:00
parent 4636aaabfe
commit 12d58ace10
14 changed files with 433 additions and 428 deletions
+3
View File
@@ -327,6 +327,7 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
true,
false,
parsed_way.roundabout,
parsed_way.circular,
parsed_way.is_access_restricted,
parsed_way.is_startpoint,
parsed_way.backward_travel_mode,
@@ -359,6 +360,7 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
true,
!forward_only,
parsed_way.roundabout,
parsed_way.circular,
parsed_way.is_access_restricted,
parsed_way.is_startpoint,
parsed_way.forward_travel_mode,
@@ -381,6 +383,7 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
false,
true,
parsed_way.roundabout,
parsed_way.circular,
parsed_way.is_access_restricted,
parsed_way.is_startpoint,
parsed_way.backward_travel_mode,
@@ -88,7 +88,7 @@ CoordinateExtractor::GetCoordinateAlongRoad(const NodeID intersection_node,
const auto &turn_edge_data = node_based_graph.GetEdgeData(turn_edge);
// roundabouts, check early to avoid other costly checks
if (turn_edge_data.roundabout)
if (turn_edge_data.roundabout || turn_edge_data.circular )
return TrimCoordinatesToLength(std::move(coordinates),
distance_to_skip_over_due_to_coordinate_inaccuracies)
.back();
@@ -56,7 +56,8 @@ bool IntersectionNormalizer::CanMerge(const NodeID node_at_intersection,
return false;
// may not be on a roundabout
if (first_data.roundabout || second_data.roundabout)
if (first_data.roundabout || second_data.roundabout || first_data.circular ||
second_data.circular)
return false;
// exactly one of them has to be reversed
@@ -237,7 +238,8 @@ Intersection IntersectionNormalizer::MergeSegregatedRoads(const NodeID intersect
const bool is_connected_to_roundabout = [this, &intersection]() {
for (const auto &road : intersection)
{
if (node_based_graph.GetEdgeData(road.eid).roundabout)
if (node_based_graph.GetEdgeData(road.eid).roundabout ||
node_based_graph.GetEdgeData(road.eid).circular)
return true;
}
return false;
+39 -18
View File
@@ -67,7 +67,7 @@ detail::RoundaboutFlags RoundaboutHandler::getRoundaboutFlags(
const NodeID from_nid, const EdgeID via_eid, const Intersection &intersection) const
{
const auto &in_edge_data = node_based_graph.GetEdgeData(via_eid);
bool on_roundabout = in_edge_data.roundabout;
bool on_roundabout = in_edge_data.roundabout || in_edge_data.circular;
bool can_enter_roundabout = false;
bool can_exit_roundabout_separately = false;
@@ -82,7 +82,7 @@ detail::RoundaboutFlags RoundaboutHandler::getRoundaboutFlags(
if (edge_data.reversed || !road.entry_allowed)
continue;
if (edge_data.roundabout)
if (edge_data.roundabout || edge_data.circular)
{
can_enter_roundabout = true;
}
@@ -106,7 +106,7 @@ void RoundaboutHandler::invalidateExitAgainstDirection(const NodeID from_nid,
Intersection &intersection) const
{
const auto &in_edge_data = node_based_graph.GetEdgeData(via_eid);
if (in_edge_data.roundabout)
if (in_edge_data.roundabout || in_edge_data.circular)
return;
bool past_roundabout_angle = false;
@@ -121,7 +121,7 @@ void RoundaboutHandler::invalidateExitAgainstDirection(const NodeID from_nid,
if (edge_data.reversed)
{
// remember whether we have seen the roundabout in-part
if (edge_data.roundabout)
if (edge_data.roundabout || edge_data.circular)
past_roundabout_angle = true;
continue;
@@ -131,8 +131,8 @@ void RoundaboutHandler::invalidateExitAgainstDirection(const NodeID from_nid,
// This workaround handles cases in which an exit precedes and entry. The resulting
// u-turn against the roundabout direction is invalidated.
// The sorting of the angles represents a problem for left-sided driving, though.
if (!edge_data.roundabout && node_based_graph.GetTarget(road.eid) != from_nid &&
past_roundabout_angle)
if (!edge_data.roundabout && !edge_data.circular &&
node_based_graph.GetTarget(road.eid) != from_nid && past_roundabout_angle)
{
road.entry_allowed = false;
}
@@ -176,7 +176,7 @@ bool RoundaboutHandler::qualifiesAsRoundaboutIntersection(
for (const auto edge : node_based_graph.GetAdjacentEdgeRange(node))
{
const auto edge_data = node_based_graph.GetEdgeData(edge);
if (edge_data.roundabout)
if (edge_data.roundabout || edge_data.circular)
continue;
// there is a single non-roundabout edge
@@ -224,12 +224,14 @@ RoundaboutType RoundaboutHandler::getRoundaboutType(const NodeID nid) const
std::unordered_set<unsigned> connected_names;
const auto getNextOnRoundabout = [this, &roundabout_name_ids, &connected_names](
const NodeID node) {
const NodeID node, const bool roundabout, const bool circular) {
BOOST_ASSERT(roundabout != circular);
EdgeID continue_edge = SPECIAL_EDGEID;
for (const auto edge : node_based_graph.GetAdjacentEdgeRange(node))
{
const auto &edge_data = node_based_graph.GetEdgeData(edge);
if (!edge_data.reversed && edge_data.roundabout)
if (!edge_data.reversed && (edge_data.circular == circular) &&
(edge_data.roundabout == roundabout))
{
if (SPECIAL_EDGEID != continue_edge)
{
@@ -251,7 +253,7 @@ RoundaboutType RoundaboutHandler::getRoundaboutType(const NodeID nid) const
continue_edge = edge;
}
else if (!edge_data.roundabout)
else if (!edge_data.roundabout && !edge_data.circular)
{
// remember all connected road names
connected_names.insert(edge_data.name_id);
@@ -268,7 +270,7 @@ RoundaboutType RoundaboutHandler::getRoundaboutType(const NodeID nid) const
for (const auto edge : node_based_graph.GetAdjacentEdgeRange(at_node))
{
const auto &edge_data = node_based_graph.GetEdgeData(edge);
if (edge_data.roundabout)
if (edge_data.roundabout || edge_data.circular)
count++;
}
return count;
@@ -294,6 +296,19 @@ RoundaboutType RoundaboutHandler::getRoundaboutType(const NodeID nid) const
double roundabout_length = 0.;
NodeID last_node = nid;
// cannot be find_if, as long as adjacent edge range does not work.
bool roundabout = false, circular = false;
for (const auto eid : node_based_graph.GetAdjacentEdgeRange(nid))
{
const auto data = node_based_graph.GetEdgeData(eid);
roundabout |= data.roundabout;
circular |= data.circular;
}
if (roundabout == circular)
return RoundaboutType::None;
while (0 == roundabout_nodes.count(last_node))
{
// only count exits/entry locations
@@ -304,7 +319,7 @@ RoundaboutType RoundaboutHandler::getRoundaboutType(const NodeID nid) const
if (countRoundaboutFlags(last_node) != 2)
return RoundaboutType::None;
const auto eid = getNextOnRoundabout(last_node);
const auto eid = getNextOnRoundabout(last_node, roundabout, circular);
if (eid == SPECIAL_EDGEID)
{
@@ -324,7 +339,7 @@ RoundaboutType RoundaboutHandler::getRoundaboutType(const NodeID nid) const
return RoundaboutType::None;
// More a traffic loop than anything else, currently treated as roundabout turn
if (roundabout_nodes.size() == 1)
if (roundabout_nodes.size() == 1 && roundabout)
{
return RoundaboutType::RoundaboutIntersection;
}
@@ -336,13 +351,18 @@ RoundaboutType RoundaboutHandler::getRoundaboutType(const NodeID nid) const
// This function can theoretically fail if the roundabout name is partly
// used with a reference and without. This will be fixed automatically
// when we handle references separately or if the useage is more consistent
const auto is_rotary = 1 == roundabout_name_ids.size() && //
0 == connected_names.count(*roundabout_name_ids.begin()) && //
radius > MAX_ROUNDABOUT_RADIUS;
const auto is_rotary = (1 == roundabout_name_ids.size()) &&
(circular || //
((0 == connected_names.count(*roundabout_name_ids.begin())) && //
(radius > MAX_ROUNDABOUT_RADIUS)));
if (is_rotary)
return RoundaboutType::Rotary;
// circular intersections need to be rotaries
if (circular)
return RoundaboutType::None;
// Looks like an intersection: four ways and turn angles are easy to distinguish
const auto is_roundabout_intersection = qualifiesAsRoundaboutIntersection(roundabout_nodes) &&
radius < MAX_ROUNDABOUT_INTERSECTION_RADIUS;
@@ -376,7 +396,7 @@ Intersection RoundaboutHandler::handleRoundabouts(const RoundaboutType roundabou
auto &road = intersection[idx];
auto &turn = road;
const auto &out_data = node_based_graph.GetEdgeData(road.eid);
if (out_data.roundabout)
if (out_data.roundabout || out_data.circular)
{
// TODO can forks happen in roundabouts? E.g. required lane changes
if (1 == node_based_graph.GetDirectedOutDegree(node_at_center_of_intersection))
@@ -401,6 +421,7 @@ Intersection RoundaboutHandler::handleRoundabouts(const RoundaboutType roundabou
const auto &data_of_leaving_edge = node_based_graph.GetEdgeData(eid);
if (!data_of_leaving_edge.reversed &&
!data_of_leaving_edge.roundabout &&
!data_of_leaving_edge.circular &&
!data_of_leaving_edge.road_classification.IsLowPriorityRoadClass())
return true;
}
@@ -433,7 +454,7 @@ Intersection RoundaboutHandler::handleRoundabouts(const RoundaboutType roundabou
continue;
auto &turn = road;
const auto &out_data = node_based_graph.GetEdgeData(turn.eid);
if (out_data.roundabout)
if (out_data.roundabout || out_data.circular)
{
if (can_exit_roundabout_separately)
turn.instruction = TurnInstruction::ENTER_ROUNDABOUT_AT_EXIT(
@@ -220,6 +220,7 @@ void LuaScriptingEnvironment::InitContext(LuaScriptingContext &context)
&ExtractionWay::GetTurnLanesBackward,
&ExtractionWay::SetTurnLanesBackward)
.def_readwrite("roundabout", &ExtractionWay::roundabout)
.def_readwrite("circular", &ExtractionWay::circular)
.def_readwrite("is_access_restricted", &ExtractionWay::is_access_restricted)
.def_readwrite("is_startpoint", &ExtractionWay::is_startpoint)
.def_readwrite("duration", &ExtractionWay::duration)