roundabout for segregated entry roads

This commit is contained in:
Moritz Kobitzsch 2016-04-15 17:18:55 +02:00 committed by Patrick Niklaus
parent be5b49e391
commit e59a7926a2
No known key found for this signature in database
GPG Key ID: E426891B5F978B1B
5 changed files with 172 additions and 29 deletions

View File

@ -165,6 +165,84 @@ Feature: Basic Roundabout
| j,f | jkl,def,def | depart,roundabout-exit-3,arrive |
| j,c | jkl,abc,abc | depart,roundabout-exit-4,arrive |
Scenario: Mixed Entry and Exit - segregated roads
Given the node map
| | | a | | c | | |
| | | | | | | |
| l | | | b | | | d |
| | | k | | e | | |
| j | | | h | | | f |
| | | | | | | |
| | | i | | g | | |
And the ways
| nodes | junction | oneway |
| abc | | yes |
| def | | yes |
| ghi | | yes |
| jkl | | yes |
| bkheb | roundabout | yes |
When I route I should get
| waypoints | route | turns |
| a,c | abc,abc,abc | depart,roundabout-exit-4,arrive |
| a,l | abc,jkl,jkl | depart,roundabout-exit-1,arrive |
| a,i | abc,ghi,ghi | depart,roundabout-exit-2,arrive |
| a,f | abc,def,def | depart,roundabout-exit-3,arrive |
| d,f | def,def,def | depart,roundabout-exit-4,arrive |
| d,c | def,abc,abc | depart,roundabout-exit-1,arrive |
| d,l | def,jkl,jkl | depart,roundabout-exit-2,arrive |
| d,i | def,ghi,ghi | depart,roundabout-exit-3,arrive |
| g,i | ghi,ghi,ghi | depart,roundabout-exit-4,arrive |
| g,f | ghi,def,def | depart,roundabout-exit-1,arrive |
| g,c | ghi,abc,abc | depart,roundabout-exit-2,arrive |
| g,l | ghi,jkl,jkl | depart,roundabout-exit-3,arrive |
| j,l | jkl,jkl,jkl | depart,roundabout-exit-4,arrive |
| j,i | jkl,ghi,ghi | depart,roundabout-exit-1,arrive |
| j,f | jkl,def,def | depart,roundabout-exit-2,arrive |
| j,c | jkl,abc,abc | depart,roundabout-exit-3,arrive |
Scenario: Mixed Entry and Exit - segregated roads, different names
Given the node map
| | | a | | c | | |
| | | | | | | |
| l | | | b | | | d |
| | | k | | e | | |
| j | | | h | | | f |
| | | | | | | |
| | | i | | g | | |
And the ways
| nodes | junction | oneway |
| ab | | yes |
| bc | | yes |
| de | | yes |
| ef | | yes |
| gh | | yes |
| hi | | yes |
| jk | | yes |
| kl | | yes |
| bkheb | roundabout | yes |
When I route I should get
| waypoints | route | turns |
| a,c | ab,bc,bc | depart,roundabout-exit-4,arrive |
| a,l | ab,kl,kl | depart,roundabout-exit-1,arrive |
| a,i | ab,hi,hi | depart,roundabout-exit-2,arrive |
| a,f | ab,ef,ef | depart,roundabout-exit-3,arrive |
| d,f | de,ef,ef | depart,roundabout-exit-4,arrive |
| d,c | de,bc,bc | depart,roundabout-exit-1,arrive |
| d,l | de,kl,kl | depart,roundabout-exit-2,arrive |
| d,i | de,hi,hi | depart,roundabout-exit-3,arrive |
| g,i | gh,hi,hi | depart,roundabout-exit-4,arrive |
| g,f | gh,ef,ef | depart,roundabout-exit-1,arrive |
| g,c | gh,bc,bc | depart,roundabout-exit-2,arrive |
| g,l | gh,kl,kl | depart,roundabout-exit-3,arrive |
| j,l | jk,kl,kl | depart,roundabout-exit-4,arrive |
| j,i | jk,hi,hi | depart,roundabout-exit-1,arrive |
| j,f | jk,ef,ef | depart,roundabout-exit-2,arrive |
| j,c | jk,bc,bc | depart,roundabout-exit-3,arrive |
Scenario: Collinear in X
Given the node map
| a | b | c | d | f |
@ -184,11 +262,11 @@ Feature: Basic Roundabout
Scenario: Collinear in Y
Given the node map
| a | |
| b | |
| c | e |
| d | |
| f | |
| | a |
| | b |
| e | c |
| | d |
| | f |
And the ways
| nodes | junction |

View File

@ -56,6 +56,10 @@ class RoundaboutHandler : public IntersectionHandler
const EdgeID via_eid,
const Intersection &intersection) const;
void invalidateExitAgainstDirection(const NodeID from_nid,
const EdgeID via_eid,
Intersection &intersection) const;
// decide whether we lookk at a roundabout or a rotary
bool isRotary(const NodeID nid) const;

View File

@ -25,6 +25,28 @@ namespace engine
namespace guidance
{
void print(const std::vector<RouteStep> &steps)
{
std::cout << "Path\n";
int segment = 0;
for (const auto &step : steps)
{
const auto type = static_cast<int>(step.maneuver.instruction.type);
const auto modifier = static_cast<int>(step.maneuver.instruction.direction_modifier);
std::cout << "\t[" << ++segment << "]: " << type << " " << modifier
<< " Duration: " << step.duration << " Distance: " << step.distance
<< " Geometry: " << step.geometry_begin << " " << step.geometry_end
<< " exit: " << step.maneuver.exit
<< " Intersections: " << step.maneuver.intersections.size() << " [";
for (const auto &intersection : step.maneuver.intersections)
std::cout << "(" << intersection.duration << " " << intersection.distance << ")";
std::cout << "] name[" << step.name_id << "]: " << step.name << std::endl;
}
}
namespace detail
{
bool canMergeTrivially(const RouteStep &destination, const RouteStep &source)
@ -176,28 +198,6 @@ void closeOffRoundabout(const bool on_roundabout,
}
} // namespace detail
void print(const std::vector<RouteStep> &steps)
{
std::cout << "Path\n";
int segment = 0;
for (const auto &step : steps)
{
const auto type = static_cast<int>(step.maneuver.instruction.type);
const auto modifier = static_cast<int>(step.maneuver.instruction.direction_modifier);
std::cout << "\t[" << ++segment << "]: " << type << " " << modifier
<< " Duration: " << step.duration << " Distance: " << step.distance
<< " Geometry: " << step.geometry_begin << " " << step.geometry_end
<< " exit: " << step.maneuver.exit
<< " Intersections: " << step.maneuver.intersections.size() << " [";
for (auto intersection : step.maneuver.intersections)
std::cout << "(" << intersection.duration << " " << intersection.distance << ")";
std::cout << "] name[" << step.name_id << "]: " << step.name << std::endl;
}
}
// Every Step Maneuver consists of the information until the turn.
// This list contains a set of instructions, called silent, which should
// not be part of the final output.

View File

@ -208,6 +208,15 @@ Intersection IntersectionGenerator::mergeSegregatedRoads(Intersection intersecti
if (intersection.size() == 1)
return intersection;
const bool is_connected_to_roundabout = [this,&intersection]() {
for (const auto &road : intersection)
{
if (node_based_graph.GetEdgeData(road.turn.eid).roundabout)
return true;
}
return false;
}();
// check for merges including the basic u-turn
// these result in an adjustment of all other angles
if (mergable(0, intersection.size() - 1))
@ -216,8 +225,24 @@ Intersection IntersectionGenerator::mergeSegregatedRoads(Intersection intersecti
(360 - intersection[intersection.size() - 1].turn.angle) / 2;
for (std::size_t i = 1; i + 1 < intersection.size(); ++i)
intersection[i].turn.angle += correction_factor;
// FIXME if we have a left-sided country, we need to switch this off and enable it below
intersection[0] = merge(intersection.front(), intersection.back());
intersection[0].turn.angle = 0;
if (is_connected_to_roundabout)
{
// We are merging a u-turn against the direction of a roundabout
//
// -----------> roundabout
// / \
// out in
//
// These cases have to be disabled, even if they are not forbidden specifically by a
// relation
intersection[0].entry_allowed = false;
}
intersection.pop_back();
}

View File

@ -37,6 +37,7 @@ bool RoundaboutHandler::canProcess(const NodeID from_nid,
Intersection RoundaboutHandler::
operator()(const NodeID from_nid, const EdgeID via_eid, Intersection intersection) const
{
invalidateExitAgainstDirection(from_nid, via_eid, intersection);
const auto flags = getRoundaboutFlags(from_nid, via_eid, intersection);
const bool is_rotary = isRotary(node_based_graph.GetTarget(via_eid));
// find the radius of the roundabout
@ -55,7 +56,7 @@ detail::RoundaboutFlags RoundaboutHandler::getRoundaboutFlags(
{
const auto &edge_data = node_based_graph.GetEdgeData(road.turn.eid);
// only check actual outgoing edges
if (edge_data.reversed)
if (edge_data.reversed || !road.entry_allowed )
continue;
if (edge_data.roundabout)
@ -79,6 +80,42 @@ detail::RoundaboutFlags RoundaboutHandler::getRoundaboutFlags(
return {on_roundabout, can_enter_roundabout, can_exit_roundabout_separately};
}
void RoundaboutHandler::invalidateExitAgainstDirection(const NodeID from_nid,
const EdgeID via_eid,
Intersection &intersection) const
{
const auto &in_edge_data = node_based_graph.GetEdgeData(via_eid);
if( in_edge_data.roundabout )
return;
bool past_roundabout_angle = false;
for (auto &road : intersection)
{
const auto &edge_data = node_based_graph.GetEdgeData(road.turn.eid);
// only check actual outgoing edges
if (edge_data.reversed)
{
// remember whether we have seen the roundabout in-part
if (edge_data.roundabout)
past_roundabout_angle = true;
continue;
}
// Exiting roundabouts at an entry point is technically a data-modelling issue.
// 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.
// FIXME in case of left-sided driving, we have to check whether we can enter the
// roundabout later in the cycle, rather than prior.
if (!edge_data.roundabout && node_based_graph.GetTarget(road.turn.eid) != from_nid &&
past_roundabout_angle)
{
road.entry_allowed = false;
}
}
}
bool RoundaboutHandler::isRotary(const NodeID nid) const
{
// translate a node ID into its respective coordinate stored in the node_info_list
@ -191,7 +228,6 @@ Intersection RoundaboutHandler::handleRoundabouts(const bool is_rotary,
const bool can_exit_roundabout_separately,
Intersection intersection) const
{
// TODO requires differentiation between roundabouts and rotaries
// detect via radius (get via circle through three vertices)
NodeID node_v = node_based_graph.GetTarget(via_eid);
if (on_roundabout)