calculate roundabout radius from circumference, fix #2716

This commit is contained in:
Ansis Brammanis 2016-09-07 12:51:10 -04:00 committed by Moritz Kobitzsch
parent 3d5a53566c
commit 7e2663f2ad
4 changed files with 49 additions and 73 deletions

View File

@ -244,8 +244,28 @@ Feature: Basic Roundabout
When I route I should get
| waypoints | route | turns |
| a,e | ab,ce,ce | depart,roundabout-exit-1,arrive |
| a,f | ab,df,df | depart,roundabout-exit-2,arrive |
| a,e | ab,ce,ce | depart,roundabout turn right exit-1,arrive |
| a,f | ab,df,df | depart,roundabout turn straight exit-2,arrive |
Scenario: Collinear in Y
Given the node map
| | a |
| | b |
| e | c |
| | d |
| | f |
And the ways
| nodes | junction |
| ab | |
| bcdb | roundabout |
| ce | |
| df | |
When I route I should get
| waypoints | route | turns |
| a,e | ab,ce,ce | depart,roundabout turn right exit-1,arrive |
| a,f | ab,df,df | depart,roundabout turn straight exit-2,arrive |
Scenario: Collinear in X,Y
Given the node map

View File

@ -231,43 +231,6 @@ Feature: Basic Roundabout
| 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 |
| | | e | | |
And the ways
| nodes | junction |
| ab | |
| bcdb | roundabout |
| ce | |
| df | |
When I route I should get
| waypoints | route | turns |
| a,e | ab,ce,ce | depart,roundabout-exit-1,arrive |
| a,f | ab,df,df | depart,roundabout-exit-2,arrive |
Scenario: Collinear in Y
Given the node map
| | a |
| | b |
| e | c |
| | d |
| | f |
And the ways
| nodes | junction |
| ab | |
| bcdb | roundabout |
| ce | |
| df | |
When I route I should get
| waypoints | route | turns |
| a,e | ab,ce,ce | depart,roundabout-exit-1,arrive |
| a,f | ab,df,df | depart,roundabout-exit-2,arrive |
Scenario: Motorway Roundabout
#See 39.933742 -75.082345
Given the node map

View File

@ -13,7 +13,7 @@
#include "util/node_based_graph.hpp"
#include "util/typedefs.hpp"
#include <set>
#include <unordered_set>
#include <utility>
#include <vector>
@ -82,7 +82,8 @@ class RoundaboutHandler : public IntersectionHandler
const bool can_exit_roundabout,
Intersection intersection) const;
bool qualifiesAsRoundaboutIntersection(const std::set<NodeID> &roundabout_nodes) const;
bool
qualifiesAsRoundaboutIntersection(const std::unordered_set<NodeID> &roundabout_nodes) const;
const CompressedEdgeContainer &compressed_edge_container;
const ProfileProperties &profile_properties;

View File

@ -8,7 +8,6 @@
#include <algorithm>
#include <cmath>
#include <unordered_set>
#include <boost/assert.hpp>
@ -145,7 +144,7 @@ void RoundaboutHandler::invalidateExitAgainstDirection(const NodeID from_nid,
// Processing segregated roads would technically require an angle of the turn to be available
// in postprocessing since we correct the turn-angle in turn-generaion.
bool RoundaboutHandler::qualifiesAsRoundaboutIntersection(
const std::set<NodeID> &roundabout_nodes) const
const std::unordered_set<NodeID> &roundabout_nodes) const
{
// translate a node ID into its respective coordinate stored in the node_info_list
const auto getCoordinate = [this](const NodeID node) {
@ -262,10 +261,6 @@ RoundaboutType RoundaboutHandler::getRoundaboutType(const NodeID nid) const
}
return continue_edge;
};
// the roundabout radius has to be the same for all locations we look at it from
// to guarantee this, we search the full roundabout for its vertices
// and select the three smallest ids
std::set<NodeID> roundabout_nodes; // needs to be sorted
// this value is a hard abort to deal with potential self-loops
const auto countRoundaboutFlags = [&](const NodeID at_node) {
@ -281,6 +276,25 @@ RoundaboutType RoundaboutHandler::getRoundaboutType(const NodeID nid) const
return count;
};
const auto getEdgeLength = [&](const NodeID source_node, EdgeID eid) {
double length = 0.;
auto last_coord = getCoordinate(source_node);
const auto &edge_bucket = compressed_edge_container.GetBucketReference(eid);
for (const auto &compressed_edge : edge_bucket)
{
const auto next_coord = getCoordinate(compressed_edge.node_id);
length += util::coordinate_calculation::haversineDistance(last_coord, next_coord);
last_coord = next_coord;
}
return length;
};
// the roundabout radius has to be the same for all locations we look at it from
// to guarantee this, we search the full roundabout for its vertices
// and select the three smallest ids
std::unordered_set<NodeID> roundabout_nodes;
double roundabout_length = 0.;
NodeID last_node = nid;
while (0 == roundabout_nodes.count(last_node))
{
@ -299,6 +313,8 @@ RoundaboutType RoundaboutHandler::getRoundaboutType(const NodeID nid) const
return RoundaboutType::None;
}
roundabout_length += getEdgeLength(last_node, eid);
last_node = node_based_graph.GetTarget(eid);
if (last_node == nid)
@ -315,31 +331,7 @@ RoundaboutType RoundaboutHandler::getRoundaboutType(const NodeID nid) const
return RoundaboutType::RoundaboutIntersection;
}
// calculate the radius of the roundabout/rotary. For two coordinates, we assume a minimal
// circle
// with both vertices right at the other side (so half their distance in meters).
// Otherwise, we construct a circle through the first tree vertices.
const auto getRadius = [&roundabout_nodes, &getCoordinate]() {
auto node_itr = roundabout_nodes.begin();
if (roundabout_nodes.size() == 2)
{
const auto first = getCoordinate(*node_itr++), second = getCoordinate(*node_itr++);
return 0.5 * util::coordinate_calculation::haversineDistance(first, second);
}
else
{
const auto first = getCoordinate(*node_itr++), second = getCoordinate(*node_itr++),
third = getCoordinate(*node_itr++);
return util::coordinate_calculation::circleRadius(first, second, third);
}
};
const double radius = getRadius();
// check whether the circle computation has gone wrong
// The radius computation can result in infinity, if the three coordinates are non-distinct.
// To stay on the safe side, we say its not a rotary
if (std::isinf(radius))
return RoundaboutType::Roundabout;
const double radius = roundabout_length / (2 * M_PI);
// Looks like a rotary: large roundabout with dedicated name
// do we have a dedicated name for the rotary, if not its a roundabout