introduce roundabout-turns into instruction set
This commit is contained in:
parent
8d68d4c050
commit
1544a08ea2
@ -1,3 +1,11 @@
|
|||||||
|
# 5.1.0
|
||||||
|
- API:
|
||||||
|
- added roundabout-turn instruction. The instruction indicates a small roundabout that is treated as an intersection
|
||||||
|
(turn right at the roundabout for first exit, go straight at the roundabout...)
|
||||||
|
|
||||||
|
- Infrastructure
|
||||||
|
- BREAKING: reordered internal instruction types. This breaks the data format
|
||||||
|
|
||||||
# 5.0.0
|
# 5.0.0
|
||||||
Changes with regard 5.0.0 RC2:
|
Changes with regard 5.0.0 RC2:
|
||||||
- API:
|
- API:
|
||||||
|
369
features/guidance/roundabout-turn.feature
Normal file
369
features/guidance/roundabout-turn.feature
Normal file
@ -0,0 +1,369 @@
|
|||||||
|
@routing @guidance
|
||||||
|
Feature: Basic Roundabout
|
||||||
|
|
||||||
|
Background:
|
||||||
|
Given the profile "car"
|
||||||
|
Given a grid size of 3 meters
|
||||||
|
|
||||||
|
Scenario: Enter and Exit
|
||||||
|
Given the node map
|
||||||
|
| | | a | | |
|
||||||
|
| | | b | | |
|
||||||
|
| h | g | | c | d |
|
||||||
|
| | | e | | |
|
||||||
|
| | | f | | |
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | junction |
|
||||||
|
| ab | |
|
||||||
|
| cd | |
|
||||||
|
| ef | |
|
||||||
|
| gh | |
|
||||||
|
| bgecb | roundabout |
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| waypoints | route | turns |
|
||||||
|
| a,d | ab,cd,cd | depart,roundabout_turn left exit-3,arrive |
|
||||||
|
| a,f | ab,ef,ef | depart,roundabout_turn straight exit-2,arrive |
|
||||||
|
| a,h | ab,gh,gh | depart,roundabout_turn right exit-1,arrive |
|
||||||
|
| d,f | cd,ef,ef | depart,roundabout_turn left exit-3,arrive |
|
||||||
|
| d,h | cd,gh,gh | depart,roundabout_turn straight exit-2,arrive |
|
||||||
|
| d,a | cd,ab,ab | depart,roundabout_turn right exit-1,arrive |
|
||||||
|
| f,h | ef,gh,gh | depart,roundabout_turn left exit-3,arrive |
|
||||||
|
| f,a | ef,ab,ab | depart,roundabout_turn straight exit-2,arrive |
|
||||||
|
| f,d | ef,cd,cd | depart,roundabout_turn right exit-1,arrive |
|
||||||
|
| h,a | gh,ab,ab | depart,roundabout_turn left exit-3,arrive |
|
||||||
|
| h,d | gh,cd,cd | depart,roundabout_turn straight exit-2,arrive |
|
||||||
|
| h,f | gh,ef,ef | depart,roundabout_turn right exit-1,arrive |
|
||||||
|
|
||||||
|
Scenario: Enter and Exit - Rotated
|
||||||
|
Given the node map
|
||||||
|
| a | | | d |
|
||||||
|
| | b | c | |
|
||||||
|
| | g | e | |
|
||||||
|
| h | | | f |
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | junction |
|
||||||
|
| ab | |
|
||||||
|
| cd | |
|
||||||
|
| ef | |
|
||||||
|
| gh | |
|
||||||
|
| bgecb | roundabout |
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| waypoints | route | turns |
|
||||||
|
| a,d | ab,cd,cd | depart,roundabout_turn left exit-3,arrive |
|
||||||
|
| a,f | ab,ef,ef | depart,roundabout_turn straight exit-2,arrive |
|
||||||
|
| a,h | ab,gh,gh | depart,roundabout_turn right exit-1,arrive |
|
||||||
|
| d,f | cd,ef,ef | depart,roundabout_turn left exit-3,arrive |
|
||||||
|
| d,h | cd,gh,gh | depart,roundabout_turn straight exit-2,arrive |
|
||||||
|
| d,a | cd,ab,ab | depart,roundabout_turn right exit-1,arrive |
|
||||||
|
| f,h | ef,gh,gh | depart,roundabout_turn left exit-3,arrive |
|
||||||
|
| f,a | ef,ab,ab | depart,roundabout_turn straight exit-2,arrive |
|
||||||
|
| f,d | ef,cd,cd | depart,roundabout_turn right exit-1,arrive |
|
||||||
|
| h,a | gh,ab,ab | depart,roundabout_turn left exit-3,arrive |
|
||||||
|
| h,d | gh,cd,cd | depart,roundabout_turn straight exit-2,arrive |
|
||||||
|
| h,f | gh,ef,ef | depart,roundabout_turn right exit-1,arrive |
|
||||||
|
|
||||||
|
Scenario: Only Enter
|
||||||
|
Given the node map
|
||||||
|
| | | a | | |
|
||||||
|
| | | b | | |
|
||||||
|
| d | c | | g | h |
|
||||||
|
| | | e | | |
|
||||||
|
| | | f | | |
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | junction |
|
||||||
|
| ab | |
|
||||||
|
| cd | |
|
||||||
|
| ef | |
|
||||||
|
| gh | |
|
||||||
|
| bcegb | roundabout |
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| waypoints | route | turns |
|
||||||
|
| a,c | ab,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
|
||||||
|
| a,e | ab,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
|
||||||
|
| a,g | ab,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
|
||||||
|
| d,e | cd,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
|
||||||
|
| d,g | cd,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
|
||||||
|
| d,b | cd,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
|
||||||
|
| f,g | ef,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
|
||||||
|
| f,b | ef,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
|
||||||
|
| f,c | ef,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
|
||||||
|
| h,b | gh,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
|
||||||
|
| h,c | gh,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
|
||||||
|
| h,e | gh,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
|
||||||
|
|
||||||
|
Scenario: Only Exit
|
||||||
|
Given the node map
|
||||||
|
| | | a | | |
|
||||||
|
| | | b | | |
|
||||||
|
| d | c | | g | h |
|
||||||
|
| | | e | | |
|
||||||
|
| | | f | | |
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | junction |
|
||||||
|
| ab | |
|
||||||
|
| cd | |
|
||||||
|
| ef | |
|
||||||
|
| gh | |
|
||||||
|
| bcegb | roundabout |
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| waypoints | route | turns |
|
||||||
|
| b,d | bcegb,cd,cd | depart,roundabout-exit-1,arrive |
|
||||||
|
| b,f | bcegb,ef,ef | depart,roundabout-exit-2,arrive |
|
||||||
|
| b,h | bcegb,gh,gh | depart,roundabout-exit-3,arrive |
|
||||||
|
| c,f | bcegb,ef,ef | depart,roundabout-exit-1,arrive |
|
||||||
|
| c,h | bcegb,gh,gh | depart,roundabout-exit-2,arrive |
|
||||||
|
| c,a | bcegb,ab,ab | depart,roundabout-exit-3,arrive |
|
||||||
|
| e,h | bcegb,gh,gh | depart,roundabout-exit-1,arrive |
|
||||||
|
| e,a | bcegb,ab,ab | depart,roundabout-exit-2,arrive |
|
||||||
|
| e,d | bcegb,cd,cd | depart,roundabout-exit-3,arrive |
|
||||||
|
| g,a | bcegb,ab,ab | depart,roundabout-exit-1,arrive |
|
||||||
|
| g,d | bcegb,cd,cd | depart,roundabout-exit-2,arrive |
|
||||||
|
| g,f | bcegb,ef,ef | depart,roundabout-exit-3,arrive |
|
||||||
|
#phantom node snapping can result in a full round-trip here, therefore we cannot test b->a and the other direct exits
|
||||||
|
|
||||||
|
Scenario: Drive Around
|
||||||
|
Given the node map
|
||||||
|
| | | a | | |
|
||||||
|
| | | b | | |
|
||||||
|
| d | c | | g | h |
|
||||||
|
| | | e | | |
|
||||||
|
| | | f | | |
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | junction |
|
||||||
|
| ab | |
|
||||||
|
| cd | |
|
||||||
|
| ef | |
|
||||||
|
| gh | |
|
||||||
|
| bcegb | roundabout |
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| waypoints | route | turns |
|
||||||
|
| b,c | bcegb,bcegb | depart,arrive |
|
||||||
|
| b,e | bcegb,bcegb | depart,arrive |
|
||||||
|
| b,g | bcegb,bcegb | depart,arrive |
|
||||||
|
| c,e | bcegb,bcegb | depart,arrive |
|
||||||
|
| c,g | bcegb,bcegb | depart,arrive |
|
||||||
|
| c,b | bcegb,bcegb | depart,arrive |
|
||||||
|
| e,g | bcegb,bcegb | depart,arrive |
|
||||||
|
| e,b | bcegb,bcegb | depart,arrive |
|
||||||
|
| e,c | bcegb,bcegb | depart,arrive |
|
||||||
|
| g,b | bcegb,bcegb | depart,arrive |
|
||||||
|
| g,c | bcegb,bcegb | depart,arrive |
|
||||||
|
| g,e | bcegb,bcegb | depart,arrive |
|
||||||
|
|
||||||
|
Scenario: Mixed Entry and Exit - Not an Intersection
|
||||||
|
Given the node map
|
||||||
|
| | c | | a | |
|
||||||
|
| j | | b | | f |
|
||||||
|
| | k | | e | |
|
||||||
|
| l | | h | | d |
|
||||||
|
| | g | | i | |
|
||||||
|
|
||||||
|
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-1,arrive |
|
||||||
|
| a,l | abc,jkl,jkl | depart,roundabout-exit-2,arrive |
|
||||||
|
| a,i | abc,ghi,ghi | depart,roundabout-exit-3,arrive |
|
||||||
|
| a,f | abc,def,def | depart,roundabout-exit-4,arrive |
|
||||||
|
| d,f | def,def,def | depart,roundabout-exit-1,arrive |
|
||||||
|
| d,c | def,abc,abc | depart,roundabout-exit-2,arrive |
|
||||||
|
| d,l | def,jkl,jkl | depart,roundabout-exit-3,arrive |
|
||||||
|
| d,i | def,ghi,ghi | depart,roundabout-exit-4,arrive |
|
||||||
|
| g,i | ghi,ghi,ghi | depart,roundabout-exit-1,arrive |
|
||||||
|
| g,f | ghi,def,def | depart,roundabout-exit-2,arrive |
|
||||||
|
| g,c | ghi,abc,abc | depart,roundabout-exit-3,arrive |
|
||||||
|
| g,l | ghi,jkl,jkl | depart,roundabout-exit-4,arrive |
|
||||||
|
| j,l | jkl,jkl,jkl | depart,roundabout-exit-1,arrive |
|
||||||
|
| j,i | jkl,ghi,ghi | depart,roundabout-exit-2,arrive |
|
||||||
|
| j,f | jkl,def,def | depart,roundabout-exit-3,arrive |
|
||||||
|
| j,c | jkl,abc,abc | depart,roundabout-exit-4,arrive |
|
||||||
|
|
||||||
|
Scenario: Segregated roads - Not an intersection
|
||||||
|
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: 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 X,Y
|
||||||
|
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_turn straight exit-1,arrive |
|
||||||
|
| a,f | ab,df,df | depart,roundabout_turn left exit-2,arrive |
|
||||||
|
|
||||||
|
Scenario: Collinear in X,Y
|
||||||
|
Given the node map
|
||||||
|
| a | | |
|
||||||
|
| d | | |
|
||||||
|
| b | c | f |
|
||||||
|
| e | | |
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | junction |
|
||||||
|
| ad | |
|
||||||
|
| bcdb | roundabout |
|
||||||
|
| be | |
|
||||||
|
| cf | |
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| waypoints | route | turns |
|
||||||
|
| a,e | ad,be,be | depart,roundabout_turn straight exit-1,arrive |
|
||||||
|
| a,f | ad,cf,cf | depart,roundabout_turn left exit-2,arrive |
|
||||||
|
|
||||||
|
Scenario: Collinear in X,Y
|
||||||
|
Given the node map
|
||||||
|
| a | | |
|
||||||
|
| c | | |
|
||||||
|
| d | b | f |
|
||||||
|
| e | | |
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | junction |
|
||||||
|
| ac | |
|
||||||
|
| bcdb | roundabout |
|
||||||
|
| de | |
|
||||||
|
| bf | |
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| waypoints | route | turns |
|
||||||
|
| a,e | ac,de,de | depart,roundabout_turn straight exit-1,arrive |
|
||||||
|
| a,f | ac,bf,bf | depart,roundabout_turn left exit-2,arrive |
|
||||||
|
|
||||||
|
Scenario: Enter and Exit -- too complex
|
||||||
|
Given the node map
|
||||||
|
| j | | a | | |
|
||||||
|
| | i | b | | |
|
||||||
|
| | g | | c | d |
|
||||||
|
| h | | e | | |
|
||||||
|
| | | f | | |
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | junction |
|
||||||
|
| ab | |
|
||||||
|
| ij | |
|
||||||
|
| cd | |
|
||||||
|
| ef | |
|
||||||
|
| gh | |
|
||||||
|
| bigecb | roundabout |
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| waypoints | route | turns |
|
||||||
|
| a,d | ab,cd,cd | depart,roundabout-exit-4,arrive |
|
||||||
|
| a,f | ab,ef,ef | depart,roundabout-exit-3,arrive |
|
||||||
|
| a,h | ab,gh,gh | depart,roundabout-exit-2,arrive |
|
||||||
|
| d,f | cd,ef,ef | depart,roundabout-exit-4,arrive |
|
||||||
|
| d,h | cd,gh,gh | depart,roundabout-exit-3,arrive |
|
||||||
|
| d,a | cd,ab,ab | depart,roundabout-exit-1,arrive |
|
||||||
|
| f,h | ef,gh,gh | depart,roundabout-exit-4,arrive |
|
||||||
|
| f,a | ef,ab,ab | depart,roundabout-exit-2,arrive |
|
||||||
|
| f,d | ef,cd,cd | depart,roundabout-exit-1,arrive |
|
||||||
|
| h,a | gh,ab,ab | depart,roundabout-exit-3,arrive |
|
||||||
|
| h,d | gh,cd,cd | depart,roundabout-exit-2,arrive |
|
||||||
|
| h,f | gh,ef,ef | depart,roundabout-exit-1,arrive |
|
||||||
|
|
||||||
|
Scenario: Enter and Exit -- Non-Distinct
|
||||||
|
Given the node map
|
||||||
|
| | | a | | |
|
||||||
|
| | | b | | |
|
||||||
|
| | g | | c | d |
|
||||||
|
| | | e | | |
|
||||||
|
| h | | f | | |
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | junction |
|
||||||
|
| ab | |
|
||||||
|
| cd | |
|
||||||
|
| ef | |
|
||||||
|
| gh | |
|
||||||
|
| bgecb | roundabout |
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| waypoints | route | turns |
|
||||||
|
| a,d | ab,cd,cd | depart,roundabout-exit-3,arrive |
|
||||||
|
| a,f | ab,ef,ef | depart,roundabout-exit-2,arrive |
|
||||||
|
| a,h | ab,gh,gh | depart,roundabout-exit-1,arrive |
|
||||||
|
| d,f | cd,ef,ef | depart,roundabout-exit-3,arrive |
|
||||||
|
| d,h | cd,gh,gh | depart,roundabout-exit-2,arrive |
|
||||||
|
| d,a | cd,ab,ab | depart,roundabout-exit-1,arrive |
|
||||||
|
| f,h | ef,gh,gh | depart,roundabout-exit-3,arrive |
|
||||||
|
| f,a | ef,ab,ab | depart,roundabout-exit-2,arrive |
|
||||||
|
| f,d | ef,cd,cd | depart,roundabout-exit-1,arrive |
|
||||||
|
| h,a | gh,ab,ab | depart,roundabout-exit-3,arrive |
|
||||||
|
| h,d | gh,cd,cd | depart,roundabout-exit-2,arrive |
|
||||||
|
| h,f | gh,ef,ef | depart,roundabout-exit-1,arrive |
|
||||||
|
|
@ -149,6 +149,8 @@ module.exports = function () {
|
|||||||
return v.rotary_name + '-exit-' + v.maneuver.exit;
|
return v.rotary_name + '-exit-' + v.maneuver.exit;
|
||||||
else
|
else
|
||||||
return 'rotary-exit-' + v.maneuver.exit;
|
return 'rotary-exit-' + v.maneuver.exit;
|
||||||
|
case 'roundabout_turn':
|
||||||
|
return v.maneuver.type + ' ' + v.maneuver.modifier + ' exit-' + v.maneuver.exit;
|
||||||
// FIXME this is a little bit over-simplistic for merge/fork instructions
|
// FIXME this is a little bit over-simplistic for merge/fork instructions
|
||||||
default:
|
default:
|
||||||
return v.maneuver.type + ' ' + v.maneuver.modifier;
|
return v.maneuver.type + ' ' + v.maneuver.modifier;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#ifndef OSRM_UTIL_GUIDANCE_TOOLKIT_HPP_
|
#ifndef OSRM_ENGINE_GUIDANCE_TOOLKIT_HPP_
|
||||||
#define OSRM_UTIL_GUIDANCE_TOOLKIT_HPP_
|
#define OSRM_ENGINE_GUIDANCE_TOOLKIT_HPP_
|
||||||
|
|
||||||
#include "extractor/guidance/turn_instruction.hpp"
|
#include "extractor/guidance/turn_instruction.hpp"
|
||||||
#include "util/bearing.hpp"
|
#include "util/bearing.hpp"
|
||||||
@ -25,9 +25,12 @@ inline bool entersRoundabout(const extractor::guidance::TurnInstruction instruct
|
|||||||
{
|
{
|
||||||
return (instruction.type == extractor::guidance::TurnType::EnterRoundabout ||
|
return (instruction.type == extractor::guidance::TurnType::EnterRoundabout ||
|
||||||
instruction.type == extractor::guidance::TurnType::EnterRotary ||
|
instruction.type == extractor::guidance::TurnType::EnterRotary ||
|
||||||
|
instruction.type == extractor::guidance::TurnType::EnterRoundaboutIntersection ||
|
||||||
instruction.type == extractor::guidance::TurnType::EnterRoundaboutAtExit ||
|
instruction.type == extractor::guidance::TurnType::EnterRoundaboutAtExit ||
|
||||||
instruction.type == extractor::guidance::TurnType::EnterRotaryAtExit ||
|
instruction.type == extractor::guidance::TurnType::EnterRotaryAtExit ||
|
||||||
|
instruction.type == extractor::guidance::TurnType::EnterRoundaboutIntersectionAtExit ||
|
||||||
instruction.type == extractor::guidance::TurnType::EnterAndExitRoundabout ||
|
instruction.type == extractor::guidance::TurnType::EnterAndExitRoundabout ||
|
||||||
|
instruction.type == extractor::guidance::TurnType::EnterAndExitRotary ||
|
||||||
instruction.type == extractor::guidance::TurnType::EnterAndExitRotary);
|
instruction.type == extractor::guidance::TurnType::EnterAndExitRotary);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,8 +38,10 @@ inline bool leavesRoundabout(const extractor::guidance::TurnInstruction instruct
|
|||||||
{
|
{
|
||||||
return (instruction.type == extractor::guidance::TurnType::ExitRoundabout ||
|
return (instruction.type == extractor::guidance::TurnType::ExitRoundabout ||
|
||||||
instruction.type == extractor::guidance::TurnType::ExitRotary ||
|
instruction.type == extractor::guidance::TurnType::ExitRotary ||
|
||||||
|
instruction.type == extractor::guidance::TurnType::ExitRoundaboutIntersection ||
|
||||||
instruction.type == extractor::guidance::TurnType::EnterAndExitRoundabout ||
|
instruction.type == extractor::guidance::TurnType::EnterAndExitRoundabout ||
|
||||||
instruction.type == extractor::guidance::TurnType::EnterAndExitRotary);
|
instruction.type == extractor::guidance::TurnType::EnterAndExitRotary ||
|
||||||
|
instruction.type == extractor::guidance::TurnType::EnterAndExitRoundaboutIntersection);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool staysOnRoundabout(const extractor::guidance::TurnInstruction instruction)
|
inline bool staysOnRoundabout(const extractor::guidance::TurnInstruction instruction)
|
||||||
@ -68,4 +73,4 @@ inline double angularDeviation(const double angle, const double from)
|
|||||||
} // namespace engine
|
} // namespace engine
|
||||||
} // namespace osrm
|
} // namespace osrm
|
||||||
|
|
||||||
#endif /* OSRM_UTIL_GUIDANCE_TOOLKIT_HPP_ */
|
#endif /* OSRM_ENGINE_GUIDANCE_TOOLKIT_HPP_ */
|
||||||
|
@ -22,6 +22,7 @@ const double constexpr FUZZY_ANGLE_DIFFERENCE = 20.;
|
|||||||
const double constexpr DISTINCTION_RATIO = 2;
|
const double constexpr DISTINCTION_RATIO = 2;
|
||||||
const unsigned constexpr INVALID_NAME_ID = 0;
|
const unsigned constexpr INVALID_NAME_ID = 0;
|
||||||
|
|
||||||
|
const double constexpr MAX_ROUNDABOUT_INTERSECTION_RADIUS = 5;
|
||||||
const double constexpr MAX_ROUNDABOUT_RADIUS = 15; // 30 m diameter as final distinction
|
const double constexpr MAX_ROUNDABOUT_RADIUS = 15; // 30 m diameter as final distinction
|
||||||
const double constexpr INCREASES_BY_FOURTY_PERCENT = 1.4;
|
const double constexpr INCREASES_BY_FOURTY_PERCENT = 1.4;
|
||||||
|
|
||||||
|
@ -1,14 +1,17 @@
|
|||||||
#ifndef OSRM_EXTRACTOR_GUIDANCE_ROUNDABOUT_HANDLER_HPP_
|
#ifndef OSRM_EXTRACTOR_GUIDANCE_ROUNDABOUT_HANDLER_HPP_
|
||||||
#define OSRM_EXTRACTOR_GUIDANCE_ROUNDABOUT_HANDLER_HPP_
|
#define OSRM_EXTRACTOR_GUIDANCE_ROUNDABOUT_HANDLER_HPP_
|
||||||
|
|
||||||
|
#include "extractor/compressed_edge_container.hpp"
|
||||||
#include "extractor/guidance/intersection.hpp"
|
#include "extractor/guidance/intersection.hpp"
|
||||||
#include "extractor/guidance/intersection_handler.hpp"
|
#include "extractor/guidance/intersection_handler.hpp"
|
||||||
|
#include "extractor/guidance/roundabout_type.hpp"
|
||||||
#include "extractor/query_node.hpp"
|
#include "extractor/query_node.hpp"
|
||||||
|
|
||||||
#include "util/name_table.hpp"
|
#include "util/name_table.hpp"
|
||||||
#include "util/node_based_graph.hpp"
|
#include "util/node_based_graph.hpp"
|
||||||
#include "util/typedefs.hpp"
|
#include "util/typedefs.hpp"
|
||||||
|
|
||||||
|
#include <set>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -37,7 +40,8 @@ class RoundaboutHandler : public IntersectionHandler
|
|||||||
public:
|
public:
|
||||||
RoundaboutHandler(const util::NodeBasedDynamicGraph &node_based_graph,
|
RoundaboutHandler(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||||
const std::vector<QueryNode> &node_info_list,
|
const std::vector<QueryNode> &node_info_list,
|
||||||
const util::NameTable &name_table);
|
const util::NameTable &name_table,
|
||||||
|
const CompressedEdgeContainer &compressed_edge_container);
|
||||||
|
|
||||||
~RoundaboutHandler() override final;
|
~RoundaboutHandler() override final;
|
||||||
|
|
||||||
@ -61,17 +65,21 @@ class RoundaboutHandler : public IntersectionHandler
|
|||||||
Intersection &intersection) const;
|
Intersection &intersection) const;
|
||||||
|
|
||||||
// decide whether we lookk at a roundabout or a rotary
|
// decide whether we lookk at a roundabout or a rotary
|
||||||
bool isRotary(const NodeID nid) const;
|
RoundaboutType getRoundaboutType(const NodeID nid) const;
|
||||||
|
|
||||||
// TODO handle bike/walk cases that allow crossing a roundabout!
|
// TODO handle bike/walk cases that allow crossing a roundabout!
|
||||||
// Processing of roundabouts
|
// Processing of roundabouts
|
||||||
// Produces instructions to enter/exit a roundabout or to stay on it.
|
// Produces instructions to enter/exit a roundabout or to stay on it.
|
||||||
// Performs the distinction between roundabout and rotaries.
|
// Performs the distinction between roundabout and rotaries.
|
||||||
Intersection handleRoundabouts(const bool is_rotary,
|
Intersection handleRoundabouts(const RoundaboutType roundabout_type,
|
||||||
const EdgeID via_edge,
|
const EdgeID via_edge,
|
||||||
const bool on_roundabout,
|
const bool on_roundabout,
|
||||||
const bool can_exit_roundabout,
|
const bool can_exit_roundabout,
|
||||||
Intersection intersection) const;
|
Intersection intersection) const;
|
||||||
|
|
||||||
|
bool qualifiesAsRoundaboutIntersection(const std::set<NodeID> &roundabout_nodes) const;
|
||||||
|
|
||||||
|
const CompressedEdgeContainer &compressed_edge_container;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace guidance
|
} // namespace guidance
|
||||||
|
21
include/extractor/guidance/roundabout_type.hpp
Normal file
21
include/extractor/guidance/roundabout_type.hpp
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#ifndef OSRM_EXTRACTOR_GUIDANCE_ROUNDABOUT_TYPES_HPP_
|
||||||
|
#define OSRM_EXTRACTOR_GUIDANCE_ROUNDABOUT_TYPES_HPP_
|
||||||
|
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace extractor
|
||||||
|
{
|
||||||
|
namespace guidance
|
||||||
|
{
|
||||||
|
enum class RoundaboutType
|
||||||
|
{
|
||||||
|
None, // not a roundabout
|
||||||
|
Roundabout, // standard roundabout
|
||||||
|
Rotary, // traffic circle (large roundabout) with dedicated name
|
||||||
|
RoundaboutIntersection // small roundabout with distinct turns, handled as intersection
|
||||||
|
};
|
||||||
|
} /* namespace guidance */
|
||||||
|
} /* namespace extractor */
|
||||||
|
} /* namespace osrm */
|
||||||
|
|
||||||
|
#endif /* OSRM_EXTRACTOR_GUIDANCE_ROUNDABOUT_TYPES_HPP_ */
|
@ -4,6 +4,7 @@
|
|||||||
#include "util/bearing.hpp"
|
#include "util/bearing.hpp"
|
||||||
#include "util/coordinate.hpp"
|
#include "util/coordinate.hpp"
|
||||||
#include "util/coordinate_calculation.hpp"
|
#include "util/coordinate_calculation.hpp"
|
||||||
|
#include "util/guidance/toolkit.hpp"
|
||||||
|
|
||||||
#include "extractor/compressed_edge_container.hpp"
|
#include "extractor/compressed_edge_container.hpp"
|
||||||
#include "extractor/query_node.hpp"
|
#include "extractor/query_node.hpp"
|
||||||
@ -26,6 +27,8 @@ namespace extractor
|
|||||||
namespace guidance
|
namespace guidance
|
||||||
{
|
{
|
||||||
|
|
||||||
|
using util::guidance::angularDeviation;
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
const constexpr double DESIRED_SEGMENT_LENGTH = 10.0;
|
const constexpr double DESIRED_SEGMENT_LENGTH = 10.0;
|
||||||
@ -246,12 +249,6 @@ inline double angleFromDiscreteAngle(const DiscreteAngle angle)
|
|||||||
return static_cast<double>(angle) * detail::discrete_angle_step_size;
|
return static_cast<double>(angle) * detail::discrete_angle_step_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline double angularDeviation(const double angle, const double from)
|
|
||||||
{
|
|
||||||
const double deviation = std::abs(angle - from);
|
|
||||||
return std::min(360 - deviation, deviation);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline double getAngularPenalty(const double angle, DirectionModifier modifier)
|
inline double getAngularPenalty(const double angle, DirectionModifier modifier)
|
||||||
{
|
{
|
||||||
// these are not aligned with getTurnDirection but represent an ideal center
|
// these are not aligned with getTurnDirection but represent an ideal center
|
||||||
@ -272,30 +269,6 @@ inline double getTurnConfidence(const double angle, TurnInstruction instruction)
|
|||||||
return 1.0 - (difference / max_deviation) * (difference / max_deviation);
|
return 1.0 - (difference / max_deviation) * (difference / max_deviation);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Translates between angles and their human-friendly directional representation
|
|
||||||
inline DirectionModifier getTurnDirection(const double angle)
|
|
||||||
{
|
|
||||||
// An angle of zero is a u-turn
|
|
||||||
// 180 goes perfectly straight
|
|
||||||
// 0-180 are right turns
|
|
||||||
// 180-360 are left turns
|
|
||||||
if (angle > 0 && angle < 60)
|
|
||||||
return DirectionModifier::SharpRight;
|
|
||||||
if (angle >= 60 && angle < 140)
|
|
||||||
return DirectionModifier::Right;
|
|
||||||
if (angle >= 140 && angle < 170)
|
|
||||||
return DirectionModifier::SlightRight;
|
|
||||||
if (angle >= 165 && angle <= 195)
|
|
||||||
return DirectionModifier::Straight;
|
|
||||||
if (angle > 190 && angle <= 220)
|
|
||||||
return DirectionModifier::SlightLeft;
|
|
||||||
if (angle > 220 && angle <= 300)
|
|
||||||
return DirectionModifier::Left;
|
|
||||||
if (angle > 300 && angle < 360)
|
|
||||||
return DirectionModifier::SharpLeft;
|
|
||||||
return DirectionModifier::UTurn;
|
|
||||||
}
|
|
||||||
|
|
||||||
// swaps left <-> right modifier types
|
// swaps left <-> right modifier types
|
||||||
inline DirectionModifier mirrorDirectionModifier(const DirectionModifier modifier)
|
inline DirectionModifier mirrorDirectionModifier(const DirectionModifier modifier)
|
||||||
{
|
{
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
#include <boost/assert.hpp>
|
#include <boost/assert.hpp>
|
||||||
|
|
||||||
|
#include "extractor/guidance/roundabout_type.hpp"
|
||||||
|
|
||||||
namespace osrm
|
namespace osrm
|
||||||
{
|
{
|
||||||
namespace extractor
|
namespace extractor
|
||||||
@ -36,26 +38,30 @@ enum DirectionModifier
|
|||||||
// enum class TurnType : unsigned char
|
// enum class TurnType : unsigned char
|
||||||
enum TurnType // at the moment we can support 32 turn types, without increasing memory consumption
|
enum TurnType // at the moment we can support 32 turn types, without increasing memory consumption
|
||||||
{
|
{
|
||||||
Invalid, // no valid turn instruction
|
Invalid, // no valid turn instruction
|
||||||
NoTurn, // end of segment without turn/middle of a segment
|
NewName, // no turn, but name changes
|
||||||
Suppressed, // location that suppresses a turn
|
Continue, // remain on a street
|
||||||
NewName, // no turn, but name changes
|
Turn, // basic turn
|
||||||
Continue, // remain on a street
|
Merge, // merge onto a street
|
||||||
Turn, // basic turn
|
Ramp, // special turn (highway ramp exits)
|
||||||
Merge, // merge onto a street
|
Fork, // fork road splitting up
|
||||||
Ramp, // special turn (highway ramp exits)
|
EndOfRoad, // T intersection
|
||||||
Fork, // fork road splitting up
|
Notification, // Travel Mode Changes, Restrictions apply...
|
||||||
EndOfRoad, // T intersection
|
EnterRoundabout, // Entering a small Roundabout
|
||||||
EnterRoundabout, // Entering a small Roundabout
|
EnterAndExitRoundabout, // Touching a roundabout
|
||||||
EnterRoundaboutAtExit, // Entering a small Roundabout at a countable exit
|
EnterRotary, // Enter a rotary
|
||||||
EnterAndExitRoundabout, // Touching a roundabout
|
EnterAndExitRotary, // Touching a rotary
|
||||||
ExitRoundabout, // Exiting a small Roundabout
|
EnterRoundaboutIntersection, // Entering a small Roundabout
|
||||||
EnterRotary, // Enter a rotary
|
EnterAndExitRoundaboutIntersection, // Touching a roundabout
|
||||||
EnterRotaryAtExit, // Enter A Rotary at a countable exit
|
NoTurn, // end of segment without turn/middle of a segment
|
||||||
EnterAndExitRotary, // Touching a rotary
|
Suppressed, // location that suppresses a turn
|
||||||
ExitRotary, // Exit a rotary
|
EnterRoundaboutAtExit, // Entering a small Roundabout at a countable exit
|
||||||
StayOnRoundabout, // Continue on Either a small or a large Roundabout
|
ExitRoundabout, // Exiting a small Roundabout
|
||||||
Notification // Travel Mode Changes`
|
EnterRotaryAtExit, // Enter A Rotary at a countable exit
|
||||||
|
ExitRotary, // Exit a rotary
|
||||||
|
EnterRoundaboutIntersectionAtExit, // Entering a small Roundabout at a countable exit
|
||||||
|
ExitRoundaboutIntersection, // Exiting a small Roundabout
|
||||||
|
StayOnRoundabout // Continue on Either a small or a large Roundabout
|
||||||
};
|
};
|
||||||
|
|
||||||
// turn angle in 1.40625 degree -> 128 == 180 degree
|
// turn angle in 1.40625 degree -> 128 == 180 degree
|
||||||
@ -80,27 +86,45 @@ struct TurnInstruction
|
|||||||
return TurnInstruction(TurnType::NoTurn, DirectionModifier::UTurn);
|
return TurnInstruction(TurnType::NoTurn, DirectionModifier::UTurn);
|
||||||
}
|
}
|
||||||
|
|
||||||
static TurnInstruction REMAIN_ROUNDABOUT(bool is_rotary, const DirectionModifier modifier)
|
static TurnInstruction REMAIN_ROUNDABOUT(const RoundaboutType, const DirectionModifier modifier)
|
||||||
{
|
{
|
||||||
(void)is_rotary; // staying does not require a different instruction at the moment
|
|
||||||
return TurnInstruction(TurnType::StayOnRoundabout, modifier);
|
return TurnInstruction(TurnType::StayOnRoundabout, modifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
static TurnInstruction ENTER_ROUNDABOUT(bool is_rotary, const DirectionModifier modifier)
|
static TurnInstruction ENTER_ROUNDABOUT(const RoundaboutType roundabout_type,
|
||||||
|
const DirectionModifier modifier)
|
||||||
{
|
{
|
||||||
return {is_rotary ? TurnType::EnterRotary : TurnType::EnterRoundabout, modifier};
|
const constexpr TurnType enter_instruction[] = {
|
||||||
|
TurnType::Invalid, TurnType::EnterRoundabout, TurnType::EnterRotary,
|
||||||
|
TurnType::EnterRoundaboutIntersection};
|
||||||
|
return {enter_instruction[static_cast<int>(roundabout_type)], modifier};
|
||||||
}
|
}
|
||||||
|
|
||||||
static TurnInstruction EXIT_ROUNDABOUT(bool is_rotary, const DirectionModifier modifier)
|
static TurnInstruction EXIT_ROUNDABOUT(const RoundaboutType roundabout_type,
|
||||||
|
const DirectionModifier modifier)
|
||||||
{
|
{
|
||||||
return {is_rotary ? TurnType::ExitRotary : TurnType::ExitRoundabout, modifier};
|
const constexpr TurnType exit_instruction[] = {TurnType::Invalid, TurnType::ExitRoundabout,
|
||||||
|
TurnType::ExitRotary,
|
||||||
|
TurnType::ExitRoundaboutIntersection};
|
||||||
|
return {exit_instruction[static_cast<int>(roundabout_type)], modifier};
|
||||||
}
|
}
|
||||||
|
|
||||||
static TurnInstruction ENTER_AND_EXIT_ROUNDABOUT(bool is_rotary,
|
static TurnInstruction ENTER_AND_EXIT_ROUNDABOUT(const RoundaboutType roundabout_type,
|
||||||
const DirectionModifier modifier)
|
const DirectionModifier modifier)
|
||||||
{
|
{
|
||||||
return {is_rotary ? TurnType::EnterAndExitRotary : TurnType::EnterAndExitRoundabout,
|
const constexpr TurnType exit_instruction[] = {
|
||||||
modifier};
|
TurnType::Invalid, TurnType::EnterAndExitRoundabout, TurnType::EnterAndExitRotary,
|
||||||
|
TurnType::EnterAndExitRoundaboutIntersection};
|
||||||
|
return {exit_instruction[static_cast<int>(roundabout_type)], modifier};
|
||||||
|
}
|
||||||
|
|
||||||
|
static TurnInstruction ENTER_ROUNDABOUT_AT_EXIT(const RoundaboutType roundabout_type,
|
||||||
|
const DirectionModifier modifier)
|
||||||
|
{
|
||||||
|
const constexpr TurnType enter_instruction[] = {
|
||||||
|
TurnType::Invalid, TurnType::EnterRoundaboutAtExit, TurnType::EnterRotaryAtExit,
|
||||||
|
TurnType::EnterRoundaboutIntersectionAtExit};
|
||||||
|
return {enter_instruction[static_cast<int>(roundabout_type)], modifier};
|
||||||
}
|
}
|
||||||
|
|
||||||
static TurnInstruction SUPPRESSED(const DirectionModifier modifier)
|
static TurnInstruction SUPPRESSED(const DirectionModifier modifier)
|
||||||
|
48
include/util/guidance/toolkit.hpp
Normal file
48
include/util/guidance/toolkit.hpp
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#ifndef OSRM_UTIL_GUIDANCE_TOOLKIT_HPP_
|
||||||
|
#define OSRM_UTIL_GUIDANCE_TOOLKIT_HPP_
|
||||||
|
|
||||||
|
/* A set of tools required for guidance in both pre and post-processing */
|
||||||
|
|
||||||
|
#include "extractor/guidance/turn_instruction.hpp"
|
||||||
|
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace util
|
||||||
|
{
|
||||||
|
namespace guidance
|
||||||
|
{
|
||||||
|
|
||||||
|
inline double angularDeviation(const double angle, const double from)
|
||||||
|
{
|
||||||
|
const double deviation = std::abs(angle - from);
|
||||||
|
return std::min(360 - deviation, deviation);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline extractor::guidance::DirectionModifier getTurnDirection(const double angle)
|
||||||
|
{
|
||||||
|
// An angle of zero is a u-turn
|
||||||
|
// 180 goes perfectly straight
|
||||||
|
// 0-180 are right turns
|
||||||
|
// 180-360 are left turns
|
||||||
|
if (angle > 0 && angle < 60)
|
||||||
|
return extractor::guidance::DirectionModifier::SharpRight;
|
||||||
|
if (angle >= 60 && angle < 140)
|
||||||
|
return extractor::guidance::DirectionModifier::Right;
|
||||||
|
if (angle >= 140 && angle < 170)
|
||||||
|
return extractor::guidance::DirectionModifier::SlightRight;
|
||||||
|
if (angle >= 165 && angle <= 195)
|
||||||
|
return extractor::guidance::DirectionModifier::Straight;
|
||||||
|
if (angle > 190 && angle <= 220)
|
||||||
|
return extractor::guidance::DirectionModifier::SlightLeft;
|
||||||
|
if (angle > 220 && angle <= 300)
|
||||||
|
return extractor::guidance::DirectionModifier::Left;
|
||||||
|
if (angle > 300 && angle < 360)
|
||||||
|
return extractor::guidance::DirectionModifier::SharpLeft;
|
||||||
|
return extractor::guidance::DirectionModifier::UTurn;
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* namespace guidance */
|
||||||
|
} /* namespace util */
|
||||||
|
} /* namespace osrm */
|
||||||
|
|
||||||
|
#endif /* OSRM_UTIL_GUIDANCE_TOOLKIT_HPP_ */
|
@ -34,9 +34,11 @@ const constexpr char *modifier_names[] = {"uturn", "sharp right", "right", "s
|
|||||||
// translations of TurnTypes. Not all types are exposed to the outside world.
|
// translations of TurnTypes. Not all types are exposed to the outside world.
|
||||||
// invalid types should never be returned as part of the API
|
// invalid types should never be returned as part of the API
|
||||||
const constexpr char *turn_type_names[] = {
|
const constexpr char *turn_type_names[] = {
|
||||||
"invalid", "no turn", "invalid", "new name", "continue", "turn", "merge",
|
"invalid", "new name", "continue", "turn", "merge", "ramp",
|
||||||
"ramp", "fork", "end of road", "roundabout", "invalid", "roundabout", "invalid",
|
"fork", "end of road", "notification", "roundabout", "roundabout", "rotary",
|
||||||
"rotary", "invalid", "rotary", "invalid", "invalid", "notification"};
|
"rotary", "roundabout_turn", "roundabout_turn", "invalid", "invalid", "invalid",
|
||||||
|
"invalid", "invalid", "invalid", "invalid", "invalid", "invalid"};
|
||||||
|
|
||||||
const constexpr char *waypoint_type_names[] = {"invalid", "arrive", "depart"};
|
const constexpr char *waypoint_type_names[] = {"invalid", "arrive", "depart"};
|
||||||
|
|
||||||
// Check whether to include a modifier in the result of the API
|
// Check whether to include a modifier in the result of the API
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
#include "engine/guidance/assemble_steps.hpp"
|
#include "engine/guidance/assemble_steps.hpp"
|
||||||
#include "engine/guidance/toolkit.hpp"
|
#include "engine/guidance/toolkit.hpp"
|
||||||
|
|
||||||
|
#include "util/guidance/toolkit.hpp"
|
||||||
|
|
||||||
#include <boost/assert.hpp>
|
#include <boost/assert.hpp>
|
||||||
#include <boost/range/algorithm_ext/erase.hpp>
|
#include <boost/range/algorithm_ext/erase.hpp>
|
||||||
|
|
||||||
@ -17,6 +19,8 @@
|
|||||||
using TurnInstruction = osrm::extractor::guidance::TurnInstruction;
|
using TurnInstruction = osrm::extractor::guidance::TurnInstruction;
|
||||||
using TurnType = osrm::extractor::guidance::TurnType;
|
using TurnType = osrm::extractor::guidance::TurnType;
|
||||||
using DirectionModifier = osrm::extractor::guidance::DirectionModifier;
|
using DirectionModifier = osrm::extractor::guidance::DirectionModifier;
|
||||||
|
using osrm::util::guidance::angularDeviation;
|
||||||
|
using osrm::util::guidance::getTurnDirection;
|
||||||
|
|
||||||
namespace osrm
|
namespace osrm
|
||||||
{
|
{
|
||||||
@ -43,7 +47,9 @@ void print(const std::vector<RouteStep> &steps)
|
|||||||
for (const auto &intersection : step.maneuver.intersections)
|
for (const auto &intersection : step.maneuver.intersections)
|
||||||
std::cout << "(" << intersection.duration << " " << intersection.distance << ")";
|
std::cout << "(" << intersection.duration << " " << intersection.distance << ")";
|
||||||
|
|
||||||
std::cout << "] name[" << step.name_id << "]: " << step.name << std::endl;
|
std::cout << "] name[" << step.name_id << "]: " << step.name
|
||||||
|
<< " Bearings: " << step.maneuver.bearing_before << " "
|
||||||
|
<< step.maneuver.bearing_after << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,17 +85,25 @@ void fixFinalRoundabout(std::vector<RouteStep> &steps)
|
|||||||
--propagation_index)
|
--propagation_index)
|
||||||
{
|
{
|
||||||
auto &propagation_step = steps[propagation_index];
|
auto &propagation_step = steps[propagation_index];
|
||||||
if (propagation_index == 0 || entersRoundabout(propagation_step.maneuver.instruction))
|
if (entersRoundabout(propagation_step.maneuver.instruction))
|
||||||
{
|
{
|
||||||
propagation_step.maneuver.exit = 0;
|
propagation_step.maneuver.exit = 0;
|
||||||
propagation_step.geometry_end = steps.back().geometry_begin;
|
propagation_step.geometry_end = steps.back().geometry_begin;
|
||||||
|
|
||||||
|
// remember the current name as rotary name in tha case we end in a rotary
|
||||||
if (propagation_step.maneuver.instruction.type == TurnType::EnterRotary ||
|
if (propagation_step.maneuver.instruction.type == TurnType::EnterRotary ||
|
||||||
propagation_step.maneuver.instruction.type == TurnType::EnterRotaryAtExit)
|
propagation_step.maneuver.instruction.type == TurnType::EnterRotaryAtExit)
|
||||||
propagation_step.rotary_name = propagation_step.name;
|
propagation_step.rotary_name = propagation_step.name;
|
||||||
|
|
||||||
break;
|
else if (propagation_step.maneuver.instruction.type ==
|
||||||
|
TurnType::EnterRoundaboutIntersection ||
|
||||||
|
propagation_step.maneuver.instruction.type ==
|
||||||
|
TurnType::EnterRoundaboutIntersectionAtExit)
|
||||||
|
propagation_step.maneuver.instruction.type = TurnType::EnterRoundabout;
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
// accumulate turn data into the enter instructions
|
||||||
else if (propagation_step.maneuver.instruction.type == TurnType::StayOnRoundabout)
|
else if (propagation_step.maneuver.instruction.type == TurnType::StayOnRoundabout)
|
||||||
{
|
{
|
||||||
// TODO this operates on the data that is in the instructions.
|
// TODO this operates on the data that is in the instructions.
|
||||||
@ -109,14 +123,17 @@ bool setUpRoundabout(RouteStep &step)
|
|||||||
// Special case handling, if an entry is directly tied to an exit
|
// Special case handling, if an entry is directly tied to an exit
|
||||||
const auto instruction = step.maneuver.instruction;
|
const auto instruction = step.maneuver.instruction;
|
||||||
if (instruction.type == TurnType::EnterRotaryAtExit ||
|
if (instruction.type == TurnType::EnterRotaryAtExit ||
|
||||||
instruction.type == TurnType::EnterRoundaboutAtExit)
|
instruction.type == TurnType::EnterRoundaboutAtExit ||
|
||||||
|
instruction.type == TurnType::EnterRoundaboutIntersectionAtExit)
|
||||||
{
|
{
|
||||||
step.maneuver.exit = 1;
|
step.maneuver.exit = 1;
|
||||||
// prevent futher special case handling of these two.
|
// prevent futher special case handling of these two.
|
||||||
if (instruction.type == TurnType::EnterRotaryAtExit)
|
if (instruction.type == TurnType::EnterRotaryAtExit)
|
||||||
step.maneuver.instruction.type = TurnType::EnterRotary;
|
step.maneuver.instruction.type = TurnType::EnterRotary;
|
||||||
else
|
else if (instruction.type == TurnType::EnterRoundaboutAtExit)
|
||||||
step.maneuver.instruction.type = TurnType::EnterRoundabout;
|
step.maneuver.instruction.type = TurnType::EnterRoundabout;
|
||||||
|
else
|
||||||
|
step.maneuver.instruction.type = TurnType::EnterRoundaboutIntersection;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (leavesRoundabout(instruction))
|
if (leavesRoundabout(instruction))
|
||||||
@ -126,8 +143,10 @@ bool setUpRoundabout(RouteStep &step)
|
|||||||
// prevent futher special case handling of these two.
|
// prevent futher special case handling of these two.
|
||||||
if (instruction.type == TurnType::EnterAndExitRotary)
|
if (instruction.type == TurnType::EnterAndExitRotary)
|
||||||
step.maneuver.instruction.type = TurnType::EnterRotary;
|
step.maneuver.instruction.type = TurnType::EnterRotary;
|
||||||
else
|
else if (instruction.type == TurnType::EnterAndExitRoundabout)
|
||||||
step.maneuver.instruction.type = TurnType::EnterRoundabout;
|
step.maneuver.instruction.type = TurnType::EnterRoundabout;
|
||||||
|
else
|
||||||
|
step.maneuver.instruction.type = TurnType::EnterRoundaboutIntersection;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -145,28 +164,35 @@ void closeOffRoundabout(const bool on_roundabout,
|
|||||||
if (!on_roundabout)
|
if (!on_roundabout)
|
||||||
{
|
{
|
||||||
|
|
||||||
// We reached a special case that requires the addition of a special route step in
|
// We reached a special case that requires the addition of a special route step in the
|
||||||
// the beginning.
|
// beginning. We started in a roundabout, so to announce the exit, we move use the exit
|
||||||
// We started in a roundabout, so to announce the exit, we move use the exit
|
// instruction and move it right to the beginning to make sure to immediately announce the
|
||||||
// instruction and
|
// exit.
|
||||||
// move it right to the beginning to make sure to immediately announce the exit.
|
|
||||||
BOOST_ASSERT(leavesRoundabout(steps[1].maneuver.instruction) ||
|
BOOST_ASSERT(leavesRoundabout(steps[1].maneuver.instruction) ||
|
||||||
steps[1].maneuver.instruction.type == TurnType::StayOnRoundabout);
|
steps[1].maneuver.instruction.type == TurnType::StayOnRoundabout);
|
||||||
steps[0].geometry_end = 1;
|
steps[0].geometry_end = 1;
|
||||||
steps[1] = detail::forwardInto(steps[1], steps[0]);
|
steps[1] = detail::forwardInto(steps[1], steps[0]);
|
||||||
steps[0].duration = 0;
|
steps[0].duration = 0;
|
||||||
steps[0].distance = 0;
|
steps[0].distance = 0;
|
||||||
steps[1].maneuver.instruction.type = step.maneuver.instruction.type == TurnType::ExitRotary
|
const auto exitToEnter = [](const TurnType type) {
|
||||||
? TurnType::EnterRotary
|
if (TurnType::ExitRotary == type)
|
||||||
: TurnType::EnterRoundabout;
|
return TurnType::EnterRotary;
|
||||||
|
// if we do not enter the roundabout Intersection, we cannot treat the full traversal as
|
||||||
|
// a turn. So we switch it up to the roundabout type
|
||||||
|
else if (type == TurnType::ExitRoundaboutIntersection)
|
||||||
|
return TurnType::EnterRoundabout;
|
||||||
|
else
|
||||||
|
return TurnType::EnterRoundabout;
|
||||||
|
};
|
||||||
|
steps[1].maneuver.instruction.type = exitToEnter(step.maneuver.instruction.type);
|
||||||
if (steps[1].maneuver.instruction.type == TurnType::EnterRotary)
|
if (steps[1].maneuver.instruction.type == TurnType::EnterRotary)
|
||||||
steps[1].rotary_name = steps[0].name;
|
steps[1].rotary_name = steps[0].name;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normal exit from the roundabout, or exit from a previously fixed roundabout.
|
// Normal exit from the roundabout, or exit from a previously fixed roundabout. Propagate the
|
||||||
// Propagate the index back to the entering
|
// index back to the entering location and prepare the current silent set of instructions for
|
||||||
// location and
|
// removal.
|
||||||
// prepare the current silent set of instructions for removal.
|
const auto exit_bearing = steps[step_index].maneuver.bearing_after;
|
||||||
if (step_index > 1)
|
if (step_index > 1)
|
||||||
{
|
{
|
||||||
// The very first route-step is head, so we cannot iterate past that one
|
// The very first route-step is head, so we cannot iterate past that one
|
||||||
@ -177,15 +203,55 @@ void closeOffRoundabout(const bool on_roundabout,
|
|||||||
propagation_step = detail::forwardInto(propagation_step, steps[propagation_index + 1]);
|
propagation_step = detail::forwardInto(propagation_step, steps[propagation_index + 1]);
|
||||||
if (entersRoundabout(propagation_step.maneuver.instruction))
|
if (entersRoundabout(propagation_step.maneuver.instruction))
|
||||||
{
|
{
|
||||||
// TODO at this point, we can remember the additional name for a rotary
|
|
||||||
// This requires some initial thought on the data format, though
|
|
||||||
|
|
||||||
propagation_step.maneuver.exit = step.maneuver.exit;
|
propagation_step.maneuver.exit = step.maneuver.exit;
|
||||||
propagation_step.geometry_end = step.geometry_end;
|
propagation_step.geometry_end = step.geometry_end;
|
||||||
// remember rotary name
|
// remember rotary name
|
||||||
if (propagation_step.maneuver.instruction.type == TurnType::EnterRotary ||
|
if (propagation_step.maneuver.instruction.type == TurnType::EnterRotary ||
|
||||||
propagation_step.maneuver.instruction.type == TurnType::EnterRotaryAtExit)
|
propagation_step.maneuver.instruction.type == TurnType::EnterRotaryAtExit)
|
||||||
|
{
|
||||||
propagation_step.rotary_name = propagation_step.name;
|
propagation_step.rotary_name = propagation_step.name;
|
||||||
|
}
|
||||||
|
else if (propagation_step.maneuver.instruction.type ==
|
||||||
|
TurnType::EnterRoundaboutIntersection ||
|
||||||
|
propagation_step.maneuver.instruction.type ==
|
||||||
|
TurnType::EnterRoundaboutIntersectionAtExit)
|
||||||
|
{
|
||||||
|
// Compute the angle between two bearings on a normal turn circle
|
||||||
|
//
|
||||||
|
// Bearings Angles
|
||||||
|
//
|
||||||
|
// 0 180
|
||||||
|
// 315 45 225 135
|
||||||
|
//
|
||||||
|
// 270 x 90 270 x 90
|
||||||
|
//
|
||||||
|
// 225 135 315 45
|
||||||
|
// 180 0
|
||||||
|
//
|
||||||
|
// A turn from north to north-east offerst bearing 0 and 45 has to be translated
|
||||||
|
// into a turn of 135 degrees. The same holdes for 90 - 135 (east to south
|
||||||
|
// east).
|
||||||
|
// For north, the transformation works by angle = 540 (360 + 180) - exit_bearing
|
||||||
|
// % 360;
|
||||||
|
// All other cases are handled by first rotating both bearings to an
|
||||||
|
// entry_bearing of 0.
|
||||||
|
const double angle = [](const double entry_bearing, const double exit_bearing) {
|
||||||
|
const double offset = 360 - entry_bearing;
|
||||||
|
const double rotated_exit = [](double bearing, const double offset) {
|
||||||
|
bearing += offset;
|
||||||
|
return bearing > 360 ? bearing - 360 : bearing;
|
||||||
|
}(exit_bearing, offset);
|
||||||
|
|
||||||
|
const auto angle = 540 - rotated_exit;
|
||||||
|
return angle > 360 ? angle - 360 : angle;
|
||||||
|
}(propagation_step.maneuver.bearing_before, exit_bearing);
|
||||||
|
|
||||||
|
std::cout << "Step: " << propagation_step.maneuver.bearing_before << " "
|
||||||
|
<< exit_bearing << " result: " << angle << std::endl;
|
||||||
|
|
||||||
|
propagation_step.maneuver.instruction.direction_modifier =
|
||||||
|
::osrm::util::guidance::getTurnDirection(angle);
|
||||||
|
}
|
||||||
|
|
||||||
propagation_step.name = step.name;
|
propagation_step.name = step.name;
|
||||||
propagation_step.name_id = step.name_id;
|
propagation_step.name_id = step.name_id;
|
||||||
@ -508,8 +574,8 @@ void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry)
|
|||||||
{
|
{
|
||||||
// Doing this step in post-processing provides a few challenges we cannot overcome.
|
// Doing this step in post-processing provides a few challenges we cannot overcome.
|
||||||
// The removal of an initial step imposes some copy overhead in the steps, moving all later
|
// The removal of an initial step imposes some copy overhead in the steps, moving all later
|
||||||
// steps to the front.
|
// steps to the front. In addition, we cannot reduce the travel time that is accumulated at a
|
||||||
// In addition, we cannot reduce the travel time that is accumulated at a different location.
|
// different location.
|
||||||
// As a direct implication, we have to keep the time of the initial/final turns (which adds a
|
// As a direct implication, we have to keep the time of the initial/final turns (which adds a
|
||||||
// few seconds of inaccuracy at both ends. This is acceptable, however, since the turn should
|
// few seconds of inaccuracy at both ends. This is acceptable, however, since the turn should
|
||||||
// usually not be as relevant.
|
// usually not be as relevant.
|
||||||
@ -517,14 +583,16 @@ void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry)
|
|||||||
if (steps.size() < 2 || geometry.locations.size() <= 2)
|
if (steps.size() < 2 || geometry.locations.size() <= 2)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// if phantom node is located at the connection of two segments, either one can be selected as
|
// if phantom node is located at the connection of two segments, either one can be selected
|
||||||
|
// as
|
||||||
// turn
|
// turn
|
||||||
//
|
//
|
||||||
// a --- b
|
// a --- b
|
||||||
// |
|
// |
|
||||||
// c
|
// c
|
||||||
//
|
//
|
||||||
// If a route from b to c is requested, both a--b and b--c could be selected as start segment.
|
// If a route from b to c is requested, both a--b and b--c could be selected as start
|
||||||
|
// segment.
|
||||||
// In case of a--b, we end up with an unwanted turn saying turn-right onto b-c.
|
// In case of a--b, we end up with an unwanted turn saying turn-right onto b-c.
|
||||||
// These cases start off with an initial segment which is of zero length.
|
// These cases start off with an initial segment which is of zero length.
|
||||||
// We have to be careful though, since routing that starts in a roundabout has a valid.
|
// We have to be careful though, since routing that starts in a roundabout has a valid.
|
||||||
@ -558,12 +626,12 @@ void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry)
|
|||||||
const auto ¤t_depart = steps.front();
|
const auto ¤t_depart = steps.front();
|
||||||
auto &designated_depart = *(steps.begin() + 1);
|
auto &designated_depart = *(steps.begin() + 1);
|
||||||
|
|
||||||
// FIXME this is required to be consistent with the route durations. The initial turn is
|
// FIXME this is required to be consistent with the route durations. The initial
|
||||||
// not actually part of the route, though
|
// turn is not actually part of the route, though
|
||||||
designated_depart.duration += current_depart.duration;
|
designated_depart.duration += current_depart.duration;
|
||||||
|
|
||||||
// update initial turn direction/bearings. Due to the duplicated first coordinate, the
|
// update initial turn direction/bearings. Due to the duplicated first coordinate,
|
||||||
// initial bearing is invalid
|
// the initial bearing is invalid
|
||||||
designated_depart.maneuver = detail::stepManeuverFromGeometry(
|
designated_depart.maneuver = detail::stepManeuverFromGeometry(
|
||||||
TurnInstruction::NO_TURN(), WaypointType::Depart, geometry);
|
TurnInstruction::NO_TURN(), WaypointType::Depart, geometry);
|
||||||
|
|
||||||
@ -595,8 +663,8 @@ void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry)
|
|||||||
|
|
||||||
BOOST_ASSERT(geometry.locations.size() >= steps.size());
|
BOOST_ASSERT(geometry.locations.size() >= steps.size());
|
||||||
auto &next_to_last_step = *(steps.end() - 2);
|
auto &next_to_last_step = *(steps.end() - 2);
|
||||||
// in the end, the situation with the roundabout cannot occur. As a result, we can remove all
|
// in the end, the situation with the roundabout cannot occur. As a result, we can remove
|
||||||
// zero-length instructions
|
// all zero-length instructions
|
||||||
if (next_to_last_step.distance <= 1)
|
if (next_to_last_step.distance <= 1)
|
||||||
{
|
{
|
||||||
geometry.locations.pop_back();
|
geometry.locations.pop_back();
|
||||||
|
@ -205,7 +205,7 @@ Intersection IntersectionGenerator::mergeSegregatedRoads(Intersection intersecti
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (intersection.size() == 1)
|
if (intersection.size() <= 1)
|
||||||
return intersection;
|
return intersection;
|
||||||
|
|
||||||
const bool is_connected_to_roundabout = [this,&intersection]() {
|
const bool is_connected_to_roundabout = [this,&intersection]() {
|
||||||
@ -245,7 +245,6 @@ Intersection IntersectionGenerator::mergeSegregatedRoads(Intersection intersecti
|
|||||||
|
|
||||||
intersection.pop_back();
|
intersection.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (mergable(0, 1))
|
else if (mergable(0, 1))
|
||||||
{
|
{
|
||||||
const double correction_factor = (intersection[1].turn.angle) / 2;
|
const double correction_factor = (intersection[1].turn.angle) / 2;
|
||||||
|
@ -2,11 +2,13 @@
|
|||||||
#include "extractor/guidance/intersection_handler.hpp"
|
#include "extractor/guidance/intersection_handler.hpp"
|
||||||
#include "extractor/guidance/toolkit.hpp"
|
#include "extractor/guidance/toolkit.hpp"
|
||||||
|
|
||||||
|
#include "util/guidance/toolkit.hpp"
|
||||||
#include "util/simple_logger.hpp"
|
#include "util/simple_logger.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
using EdgeData = osrm::util::NodeBasedDynamicGraph::EdgeData;
|
using EdgeData = osrm::util::NodeBasedDynamicGraph::EdgeData;
|
||||||
|
using osrm::util::guidance::getTurnDirection;
|
||||||
|
|
||||||
namespace osrm
|
namespace osrm
|
||||||
{
|
{
|
||||||
|
@ -2,6 +2,10 @@
|
|||||||
#include "extractor/guidance/intersection_scenario_three_way.hpp"
|
#include "extractor/guidance/intersection_scenario_three_way.hpp"
|
||||||
#include "extractor/guidance/toolkit.hpp"
|
#include "extractor/guidance/toolkit.hpp"
|
||||||
|
|
||||||
|
#include "util/guidance/toolkit.hpp"
|
||||||
|
|
||||||
|
using osrm::util::guidance::angularDeviation;
|
||||||
|
|
||||||
namespace osrm
|
namespace osrm
|
||||||
{
|
{
|
||||||
namespace extractor
|
namespace extractor
|
||||||
|
@ -3,12 +3,16 @@
|
|||||||
#include "extractor/guidance/toolkit.hpp"
|
#include "extractor/guidance/toolkit.hpp"
|
||||||
|
|
||||||
#include "util/simple_logger.hpp"
|
#include "util/simple_logger.hpp"
|
||||||
|
#include "util/guidance/toolkit.hpp"
|
||||||
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include <boost/assert.hpp>
|
#include <boost/assert.hpp>
|
||||||
|
|
||||||
|
using osrm::util::guidance::angularDeviation;
|
||||||
|
using osrm::util::guidance::getTurnDirection;
|
||||||
|
|
||||||
namespace osrm
|
namespace osrm
|
||||||
{
|
{
|
||||||
namespace extractor
|
namespace extractor
|
||||||
|
@ -2,14 +2,18 @@
|
|||||||
#include "extractor/guidance/roundabout_handler.hpp"
|
#include "extractor/guidance/roundabout_handler.hpp"
|
||||||
#include "extractor/guidance/toolkit.hpp"
|
#include "extractor/guidance/toolkit.hpp"
|
||||||
|
|
||||||
|
#include "util/coordinate_calculation.hpp"
|
||||||
|
#include "util/guidance/toolkit.hpp"
|
||||||
#include "util/simple_logger.hpp"
|
#include "util/simple_logger.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <set>
|
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
||||||
#include <boost/assert.hpp>
|
#include <boost/assert.hpp>
|
||||||
|
|
||||||
|
using osrm::util::guidance::getTurnDirection;
|
||||||
|
|
||||||
namespace osrm
|
namespace osrm
|
||||||
{
|
{
|
||||||
namespace extractor
|
namespace extractor
|
||||||
@ -19,8 +23,10 @@ namespace guidance
|
|||||||
|
|
||||||
RoundaboutHandler::RoundaboutHandler(const util::NodeBasedDynamicGraph &node_based_graph,
|
RoundaboutHandler::RoundaboutHandler(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||||
const std::vector<QueryNode> &node_info_list,
|
const std::vector<QueryNode> &node_info_list,
|
||||||
const util::NameTable &name_table)
|
const util::NameTable &name_table,
|
||||||
: IntersectionHandler(node_based_graph, node_info_list, name_table)
|
const CompressedEdgeContainer &compressed_edge_container)
|
||||||
|
: IntersectionHandler(node_based_graph, node_info_list, name_table),
|
||||||
|
compressed_edge_container(compressed_edge_container)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,7 +37,11 @@ bool RoundaboutHandler::canProcess(const NodeID from_nid,
|
|||||||
const Intersection &intersection) const
|
const Intersection &intersection) const
|
||||||
{
|
{
|
||||||
const auto flags = getRoundaboutFlags(from_nid, via_eid, intersection);
|
const auto flags = getRoundaboutFlags(from_nid, via_eid, intersection);
|
||||||
return flags.on_roundabout || flags.can_enter;
|
if (!flags.on_roundabout && !flags.can_enter)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const auto roundabout_type = getRoundaboutType(node_based_graph.GetTarget(via_eid));
|
||||||
|
return roundabout_type != RoundaboutType::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
Intersection RoundaboutHandler::
|
Intersection RoundaboutHandler::
|
||||||
@ -39,10 +49,10 @@ operator()(const NodeID from_nid, const EdgeID via_eid, Intersection intersectio
|
|||||||
{
|
{
|
||||||
invalidateExitAgainstDirection(from_nid, via_eid, intersection);
|
invalidateExitAgainstDirection(from_nid, via_eid, intersection);
|
||||||
const auto flags = getRoundaboutFlags(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));
|
const auto roundabout_type = getRoundaboutType(node_based_graph.GetTarget(via_eid));
|
||||||
// find the radius of the roundabout
|
// find the radius of the roundabout
|
||||||
return handleRoundabouts(is_rotary, via_eid, flags.on_roundabout, flags.can_exit_separately,
|
return handleRoundabouts(roundabout_type, via_eid, flags.on_roundabout,
|
||||||
std::move(intersection));
|
flags.can_exit_separately, std::move(intersection));
|
||||||
}
|
}
|
||||||
|
|
||||||
detail::RoundaboutFlags RoundaboutHandler::getRoundaboutFlags(
|
detail::RoundaboutFlags RoundaboutHandler::getRoundaboutFlags(
|
||||||
@ -56,7 +66,7 @@ detail::RoundaboutFlags RoundaboutHandler::getRoundaboutFlags(
|
|||||||
{
|
{
|
||||||
const auto &edge_data = node_based_graph.GetEdgeData(road.turn.eid);
|
const auto &edge_data = node_based_graph.GetEdgeData(road.turn.eid);
|
||||||
// only check actual outgoing edges
|
// only check actual outgoing edges
|
||||||
if (edge_data.reversed || !road.entry_allowed )
|
if (edge_data.reversed || !road.entry_allowed)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (edge_data.roundabout)
|
if (edge_data.roundabout)
|
||||||
@ -85,7 +95,7 @@ void RoundaboutHandler::invalidateExitAgainstDirection(const NodeID from_nid,
|
|||||||
Intersection &intersection) const
|
Intersection &intersection) const
|
||||||
{
|
{
|
||||||
const auto &in_edge_data = node_based_graph.GetEdgeData(via_eid);
|
const auto &in_edge_data = node_based_graph.GetEdgeData(via_eid);
|
||||||
if( in_edge_data.roundabout )
|
if (in_edge_data.roundabout)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bool past_roundabout_angle = false;
|
bool past_roundabout_angle = false;
|
||||||
@ -116,7 +126,74 @@ void RoundaboutHandler::invalidateExitAgainstDirection(const NodeID from_nid,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RoundaboutHandler::isRotary(const NodeID nid) const
|
// If we want to see a roundabout as a turn, the exits have to be distinct enough to be seen a
|
||||||
|
// dedicated turns. We are limiting it to four-way intersections with well distinct bearings.
|
||||||
|
// All entry/roads and exit roads have to be simple. Not segregated roads.
|
||||||
|
// 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
|
||||||
|
{
|
||||||
|
// translate a node ID into its respective coordinate stored in the node_info_list
|
||||||
|
const auto getCoordinate = [this](const NodeID node) {
|
||||||
|
return util::Coordinate(node_info_list[node].lon, node_info_list[node].lat);
|
||||||
|
};
|
||||||
|
const bool has_limited_size = roundabout_nodes.size() <= 4;
|
||||||
|
if (!has_limited_size)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const bool simple_exits = !std::find_if( roundabout_nodes.begin(), roundabout_nodes.end(), [this]( const NodeID node ){
|
||||||
|
return (node_based_graph.GetOutDegree(node) > 3);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!simple_exits)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Find all exit bearings. Only if they are well distinct (at least 60 degrees between
|
||||||
|
// them), we allow a roundabout turn
|
||||||
|
|
||||||
|
const auto exit_bearings = [this, &roundabout_nodes, getCoordinate]() {
|
||||||
|
std::vector<double> result;
|
||||||
|
for (const auto node : roundabout_nodes)
|
||||||
|
{
|
||||||
|
// given the reverse edge and the forward edge on a roundabout, a simple entry/exit
|
||||||
|
// can only contain a single further road
|
||||||
|
for (const auto edge : node_based_graph.GetAdjacentEdgeRange(node))
|
||||||
|
{
|
||||||
|
const auto edge_data = node_based_graph.GetEdgeData(edge);
|
||||||
|
if (edge_data.roundabout)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// there is a single non-roundabout edge
|
||||||
|
const auto src_coordinate = getCoordinate(node);
|
||||||
|
const auto next_coordinate = getRepresentativeCoordinate(
|
||||||
|
node, node_based_graph.GetTarget(edge), edge, edge_data.reversed,
|
||||||
|
compressed_edge_container, node_info_list);
|
||||||
|
result.push_back(
|
||||||
|
util::coordinate_calculation::bearing(src_coordinate, next_coordinate));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::sort(result.begin(), result.end());
|
||||||
|
return result;
|
||||||
|
}();
|
||||||
|
|
||||||
|
const bool well_distinct_bearings = [](const std::vector<double> &bearings) {
|
||||||
|
for (std::size_t bearing_index = 0; bearing_index < bearings.size(); ++bearing_index)
|
||||||
|
{
|
||||||
|
const double difference =
|
||||||
|
std::abs(bearings[(bearing_index + 1) % bearings.size()] - bearings[bearing_index]);
|
||||||
|
// we assume non-narrow turns as well distinct
|
||||||
|
if (difference <= NARROW_TURN_ANGLE)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}(exit_bearings);
|
||||||
|
|
||||||
|
return well_distinct_bearings;
|
||||||
|
}
|
||||||
|
|
||||||
|
RoundaboutType RoundaboutHandler::getRoundaboutType(const NodeID nid) const
|
||||||
{
|
{
|
||||||
// translate a node ID into its respective coordinate stored in the node_info_list
|
// translate a node ID into its respective coordinate stored in the node_info_list
|
||||||
const auto getCoordinate = [this](const NodeID node) {
|
const auto getCoordinate = [this](const NodeID node) {
|
||||||
@ -168,31 +245,33 @@ bool RoundaboutHandler::isRotary(const NodeID nid) const
|
|||||||
NodeID last_node = nid;
|
NodeID last_node = nid;
|
||||||
while (0 == roundabout_nodes.count(last_node))
|
while (0 == roundabout_nodes.count(last_node))
|
||||||
{
|
{
|
||||||
roundabout_nodes.insert(last_node);
|
// only count exits/entry locations
|
||||||
|
if (node_based_graph.GetOutDegree(last_node) > 2)
|
||||||
|
roundabout_nodes.insert(last_node);
|
||||||
|
|
||||||
const auto eid = getNextOnRoundabout(last_node);
|
const auto eid = getNextOnRoundabout(last_node);
|
||||||
|
|
||||||
if (eid == SPECIAL_EDGEID)
|
if (eid == SPECIAL_EDGEID)
|
||||||
{
|
{
|
||||||
util::SimpleLogger().Write(logDEBUG) << "Non-Loop Roundabout found.";
|
return RoundaboutType::None;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
last_node = node_based_graph.GetTarget(eid);
|
last_node = node_based_graph.GetTarget(eid);
|
||||||
|
|
||||||
|
if (last_node == nid)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// do we have a dedicated name for the rotary, if not its a roundabout
|
// a roundabout that cannot be entered or exited should not get here
|
||||||
// This function can theoretically fail if the roundabout name is partly
|
if (roundabout_nodes.size() == 0)
|
||||||
// used with a reference and without. This will be fixed automatically
|
return RoundaboutType::None;
|
||||||
// when we handle references separately or if the useage is more consistent
|
|
||||||
if (roundabout_name_id == 0 || connected_names.count(roundabout_name_id))
|
// More a traffic loop than anything else, currently treated as roundabout turn
|
||||||
|
if (roundabout_nodes.size() == 1)
|
||||||
{
|
{
|
||||||
return false;
|
return RoundaboutType::RoundaboutIntersection;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (roundabout_nodes.size() <= 1)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// calculate the radius of the roundabout/rotary. For two coordinates, we assume a minimal
|
// calculate the radius of the roundabout/rotary. For two coordinates, we assume a minimal
|
||||||
// circle
|
// circle
|
||||||
// with both vertices right at the other side (so half their distance in meters).
|
// with both vertices right at the other side (so half their distance in meters).
|
||||||
@ -217,12 +296,42 @@ bool RoundaboutHandler::isRotary(const NodeID nid) const
|
|||||||
// The radius computation can result in infinity, if the three coordinates are non-distinct.
|
// 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
|
// To stay on the safe side, we say its not a rotary
|
||||||
if (std::isinf(radius))
|
if (std::isinf(radius))
|
||||||
return false;
|
return RoundaboutType::Roundabout;
|
||||||
|
|
||||||
return radius > MAX_ROUNDABOUT_RADIUS;
|
// not within the dedicated radii for special roundabouts
|
||||||
|
if (radius > MAX_ROUNDABOUT_INTERSECTION_RADIUS && radius <= MAX_ROUNDABOUT_RADIUS)
|
||||||
|
return RoundaboutType::Roundabout;
|
||||||
|
|
||||||
|
if (radius > MAX_ROUNDABOUT_RADIUS)
|
||||||
|
{
|
||||||
|
// do we have a dedicated name for the rotary, if not its a roundabout
|
||||||
|
// 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
|
||||||
|
|
||||||
|
if (0 != roundabout_name_id && 0 == connected_names.count(roundabout_name_id))
|
||||||
|
return RoundaboutType::Rotary;
|
||||||
|
else
|
||||||
|
return RoundaboutType::Roundabout;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (radius <= MAX_ROUNDABOUT_INTERSECTION_RADIUS)
|
||||||
|
{
|
||||||
|
const bool qualifies_as_roundabout_nitersection =
|
||||||
|
qualifiesAsRoundaboutIntersection(roundabout_nodes);
|
||||||
|
if (qualifies_as_roundabout_nitersection)
|
||||||
|
{
|
||||||
|
return RoundaboutType::RoundaboutIntersection;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return RoundaboutType::Roundabout;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return RoundaboutType::Roundabout;
|
||||||
}
|
}
|
||||||
|
|
||||||
Intersection RoundaboutHandler::handleRoundabouts(const bool is_rotary,
|
Intersection RoundaboutHandler::handleRoundabouts(const RoundaboutType roundabout_type,
|
||||||
const EdgeID via_eid,
|
const EdgeID via_eid,
|
||||||
const bool on_roundabout,
|
const bool on_roundabout,
|
||||||
const bool can_exit_roundabout_separately,
|
const bool can_exit_roundabout_separately,
|
||||||
@ -248,14 +357,14 @@ Intersection RoundaboutHandler::handleRoundabouts(const bool is_rotary,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
turn.instruction =
|
turn.instruction = TurnInstruction::REMAIN_ROUNDABOUT(
|
||||||
TurnInstruction::REMAIN_ROUNDABOUT(is_rotary, getTurnDirection(turn.angle));
|
roundabout_type, getTurnDirection(turn.angle));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
turn.instruction =
|
turn.instruction =
|
||||||
TurnInstruction::EXIT_ROUNDABOUT(is_rotary, getTurnDirection(turn.angle));
|
TurnInstruction::EXIT_ROUNDABOUT(roundabout_type, getTurnDirection(turn.angle));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return intersection;
|
return intersection;
|
||||||
@ -269,20 +378,17 @@ Intersection RoundaboutHandler::handleRoundabouts(const bool is_rotary,
|
|||||||
const auto &out_data = node_based_graph.GetEdgeData(turn.eid);
|
const auto &out_data = node_based_graph.GetEdgeData(turn.eid);
|
||||||
if (out_data.roundabout)
|
if (out_data.roundabout)
|
||||||
{
|
{
|
||||||
turn.instruction =
|
|
||||||
TurnInstruction::ENTER_ROUNDABOUT(is_rotary, getTurnDirection(turn.angle));
|
|
||||||
if (can_exit_roundabout_separately)
|
if (can_exit_roundabout_separately)
|
||||||
{
|
turn.instruction = TurnInstruction::ENTER_ROUNDABOUT_AT_EXIT(
|
||||||
if (turn.instruction.type == TurnType::EnterRotary)
|
roundabout_type, getTurnDirection(turn.angle));
|
||||||
turn.instruction.type = TurnType::EnterRotaryAtExit;
|
else
|
||||||
if (turn.instruction.type == TurnType::EnterRoundabout)
|
turn.instruction = TurnInstruction::ENTER_ROUNDABOUT(
|
||||||
turn.instruction.type = TurnType::EnterRoundaboutAtExit;
|
roundabout_type, getTurnDirection(turn.angle));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
turn.instruction = TurnInstruction::ENTER_AND_EXIT_ROUNDABOUT(
|
turn.instruction = TurnInstruction::ENTER_AND_EXIT_ROUNDABOUT(
|
||||||
is_rotary, getTurnDirection(turn.angle));
|
roundabout_type, getTurnDirection(turn.angle));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return intersection;
|
return intersection;
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "util/coordinate.hpp"
|
#include "util/coordinate.hpp"
|
||||||
#include "util/coordinate_calculation.hpp"
|
#include "util/coordinate_calculation.hpp"
|
||||||
|
#include "util/guidance/toolkit.hpp"
|
||||||
#include "util/simple_logger.hpp"
|
#include "util/simple_logger.hpp"
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
@ -11,6 +12,8 @@
|
|||||||
#include <set>
|
#include <set>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
||||||
|
using osrm::util::guidance::getTurnDirection;
|
||||||
|
|
||||||
namespace osrm
|
namespace osrm
|
||||||
{
|
{
|
||||||
namespace extractor
|
namespace extractor
|
||||||
@ -36,7 +39,7 @@ TurnAnalysis::TurnAnalysis(const util::NodeBasedDynamicGraph &node_based_graph,
|
|||||||
barrier_nodes,
|
barrier_nodes,
|
||||||
node_info_list,
|
node_info_list,
|
||||||
compressed_edge_container),
|
compressed_edge_container),
|
||||||
roundabout_handler(node_based_graph, node_info_list, name_table),
|
roundabout_handler(node_based_graph, node_info_list, name_table, compressed_edge_container),
|
||||||
motorway_handler(node_based_graph, node_info_list, name_table),
|
motorway_handler(node_based_graph, node_info_list, name_table),
|
||||||
turn_handler(node_based_graph, node_info_list, name_table)
|
turn_handler(node_based_graph, node_info_list, name_table)
|
||||||
{
|
{
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include "extractor/guidance/turn_handler.hpp"
|
#include "extractor/guidance/turn_handler.hpp"
|
||||||
|
|
||||||
#include "util/simple_logger.hpp"
|
#include "util/simple_logger.hpp"
|
||||||
|
#include "util/guidance/toolkit.hpp"
|
||||||
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@ -11,6 +12,8 @@
|
|||||||
#include <boost/assert.hpp>
|
#include <boost/assert.hpp>
|
||||||
|
|
||||||
using EdgeData = osrm::util::NodeBasedDynamicGraph::EdgeData;
|
using EdgeData = osrm::util::NodeBasedDynamicGraph::EdgeData;
|
||||||
|
using osrm::util::guidance::getTurnDirection;
|
||||||
|
using osrm::util::guidance::angularDeviation;
|
||||||
|
|
||||||
namespace osrm
|
namespace osrm
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user