adding tests for guidance

This commit is contained in:
Moritz Kobitzsch 2016-03-23 13:04:23 +01:00
parent 56ba2cb251
commit fa0a5040e5
39 changed files with 2287 additions and 812 deletions

View File

@ -1,6 +1,6 @@
module.exports = { module.exports = {
default: '--require features --tags ~@todo --tags ~@bug --tags ~@stress --tags ~@guidance', default: '--require features --tags ~@stress --tags ~@todo',
verify: '--require features --tags ~@todo --tags ~@bug --tags ~@stress -f progress --tags ~@guidance', verify: '--require features --tags ~@todo --tags ~@bug --tags ~@stress -f progress',
jenkins: '--require features --tags ~@todo --tags ~@bug --tags ~@stress --tags ~@options -f progress', jenkins: '--require features --tags ~@todo --tags ~@bug --tags ~@stress --tags ~@options -f progress',
bugs: '--require features --tags @bug', bugs: '--require features --tags @bug',
todo: '--require features --tags @todo', todo: '--require features --tags @todo',

View File

@ -19,15 +19,15 @@ Feature: Bike - Destination only, no passing through
| axye | | | axye | |
When I route I should get When I route I should get
| from | to | route | | from | to | route |
| a | b | ab | | a | b | ab,ab |
| a | c | ab,bcd | | a | c | ab,bcd,bcd |
| a | d | ab,bcd | | a | d | ab,bcd,bcd |
| a | e | axye | | a | e | axye,axye |
| e | d | de | | e | d | de,de |
| e | c | de,bcd | | e | c | de,bcd,bcd |
| e | b | de,bcd | | e | b | de,bcd,bcd |
| e | a | axye | | e | a | axye,axye |
Scenario: Bike - Destination only street Scenario: Bike - Destination only street
Given the node map Given the node map
@ -45,15 +45,15 @@ Feature: Bike - Destination only, no passing through
| axye | | | axye | |
When I route I should get When I route I should get
| from | to | route | | from | to | route |
| a | b | ab | | a | b | ab,ab |
| a | c | ab,bc | | a | c | ab,bc,bc |
| a | d | ab,bc,cd | | a | d | ab,bc,cd,cd |
| a | e | axye | | a | e | axye,axye |
| e | d | de | | e | d | de,de |
| e | c | de,dc | | e | c | de,cd,cd |
| e | b | de,dc,bc | | e | b | de,cd,bc,bc |
| e | a | axye | | e | a | axye,axye |
Scenario: Bike - Routing inside a destination only area Scenario: Bike - Routing inside a destination only area
Given the node map Given the node map
@ -70,8 +70,8 @@ Feature: Bike - Destination only, no passing through
| axye | | | axye | |
When I route I should get When I route I should get
| from | to | route | | from | to | route |
| a | e | ab,bc,cd,de | | a | e | ab,bc,cd,de,de |
| e | a | de,cd,bc,ab | | e | a | de,cd,bc,ab,ab |
| b | d | bc,cd | | b | d | bc,cd,cd |
| d | b | cd,bc | | d | b | cd,bc,bc |

View File

@ -16,13 +16,13 @@ Feature: Bike - Mode flag
| cd | primary | | | | cd | primary | | |
When I route I should get When I route I should get
| from | to | route | turns | modes | | from | to | route | modes |
| a | d | ab,bc,cd,cd | depart,right,left,arrive | cycling,ferry,cycling,cycling | | a | d | ab,bc,cd,cd | cycling,ferry,cycling,cycling |
| d | a | cd,bc,ab,ab | depart,right,left,arrive | cycling,ferry,cycling,cycling | | d | a | cd,bc,ab,ab | cycling,ferry,cycling,cycling |
| c | a | bc,ab,ab | depart,left,arrive | ferry,cycling,cycling | | c | a | bc,ab,ab | ferry,cycling,cycling |
| d | b | cd,bc,bc | depart,right,arrive | cycling,ferry,ferry | | d | b | cd,bc,bc | cycling,ferry,ferry |
| a | c | ab,bc,bc | depart,right,arrive | cycling,ferry,ferry | | a | c | ab,bc,bc | cycling,ferry,ferry |
| b | d | bc,cd,cd | depart,left,arrive | ferry,cycling,cycling | | b | d | bc,cd,cd | ferry,cycling,cycling |
Scenario: Bike - Mode when using a train Scenario: Bike - Mode when using a train
Given the node map Given the node map
@ -36,13 +36,13 @@ Feature: Bike - Mode flag
| cd | primary | | | | cd | primary | | |
When I route I should get When I route I should get
| from | to | route | turns | modes | | from | to | route | modes |
| a | d | ab,bc,cd,cd | depart,right,left,arrive | cycling,train,cycling,cycling | | a | d | ab,bc,cd,cd | cycling,train,cycling,cycling |
| d | a | cd,bc,ab,ab | depart,right,left,arrive | cycling,train,cycling,cycling | | d | a | cd,bc,ab,ab | cycling,train,cycling,cycling |
| c | a | bc,ab,ab | depart,left,arrive | train,cycling,cycling | | c | a | bc,ab,ab | train,cycling,cycling |
| d | b | cd,bc,bc | depart,right,arrive | cycling,train,train | | d | b | cd,bc,bc | cycling,train,train |
| a | c | ab,bc,bc | depart,right,arrive | cycling,train,train | | a | c | ab,bc,bc | cycling,train,train |
| b | d | bc,cd,cd | depart,left,arrive | train,cycling,cycling | | b | d | bc,cd,cd | train,cycling,cycling |
Scenario: Bike - Mode when pushing bike against oneways Scenario: Bike - Mode when pushing bike against oneways
Given the node map Given the node map
@ -56,13 +56,13 @@ Feature: Bike - Mode flag
| cd | primary | | | cd | primary | |
When I route I should get When I route I should get
| from | to | route | turns | modes | | from | to | route | modes |
| a | d | ab,bc,cd,cd | depart,right,left,arrive | cycling,cycling,cycling,cycling | | a | d | ab,bc,cd,cd | cycling,cycling,cycling,cycling |
| d | a | cd,bc,ab,ab | depart,right,left,arrive | cycling,pushing bike,cycling,cycling | | d | a | cd,bc,ab,ab | cycling,pushing bike,cycling,cycling |
| c | a | bc,ab,ab | depart,left,arrive | pushing bike,cycling,cycling | | c | a | bc,ab,ab | pushing bike,cycling,cycling |
| d | b | cd,bc,bc | depart,right,arrive | cycling,pushing bike,pushing bike | | d | b | cd,bc,bc | cycling,pushing bike,pushing bike |
| a | c | ab,bc,bc | depart,right,arrive | cycling,cycling,cycling | | a | c | ab,bc,bc | cycling,cycling,cycling |
| b | d | bc,cd,cd | depart,left,arrive | cycling,cycling,cycling | | b | d | bc,cd,cd | cycling,cycling,cycling |
Scenario: Bike - Mode when pushing on pedestrain streets Scenario: Bike - Mode when pushing on pedestrain streets
Given the node map Given the node map
@ -76,13 +76,13 @@ Feature: Bike - Mode flag
| cd | primary | | cd | primary |
When I route I should get When I route I should get
| from | to | route | turns | modes | | from | to | route | modes |
| a | d | ab,bc,cd,cd | depart,right,left,arrive | cycling,pushing bike,cycling,cycling | | a | d | ab,bc,cd,cd | cycling,pushing bike,cycling,cycling |
| d | a | cd,bc,ab,ab | depart,right,left,arrive | cycling,pushing bike,cycling,cycling | | d | a | cd,bc,ab,ab | cycling,pushing bike,cycling,cycling |
| c | a | bc,ab,ab | depart,left,arrive | pushing bike,cycling,cycling | | c | a | bc,ab,ab | pushing bike,cycling,cycling |
| d | b | cd,bc,bc | depart,right,arrive | cycling,pushing bike,pushing bike | | d | b | cd,bc,bc | cycling,pushing bike,pushing bike |
| a | c | ab,bc,bc | depart,right,arrive | cycling,pushing bike,pushing bike | | a | c | ab,bc,bc | cycling,pushing bike,pushing bike |
| b | d | bc,cd,cd | depart,left,arrive | pushing bike,cycling,cycling | | b | d | bc,cd,cd | pushing bike,cycling,cycling |
Scenario: Bike - Mode when pushing on pedestrain areas Scenario: Bike - Mode when pushing on pedestrain areas
Given the node map Given the node map
@ -116,13 +116,13 @@ Feature: Bike - Mode flag
| cd | primary | | cd | primary |
When I route I should get When I route I should get
| from | to | route | turns | modes | | from | to | route | modes |
| a | d | ab,bc,cd,cd | depart,right,left,arrive | cycling,pushing bike,cycling,cycling | | a | d | ab,bc,cd,cd | cycling,pushing bike,cycling,cycling |
| d | a | cd,bc,ab,ab | depart,right,left,arrive | cycling,pushing bike,cycling,cycling | | d | a | cd,bc,ab,ab | cycling,pushing bike,cycling,cycling |
| c | a | bc,ab,ab | depart,left,arrive | pushing bike,cycling,cycling | | c | a | bc,ab,ab | pushing bike,cycling,cycling |
| d | b | cd,bc,bc | depart,right,arrive | cycling,pushing bike,pushing bike | | d | b | cd,bc,bc | cycling,pushing bike,pushing bike |
| a | c | ab,bc,bc | depart,right,arrive | cycling,pushing bike,pushing bike | | a | c | ab,bc,bc | cycling,pushing bike,pushing bike |
| b | d | bc,cd,cd | depart,left,arrive | pushing bike,cycling,cycling | | b | d | bc,cd,cd | pushing bike,cycling,cycling |
Scenario: Bike - Mode when bicycle=dismount Scenario: Bike - Mode when bicycle=dismount
Given the node map Given the node map
@ -136,13 +136,13 @@ Feature: Bike - Mode flag
| cd | primary | | | cd | primary | |
When I route I should get When I route I should get
| from | to | route | turns | modes | | from | to | route | modes |
| a | d | ab,bc,cd,cd | depart,right,left,arrive | cycling,pushing bike,cycling,cycling | | a | d | ab,bc,cd,cd | cycling,pushing bike,cycling,cycling |
| d | a | cd,bc,ab,ab | depart,right,left,arrive | cycling,pushing bike,cycling,cycling | | d | a | cd,bc,ab,ab | cycling,pushing bike,cycling,cycling |
| c | a | bc,ab,ab | depart,left,arrive | pushing bike,cycling,cycling | | c | a | bc,ab,ab | pushing bike,cycling,cycling |
| d | b | cd,bc,bc | depart,right,arrive | cycling,pushing bike,pushing bike | | d | b | cd,bc,bc | cycling,pushing bike,pushing bike |
| a | c | ab,bc,bc | depart,right,arrive | cycling,pushing bike,pushing bike | | a | c | ab,bc,bc | cycling,pushing bike,pushing bike |
| b | d | bc,cd,cd | depart,left,arrive | pushing bike,cycling,cycling | | b | d | bc,cd,cd | pushing bike,cycling,cycling |
Scenario: Bicycle - Modes when starting on forward oneway Scenario: Bicycle - Modes when starting on forward oneway
Given the node map Given the node map

View File

@ -63,7 +63,6 @@ Feature: Bike - Accessability of different way types
| runway | | | | | runway | | | |
| runway | yes | foot | foot | | runway | yes | foot | foot |
@todo
Scenario: Bike - Pushing bikes on ways with foot=yes in one direction Scenario: Bike - Pushing bikes on ways with foot=yes in one direction
Then routability should be Then routability should be
| highway | foot:forward | foot:backward | forw | backw | | highway | foot:forward | foot:backward | forw | backw |
@ -98,13 +97,12 @@ Feature: Bike - Accessability of different way types
| cd | primary | | | cd | primary | |
When I route I should get When I route I should get
| from | to | route | turns | | from | to | route | modes |
| a | d | ab,bc,cd,cd | depart,right,left,arrive | | a | d | ab,bc,cd,cd | cycling,cycling,cycling,cycling |
| d | a | cd,bc,ab,ab | depart,right,left,arrive | | d | a | cd,bc,ab,ab | cycling,pushing bike,cycling,cycling |
| c | a | bc,ab,ab | depart,left,arrive | | c | a | bc,ab,ab | pushing bike,cycling,cycling |
| d | b | cd,bc,bc | depart,right,arrive | | d | b | cd,bc,bc | cycling,pushing bike,pushing bike |
@todo
Scenario: Bike - Instructions when pushing bike on footway/pedestrian, etc. Scenario: Bike - Instructions when pushing bike on footway/pedestrian, etc.
Given the node map Given the node map
| a | b | | | a | b | |
@ -117,8 +115,8 @@ Feature: Bike - Accessability of different way types
| cd | primary | | cd | primary |
When I route I should get When I route I should get
| from | to | route | turns | | from | to | route | modes |
| a | d | ab,bc,cd,cd | depart,right,left,arrive | | a | d | ab,bc,cd,cd | cycling,pushing bike,cycling,cycling |
| d | a | cd,bc,ab,ab | depart,right,left,arrive | | d | a | cd,bc,ab,ab | cycling,pushing bike,cycling,cycling |
| c | a | bc,ab,ab | depart,left,arrive | | c | a | bc,ab,ab | pushing bike,cycling,cycling |
| d | b | cd,bc,bc | depart,right,arrive | | d | b | cd,bc,bc | cycling,pushing bike,pushing bike |

View File

@ -1,30 +0,0 @@
@routing @bicycle @roundabout @instruction
Feature: Roundabout Instructions
Background:
Given the profile "bicycle"
Scenario: Bicycle - Roundabout instructions
Given the node map
| | | v | | |
| | | d | | |
| s | a | | c | u |
| | | b | | |
| | | t | | |
And the ways
| nodes | junction |
| sa | |
| tb | |
| uc | |
| vd | |
| abcda | roundabout |
When I route I should get
| from | to | route | turns |
| s | t | sa,tb,tb | depart,roundabout-exit-1,arrive |
| s | u | sa,uc,uc | depart,roundabout-exit-2,arrive |
| s | v | sa,vd,vd | depart,roundabout-exit-3,arrive |
| u | v | uc,vd,vd | depart,roundabout-exit-1,arrive |
| u | s | uc,sa,sa | depart,roundabout-exit-2,arrive |
| u | t | uc,tb,tb | depart,roundabout-exit-3,arrive |

View File

@ -19,15 +19,15 @@ Feature: Car - Destination only, no passing through
| axye | | | axye | |
When I route I should get When I route I should get
| from | to | route | | from | to | route |
| a | b | ab | | a | b | ab,ab |
| a | c | ab,bcd | | a | c | ab,bcd,bcd |
| a | d | ab,bcd | | a | d | ab,bcd,bcd |
| a | e | axye | | a | e | axye,axye |
| e | d | de | | e | d | de,de |
| e | c | de,bcd | | e | c | de,bcd,bcd |
| e | b | de,bcd | | e | b | de,bcd,bcd |
| e | a | axye | | e | a | axye,axye |
Scenario: Car - Destination only street Scenario: Car - Destination only street
Given the node map Given the node map
@ -45,15 +45,15 @@ Feature: Car - Destination only, no passing through
| axye | | | axye | |
When I route I should get When I route I should get
| from | to | route | | from | to | route |
| a | b | ab | | a | b | ab,ab |
| a | c | ab,bc | | a | c | ab,bc,bc |
| a | d | ab,bc,cd | | a | d | ab,bc,cd,cd |
| a | e | axye | | a | e | axye,axye |
| e | d | de | | e | d | de,de |
| e | c | de,dc | | e | c | de,cd,cd |
| e | b | de,dc,bc | | e | b | de,cd,bc,bc |
| e | a | axye | | e | a | axye,axye |
Scenario: Car - Routing inside a destination only area Scenario: Car - Routing inside a destination only area
Given the node map Given the node map
@ -70,8 +70,8 @@ Feature: Car - Destination only, no passing through
| axye | | | axye | |
When I route I should get When I route I should get
| from | to | route | | from | to | route |
| a | e | ab,bc,cd,de | | a | e | ab,bc,cd,de,de |
| e | a | de,cd,bc,ab | | e | a | de,cd,bc,ab,ab |
| b | d | bc,cd | | b | d | bc,cd,cd |
| d | b | cd,bc | | d | b | cd,bc,bc |

View File

@ -15,13 +15,13 @@ Feature: Car - Mode flag
| cd | primary | | | | cd | primary | | |
When I route I should get When I route I should get
| from | to | route | turns | modes | | from | to | route | modes |
| a | d | ab,bc,cd,cd | depart,right,left,arrive | driving,ferry,driving,driving | | a | d | ab,bc,cd,cd | driving,ferry,driving,driving |
| d | a | cd,bc,ab,ab | depart,right,left,arrive | driving,ferry,driving,driving | | d | a | cd,bc,ab,ab | driving,ferry,driving,driving |
| c | a | bc,ab,ab | depart,left,arrive | ferry,driving,driving | | c | a | bc,ab,ab | ferry,driving,driving |
| d | b | cd,bc,bc | depart,right,arrive | driving,ferry,ferry | | d | b | cd,bc,bc | driving,ferry,ferry |
| a | c | ab,bc,bc | depart,right,arrive | driving,ferry,ferry | | a | c | ab,bc,bc | driving,ferry,ferry |
| b | d | bc,cd,cd | depart,left,arrive | ferry,driving,driving | | b | d | bc,cd,cd | ferry,driving,driving |
Scenario: Car - Snapping when using a ferry Scenario: Car - Snapping when using a ferry
Given the node map Given the node map
@ -34,7 +34,7 @@ Feature: Car - Mode flag
| ef | primary | | | | ef | primary | | |
When I route I should get When I route I should get
| from | to | route | turns | modes | time | | from | to | route | modes | time |
| c | d | bcde,bcde | depart,arrive | ferry,ferry | 600s | | c | d | bcde,bcde | ferry,ferry | 600s |

View File

@ -1,30 +0,0 @@
@routing @car @roundabout @instruction
Feature: Roundabout Instructions
Background:
Given the profile "car"
Scenario: Car - Roundabout instructions
Given the node map
| | | v | | |
| | | d | | |
| s | a | | c | u |
| | | b | | |
| | | t | | |
And the ways
| nodes | junction |
| sa | |
| tb | |
| uc | |
| vd | |
| abcda | roundabout |
When I route I should get
| from | to | route | turns |
| s | t | sa,tb,tb | depart,roundabout-exit-1,arrive |
| s | u | sa,uc,uc | depart,roundabout-exit-2,arrive |
| s | v | sa,vd,vd | depart,roundabout-exit-3,arrive |
| u | v | uc,vd,vd | depart,roundabout-exit-1,arrive |
| u | s | uc,sa,sa | depart,roundabout-exit-2,arrive |
| u | t | uc,tb,tb | depart,roundabout-exit-3,arrive |

View File

@ -0,0 +1,90 @@
@routing @guidance
Feature: Continue Instructions
Background:
Given the profile "car"
Given a grid size of 10 meters
Scenario: Road turning left
Given the node map
| | | c | |
| a | | b | d |
And the ways
| nodes | highway |
| abc | primary |
| bd | primary |
When I route I should get
| waypoints | route | turns |
| a,c | abc,abc,abc | depart,continue left,arrive |
| a,d | abc,bd,bd | depart,new name straight,arrive |
Scenario: Road turning right
Given the node map
| a | | b | d |
| | | c | |
And the ways
| nodes | highway |
| abc | primary |
| bd | primary |
When I route I should get
| waypoints | route | turns |
| a,c | abc,abc,abc | depart,continue right,arrive |
| a,d | abc,bd,bd | depart,new name straight,arrive |
Scenario: Road turning slight left
Given the node map
| | | | | c |
| | | | | |
| a | | b | | |
| | | | d | |
And the ways
| nodes | highway |
| abc | primary |
| bd | primary |
When I route I should get
| waypoints | route | turns |
| a,c | abc,abc,abc | depart,continue left,arrive |
| a,d | abc,bd,bd | depart,turn right,arrive |
Scenario: Road turning slight right
Given the node map
| | | | d | |
| a | | b | | |
| | | | | |
| | | | | c |
And the ways
| nodes | highway |
| abc | primary |
| bd | primary |
When I route I should get
| waypoints | route | turns |
| a,c | abc,abc,abc | depart,continue right,arrive |
| a,d | abc,bd,bd | depart,turn left,arrive |
Scenario: Road Loop
Given the node map
| | | f | | e |
| | | | | |
| a | | b | g | |
| | | | | |
| | | c | | d |
And the ways
| nodes | highway |
| abcdefb | primary |
| bg | primary |
When I route I should get
| waypoints | route | turns |
| a,c | abcdefb,abcdefb,abcdefb | depart,continue right,arrive |
| a,f | abcdefb,abcdefb,abcdefb | depart,continue left,arrive |
| a,d | abcdefb,abcdefb,abcdefb | depart,continue right,arrive |
| a,e | abcdefb,abcdefb,abcdefb | depart,continue left,arrive |

View File

@ -0,0 +1,106 @@
@routing @guidance
Feature: End Of Road Instructions
Background:
Given the profile "car"
Given a grid size of 10 meters
Scenario: End of Road with through street
Given the node map
| | | c |
| a | | b |
| | | d |
And the ways
| nodes | highway |
| ab | primary |
| cbd | primary |
When I route I should get
| waypoints | route | turns |
| a,c | ab,cbd,cbd | depart,end of road left,arrive |
| a,d | ab,cbd,cbd | depart,end of road right,arrive |
Scenario: End of Road with three streets
Given the node map
| | | c |
| a | | b |
| | | d |
And the ways
| nodes | highway |
| ab | primary |
| cb | primary |
| bd | primary |
When I route I should get
| waypoints | route | turns |
| a,c | ab,cb,cb | depart,end of road left,arrive |
| a,d | ab,bd,bd | depart,end of road right,arrive |
Scenario: End of Road with three streets, slightly angled
Given the node map
| a | | | | | c |
| | | | | | b |
| | | | | | d |
And the ways
| nodes | highway |
| ab | primary |
| cb | primary |
| bd | primary |
When I route I should get
| waypoints | route | turns |
| a,c | ab,cb,cb | depart,end of road left,arrive |
| a,d | ab,bd,bd | depart,end of road right,arrive |
Scenario: End of Road with three streets, slightly angled
Given the node map
| | | | | | c |
| | | | | | b |
| a | | | | | d |
And the ways
| nodes | highway |
| ab | primary |
| cb | primary |
| bd | primary |
When I route I should get
| waypoints | route | turns |
| a,c | ab,cb,cb | depart,end of road left,arrive |
| a,d | ab,bd,bd | depart,end of road right,arrive |
Scenario: End of Road with through street, slightly angled
Given the node map
| a | | | | | c |
| | | | | | b |
| | | | | | d |
And the ways
| nodes | highway |
| ab | primary |
| cbd | primary |
When I route I should get
| waypoints | route | turns |
| a,c | ab,cbd,cbd | depart,end of road left,arrive |
| a,d | ab,cbd,cbd | depart,end of road right,arrive |
Scenario: End of Road with through street, slightly angled
Given the node map
| | | | | | c |
| | | | | | b |
| a | | | | | d |
And the ways
| nodes | highway |
| ab | primary |
| cbd | primary |
When I route I should get
| waypoints | route | turns |
| a,c | ab,cbd,cbd | depart,end of road left,arrive |
| a,d | ab,cbd,cbd | depart,end of road right,arrive |

View File

@ -0,0 +1,213 @@
@routing @guidance
Feature: Fork Instructions
Background:
Given the profile "car"
Given a grid size of 10 meters
Scenario: Fork Same Road Class
Given the node map
| | | | | c |
| a | | b | | |
| | | | | d |
And the ways
| nodes | highway |
| ab | primary |
| bc | primary |
| bd | primary |
When I route I should get
| waypoints | route | turns |
| a,c | ab,bc,bc | depart,fork slight left,arrive |
| a,d | ab,bd,bd | depart,fork slight right,arrive |
Scenario: Do not fork on link type
Given the node map
| | | | | c |
| a | | b | | |
| | | | | d |
And the ways
| nodes | highway |
| abc | primary |
| bd | primary_link |
When I route I should get
| waypoints | route | turns |
| a,c | abc,abc | depart,arrive |
| a,d | abc,bd,bd | depart,turn slight right,arrive |
Scenario: Fork in presence of other roads
Given the node map
| | | | | c |
| a | | b | | |
| | e | | | d |
And the ways
| nodes | highway |
| ab | primary |
| bc | primary |
| bd | primary |
| eb | primary |
When I route I should get
| waypoints | route | turns |
| a,c | ab,bc,bc | depart,fork slight left,arrive |
| a,d | ab,bd,bd | depart,fork slight right,arrive |
Scenario: Fork Turning Slight Left
Given the node map
| | | | | | c |
| | | | | | |
| a | | b | | | |
| | | | | d | |
And the ways
| nodes | highway |
| ab | primary |
| bc | primary |
| bd | primary |
When I route I should get
| waypoints | route | turns |
| a,c | ab,bc,bc | depart,fork slight left,arrive |
| a,d | ab,bd,bd | depart,fork slight right,arrive |
Scenario: Fork Turning Slight Right
Given the node map
| | | | | c | |
| a | | b | | | |
| | | | | | |
| | | | | | d |
And the ways
| nodes | highway |
| ab | primary |
| bc | primary |
| bd | primary |
When I route I should get
| waypoints | route | turns |
| a,c | ab,bc,bc | depart,fork slight left,arrive |
| a,d | ab,bd,bd | depart,fork slight right,arrive |
Scenario: Do not fork on service
Given the node map
| | | | | c |
| a | | b | | |
| | | | | d |
And the ways
| nodes | highway |
| abc | residential |
| bd | service |
When I route I should get
| waypoints | route | turns |
| a,c | abc,abc | depart,arrive |
| a,d | abc,bd,bd | depart,turn slight right,arrive |
Scenario: Fork Both Turning Slight Right
Given the node map
| a | | b | | | |
| | | | | | c |
| | | | | | d |
And the ways
| nodes | highway |
| ab | primary |
| bc | primary |
| bd | primary |
When I route I should get
| waypoints | route | turns |
| a,c | ab,bc,bc | depart,fork slight left,arrive |
| a,d | ab,bd,bd | depart,fork slight right,arrive |
Scenario: Fork Both Turning Slight Left
Given the node map
| | | | | | c |
| | | | | | d |
| a | | b | | | |
And the ways
| nodes | highway |
| ab | primary |
| bc | primary |
| bd | primary |
When I route I should get
| waypoints | route | turns |
| a,c | ab,bc,bc | depart,fork slight left,arrive |
| a,d | ab,bd,bd | depart,fork slight right,arrive |
Scenario: Fork Both Turning Slight Right - Unnamed
Given the node map
| a | | b | | | |
| | | | | | c |
| | | | | | d |
And the ways
| nodes | highway | name |
| ab | primary | |
| bc | primary | |
| bd | primary | |
When I route I should get
| waypoints | route | turns |
| a,c | ,, | depart,fork slight left,arrive |
| a,d | ,, | depart,fork slight right,arrive |
Scenario: Fork Both Turning Slight Left - Unnamed
Given the node map
| | | | | | c |
| | | | | | d |
| a | | b | | | |
And the ways
| nodes | highway | name |
| ab | primary | |
| bc | primary | |
| bd | primary | |
When I route I should get
| waypoints | route | turns |
| a,c | ,, | depart,fork slight left,arrive |
| a,d | ,, | depart,fork slight right,arrive |
Scenario: Fork Both Turning Very Slightly Right - Unnamed
Given the node map
| a | | b | | | | | | | | | | | | | | | |
| | | | | | | | | | | | c | | | | | | |
| | | | | | | | | | | | | | | | | | d |
And the ways
| nodes | highway | name |
| ab | primary | |
| bc | primary | |
| bd | primary | |
When I route I should get
| waypoints | route | turns |
| a,c | ,, | depart,fork slight left,arrive |
| a,d | ,, | depart,fork slight right,arrive |
Scenario: Fork Both Turning Very Slightly Right - Unnamed Ramps
Given the node map
| a | | b | | | | | | | | | | | | | | | |
| | | | | | | | | | | | c | | | | | | |
| | | | | | | | | | | | | | | | | | d |
And the ways
| nodes | highway | name |
| ab | motorway_link | |
| bc | motorway_link | |
| bd | motorway_link | |
When I route I should get
| waypoints | route | turns |
| a,c | ,, | depart,fork slight left,arrive |
| a,d | ,, | depart,fork slight right,arrive |

View File

@ -0,0 +1,52 @@
@routing @guidance
Feature: Merging
Background:
Given the profile "car"
Given a grid size of 10 meters
Scenario: Merge on Four Way Intersection
Given the node map
| d | | |
| a | b | c |
| e | | |
And the ways
| nodes | highway |
| abc | primary |
| db | primary |
| eb | primary |
When I route I should get
| waypoints | route | turns |
| d,c | db,abc,abc | depart,merge slight right,arrive |
| e,c | eb,abc,abc | depart,merge slight left,arrive |
Scenario: Merge on Three Way Intersection Right
Given the node map
| d | | |
| a | b | c |
And the ways
| nodes | highway |
| abc | primary |
| db | primary |
When I route I should get
| waypoints | route | turns |
| d,c | db,abc,abc | depart,merge slight right,arrive |
Scenario: Merge on Three Way Intersection Right
Given the node map
| a | b | c |
| d | | |
And the ways
| nodes | highway |
| abc | primary |
| db | primary |
When I route I should get
| waypoints | route | turns |
| d,c | db,abc,abc | depart,merge slight left,arrive |

View File

@ -1,8 +1,8 @@
@routing @guidance @routing @guidance
Feature: Basic Roundabout Feature: Motorway Guidance
Background: Background:
Given the profile "testbot" Given the profile "car"
Given a grid size of 10 meters Given a grid size of 10 meters
Scenario: Ramp Exit Right Scenario: Ramp Exit Right
@ -16,9 +16,9 @@ Feature: Basic Roundabout
| bfg | motorway_link | | bfg | motorway_link |
When I route I should get When I route I should get
| waypoints | route | turns | | waypoints | route | turns |
| a,e | abcde, abcde | depart, arrive | | a,e | abcde,abcde | depart,arrive |
| a,g | abcde, bfg, bfg | depart, ramp-slight-right, arrive | | a,g | abcde,bfg,bfg | depart,ramp slight right,arrive |
Scenario: Ramp Exit Right Curved Right Scenario: Ramp Exit Right Curved Right
Given the node map Given the node map
@ -32,9 +32,9 @@ Feature: Basic Roundabout
| bfg | motorway_link | | bfg | motorway_link |
When I route I should get When I route I should get
| waypoints | route | turns | | waypoints | route | turns |
| a,e | abcde, abcde | depart, arrive | | a,e | abcde,abcde | depart,arrive |
| a,g | abcde, bfg, bfg | depart, ramp-slight-right, arrive | | a,g | abcde,bfg,bfg | depart,ramp right,arrive |
Scenario: Ramp Exit Right Curved Left Scenario: Ramp Exit Right Curved Left
Given the node map Given the node map
@ -49,9 +49,9 @@ Feature: Basic Roundabout
| cfg | motorway_link | | cfg | motorway_link |
When I route I should get When I route I should get
| waypoints | route | turns | | waypoints | route | turns |
| a,e | abcde, abcde | depart, arrive | | a,e | abcde,abcde | depart,arrive |
| a,g | abcde, cfg, cfg | depart, ramp-slight-right, arrive | | a,g | abcde,cfg,cfg | depart,ramp slight right,arrive |
Scenario: Ramp Exit Left Scenario: Ramp Exit Left
@ -65,9 +65,9 @@ Feature: Basic Roundabout
| bfg | motorway_link | | bfg | motorway_link |
When I route I should get When I route I should get
| waypoints | route | turns | | waypoints | route | turns |
| a,e | abcde, abcde | depart, arrive | | a,e | abcde,abcde | depart,arrive |
| a,g | abcde, bfg, bfg | depart, ramp-slight-left, arrive | | a,g | abcde,bfg,bfg | depart,ramp slight left,arrive |
Scenario: Ramp Exit Left Curved Left Scenario: Ramp Exit Left Curved Left
Given the node map Given the node map
@ -81,9 +81,9 @@ Feature: Basic Roundabout
| bfg | motorway_link | | bfg | motorway_link |
When I route I should get When I route I should get
| waypoints | route | turns | | waypoints | route | turns |
| a,e | abcde, abcde | depart, arrive | | a,e | abcde,abcde | depart,arrive |
| a,g | abcde, bfg, bfg | depart, ramp-slight-left, arrive | | a,g | abcde,bfg,bfg | depart,ramp left,arrive |
Scenario: Ramp Exit Left Curved Right Scenario: Ramp Exit Left Curved Right
Given the node map Given the node map
@ -97,9 +97,9 @@ Feature: Basic Roundabout
| cfg | motorway_link | | cfg | motorway_link |
When I route I should get When I route I should get
| waypoints | route | turns | | waypoints | route | turns |
| a,e | abcde, abcde | depart, arrive | | a,e | abcde,abcde | depart,arrive |
| a,g | abcde, cfg, cfg | depart, ramp-slight-left, arrive | | a,g | abcde,cfg,cfg | depart,ramp slight left,arrive |
Scenario: On Ramp Right Scenario: On Ramp Right
Given the node map Given the node map
@ -112,9 +112,9 @@ Feature: Basic Roundabout
| fgd | motorway_link | | fgd | motorway_link |
When I route I should get When I route I should get
| waypoints | route | turns | | waypoints | route | turns |
| a,e | abcde, abcde | depart, arrive | | a,e | abcde,abcde | depart,arrive |
| f,e | abcde, fgd, fgd | depart, merge-slight-left, arrive | | f,e | fgd,abcde,abcde | depart,merge slight left,arrive |
Scenario: On Ramp Left Scenario: On Ramp Left
Given the node map Given the node map
@ -127,9 +127,9 @@ Feature: Basic Roundabout
| fgd | motorway_link | | fgd | motorway_link |
When I route I should get When I route I should get
| waypoints | route | turns | | waypoints | route | turns |
| a,e | abcde, abcde | depart, arrive | | a,e | abcde,abcde | depart,arrive |
| f,e | abcde, fgd, fgd | depart, merge-slight-right, arrive | | f,e | fgd,abcde,abcde | depart,merge slight right,arrive |
Scenario: Highway Fork Scenario: Highway Fork
Given the node map Given the node map
@ -143,9 +143,9 @@ Feature: Basic Roundabout
| cfg | motorway | | cfg | motorway |
When I route I should get When I route I should get
| waypoints | route | turns | | waypoints | route | turns |
| a,e | abcde, abcde, abcde | depart, fork-left, arrive | | a,e | abcde,abcde,abcde | depart,fork slight left,arrive |
| a,g | abcde, cfg, cfg | depart, fork-right, arrive | | a,g | abcde,cfg,cfg | depart,fork slight right,arrive |
Scenario: Fork After Ramp Scenario: Fork After Ramp
Given the node map Given the node map
@ -160,9 +160,9 @@ Feature: Basic Roundabout
| cfg | motorway | | cfg | motorway |
When I route I should get When I route I should get
| waypoints | route | turns | | waypoints | route | turns |
| a,e | abc, cde, cde | depart, fork-left, arrive | | a,e | abc,cde,cde | depart,fork slight left,arrive |
| a,g | abc, cfg, cfg | depart, fork-right, arrive | | a,g | abc,cfg,cfg | depart,fork slight right,arrive |
Scenario: On And Off Ramp Right Scenario: On And Off Ramp Right
Given the node map Given the node map
@ -176,11 +176,11 @@ Feature: Basic Roundabout
| chi | motorway_link | | chi | motorway_link |
When I route I should get When I route I should get
| waypoints | route | turns | | waypoints | route | turns |
| a,e | abcde, abcde | depart, arrive | | a,e | abcde,abcde | depart,arrive |
| f,e | fgc, abcde, abcde | depart, merge-slight-left, arrive | | f,e | fgc,abcde,abcde | depart,merge slight left,arrive |
| a,i | abcde, chi, chi | depart, ramp-slight-right, arrive | | a,i | abcde,chi,chi | depart,ramp slight right,arrive |
| f,i | fgc, chi, chi | depart, turn-slight-right, arrive | | f,i | fgc,chi,chi | depart,ramp right,arrive |
Scenario: On And Off Ramp Left Scenario: On And Off Ramp Left
Given the node map Given the node map
@ -194,9 +194,25 @@ Feature: Basic Roundabout
| chi | motorway_link | | chi | motorway_link |
When I route I should get When I route I should get
| waypoints | route | turns | | waypoints | route | turns |
| a,e | abcde, abcde | depart, arrive | | a,e | abcde,abcde | depart,arrive |
| f,e | fgc, abcde, abcde | depart, merge-slight-right, arrive | | f,e | fgc,abcde,abcde | depart,merge slight right,arrive |
| a,i | abcde, chi, chi | depart, ramp-slight-left, arrive | | a,i | abcde,chi,chi | depart,ramp slight left,arrive |
| f,i | fgc, chi, chi | depart, turn-slight-left, arrive | | f,i | fgc,chi,chi | depart,ramp left,arrive |
Scenario: Merging Motorways
Given the node map
| e | | |
| a | b | c |
| d | | |
And the ways
| nodes | highway |
| abc | motorway |
| db | motorway |
| eb | motorway |
When I route I should get
| waypoints | route | turns |
| d,c | db,abc,abc | depart,merge slight left,arrive |
| e,c | eb,abc,abc | depart,merge slight right,arrive |

View File

@ -0,0 +1,135 @@
@routing @guidance
Feature: New-Name Instructions
Background:
Given the profile "car"
Given a grid size of 10 meters
Scenario: Undisturbed name Change
Given the node map
| a | | b | | c |
And the ways
| nodes |
| ab |
| bc |
When I route I should get
| waypoints | route | turns |
| a,c | ab,bc,bc | depart,new name straight,arrive |
Scenario: Undisturbed Name Change with unannounced Turn Right
Given the node map
| a | | b | | |
| | | | | c |
And the ways
| nodes |
| ab |
| bc |
When I route I should get
| waypoints | route | turns |
| a,c | ab,bc,bc | depart,new name slight right,arrive |
Scenario: Undisturbed Name Change with unannounced Turn Left
Given the node map
| | | | | c |
| a | | b | | |
And the ways
| nodes |
| ab |
| bc |
When I route I should get
| waypoints | route | turns |
| a,c | ab,bc,bc | depart,new name slight left,arrive |
Scenario: Disturbed Name Change with Turn
Given the node map
| a | | b | | |
| | d | | | c |
And the ways
| nodes |
| ab |
| bc |
| db |
When I route I should get
| waypoints | route | turns |
| a,c | ab,bc,bc | depart,new name slight right,arrive |
Scenario: Undisturbed Name Change with announced Turn Left
Given the node map
| | | c |
| a | | b |
And the ways
| nodes |
| ab |
| bc |
When I route I should get
| waypoints | route | turns |
| a,c | ab,bc,bc | depart,new name left,arrive |
Scenario: Undisturbed Name Change with announced Turn Sharp Left
Given the node map
| c | | |
| a | | b |
And the ways
| nodes |
| ab |
| bc |
When I route I should get
| waypoints | route | turns |
| a,c | ab,bc,bc | depart,new name sharp left,arrive |
Scenario: Undisturbed Name Change with announced Turn Right
Given the node map
| a | | b |
| | | c |
And the ways
| nodes |
| ab |
| bc |
When I route I should get
| waypoints | route | turns |
| a,c | ab,bc,bc | depart,new name right,arrive |
Scenario: Undisturbed Name Change with announced Turn Sharp Right
Given the node map
| a | | b |
| c | | |
And the ways
| nodes |
| ab |
| bc |
When I route I should get
| waypoints | route | turns |
| a,c | ab,bc,bc | depart,new name sharp right,arrive |
Scenario: Disturbed Name Change with minor road class
Given the node map
| a | | b | | d |
| | | | | c |
And the ways
| nodes | highway |
| ab | residential |
| bc | residential |
| bd | service |
When I route I should get
| waypoints | route | turns |
| a,c | ab,bc,bc | depart,new name slight right,arrive |

View File

@ -0,0 +1,229 @@
@routing @guidance
Feature: Ramp Guidance
Background:
Given the profile "car"
Given a grid size of 10 meters
Scenario: Ramp On Through Street Right
Given the node map
| a | b | c |
| | d | |
And the ways
| nodes | highway |
| abc | tertiary |
| bd | motorway_link |
When I route I should get
| waypoints | route | turns |
| a,d | abc,bd,bd | depart,ramp right,arrive |
Scenario: Ramp On Through Street Left
Given the node map
| | d | |
| a | b | c |
And the ways
| nodes | highway |
| abc | tertiary |
| bd | motorway_link |
When I route I should get
| waypoints | route | turns |
| a,d | abc,bd,bd | depart,ramp left,arrive |
Scenario: Ramp On Through Street Left and Right
Given the node map
| | e | |
| a | b | c |
| | d | |
And the ways
| nodes | highway |
| be | motorway_link |
| abc | tertiary |
| bd | motorway_link |
When I route I should get
| waypoints | route | turns |
| a,d | abc,bd,bd | depart,ramp right,arrive |
| a,e | abc,be,be | depart,ramp left,arrive |
Scenario: Ramp On Three Way Intersection Right
Given the node map
| a | b | c |
| | d | |
And the ways
| nodes | highway |
| ab | tertiary |
| bc | tertiary |
| bd | motorway_link |
When I route I should get
| waypoints | route | turns |
| a,d | ab,bd,bd | depart,ramp right,arrive |
Scenario: Ramp On Three Way Intersection Right
Given the node map
| | | c |
| a | b | |
| | d | |
And the ways
| nodes | highway |
| ab | tertiary |
| bc | tertiary |
| bd | motorway_link |
When I route I should get
| waypoints | route | turns |
| a,d | ab,bd,bd | depart,ramp right,arrive |
Scenario: Ramp Off Though Street
Given the node map
| | | c |
| a | b | |
| | d | |
And the ways
| nodes | highway |
| abc | tertiary |
| bd | motorway_link |
When I route I should get
| waypoints | route | turns |
| a,d | abc,bd,bd | depart,ramp right,arrive |
| a,c | abc,abc | depart,arrive |
Scenario: Straight Ramp Off Turning Though Street
Given the node map
| | | c |
| a | b | d |
And the ways
| nodes | highway |
| abc | tertiary |
| bd | motorway_link |
When I route I should get
| waypoints | route | turns |
| a,d | abc,bd,bd | depart,ramp straight,arrive |
| a,c | abc,abc,abc | depart,continue left,arrive |
Scenario: Fork Ramp Off Turning Though Street
Given the node map
| | | c |
| a | b | |
| | | d |
And the ways
| nodes | highway |
| abc | tertiary |
| bd | motorway_link |
When I route I should get
| waypoints | route | turns |
| a,d | abc,bd,bd | depart,ramp right,arrive |
| a,c | abc,abc,abc | depart,continue left,arrive |
Scenario: Fork Ramp
Given the node map
| | | c |
| a | b | |
| | | d |
And the ways
| nodes | highway |
| ab | tertiary |
| bc | tertiary |
| bd | motorway_link |
When I route I should get
| waypoints | route | turns |
| a,d | ab,bd,bd | depart,ramp right,arrive |
| a,c | ab,bc,bc | depart,turn left,arrive |
Scenario: Fork Slight Ramp
Given the node map
| | | | c |
| a | b | | |
| | | | d |
And the ways
| nodes | highway |
| ab | tertiary |
| bc | tertiary |
| bd | motorway_link |
When I route I should get
| waypoints | route | turns |
| a,d | ab,bd,bd | depart,ramp slight right,arrive |
| a,c | ab,bc,bc | depart,turn slight left,arrive |
Scenario: Fork Slight Ramp on Through Street
Given the node map
| | | | c |
| a | b | | |
| | | | d |
And the ways
| nodes | highway |
| abc | tertiary |
| bd | motorway_link |
When I route I should get
| waypoints | route | turns |
| a,d | abc,bd,bd | depart,ramp slight right,arrive |
| a,c | abc,abc,abc | depart,continue slight left,arrive |
Scenario: Fork Slight Ramp on Obvious Through Street
Given the node map
| | | | c |
| a | b | | |
| | | | d |
And the ways
| nodes | highway |
| abc | primary |
| bd | motorway_link |
When I route I should get
| waypoints | route | turns |
| a,d | abc,bd,bd | depart,ramp slight right,arrive |
| a,c | abc,abc | depart,arrive |
Scenario: Two Ramps Joining into common Motorway
Given the node map
| a | | | |
| | | c | d |
| b | | | |
And the ways
| nodes | highway |
| ac | motorway_link |
| bc | motorway_link |
| cd | motorway |
When I route I should get
| waypoints | route | turns |
| a,d | ac,cd,cd | depart,new name slight left,arrive |
| b,d | bc,cd,cd | depart,new name slight right,arrive |
Scenario: Two Ramps Joining into common Motorway Unnamed
Given the node map
| a | | | |
| | | c | d |
| b | | | |
And the ways
| nodes | highway | name |
| ac | motorway_link | |
| bc | motorway_link | |
| cd | motorway | |
When I route I should get
| waypoints | route | turns |
| a,d | , | depart,arrive |
| b,d | , | depart,arrive |

View File

@ -0,0 +1,167 @@
@routing @guidance
Feature: Rotary
Background:
Given the profile "bicycle"
Given a grid size of 30 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,bgecb-exit-3,arrive |
| a,f | ab,ef,ef | depart,bgecb-exit-2,arrive |
| a,h | ab,gh,gh | depart,bgecb-exit-1,arrive |
| d,f | cd,ef,ef | depart,bgecb-exit-3,arrive |
| d,h | cd,gh,gh | depart,bgecb-exit-2,arrive |
| d,a | cd,ab,ab | depart,bgecb-exit-1,arrive |
| f,h | ef,gh,gh | depart,bgecb-exit-3,arrive |
| f,a | ef,ab,ab | depart,bgecb-exit-2,arrive |
| f,d | ef,cd,cd | depart,bgecb-exit-1,arrive |
| h,a | gh,ab,ab | depart,bgecb-exit-3,arrive |
| h,d | gh,cd,cd | depart,bgecb-exit-2,arrive |
| h,f | gh,ef,ef | depart,bgecb-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,bcegb-exit-undefined,arrive |
| a,e | ab,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
| a,g | ab,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
| d,e | cd,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
| d,g | cd,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
| d,b | cd,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
| f,g | ef,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
| f,b | ef,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
| f,c | ef,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
| h,b | gh,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
| h,c | gh,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
| h,e | gh,bcegb,bcegb | depart,bcegb-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,bcegb-exit-1,arrive |
| b,f | bcegb,ef,ef | depart,bcegb-exit-2,arrive |
| b,h | bcegb,gh,gh | depart,bcegb-exit-3,arrive |
| c,f | bcegb,ef,ef | depart,bcegb-exit-1,arrive |
| c,h | bcegb,gh,gh | depart,bcegb-exit-2,arrive |
| c,a | bcegb,ab,ab | depart,bcegb-exit-3,arrive |
| e,h | bcegb,gh,gh | depart,bcegb-exit-1,arrive |
| e,a | bcegb,ab,ab | depart,bcegb-exit-2,arrive |
| e,d | bcegb,cd,cd | depart,bcegb-exit-3,arrive |
| g,a | bcegb,ab,ab | depart,bcegb-exit-1,arrive |
| g,d | bcegb,cd,cd | depart,bcegb-exit-2,arrive |
| g,f | bcegb,ef,ef | depart,bcegb-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 |
#needs to be adjusted when name-discovery works for entrys
Scenario: Mixed Entry and Exit
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,rotary-exit-1,arrive |
| a,l | abc,jkl,jkl | depart,bkheb-exit-2,arrive |
| a,i | abc,ghi,ghi | depart,bkheb-exit-3,arrive |
| a,f | abc,def,def | depart,bkheb-exit-4,arrive |
| d,f | def,def,def | depart,rotary-exit-1,arrive |
| d,c | def,abc,abc | depart,bkheb-exit-2,arrive |
| d,l | def,jkl,jkl | depart,bkheb-exit-3,arrive |
| d,i | def,ghi,ghi | depart,bkheb-exit-4,arrive |
| g,i | ghi,ghi,ghi | depart,rotary-exit-1,arrive |
| g,f | ghi,def,def | depart,bkheb-exit-2,arrive |
| g,c | ghi,abc,abc | depart,bkheb-exit-3,arrive |
| g,l | ghi,jkl,jkl | depart,bkheb-exit-4,arrive |
| j,l | jkl,jkl,jkl | depart,rotary-exit-1,arrive |
| j,i | jkl,ghi,ghi | depart,bkheb-exit-2,arrive |
| j,f | jkl,def,def | depart,bkheb-exit-3,arrive |
| j,c | jkl,abc,abc | depart,bkheb-exit-4,arrive |

View File

@ -0,0 +1,167 @@
@routing @guidance
Feature: Rotary
Background:
Given the profile "car"
Given a grid size of 30 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,bgecb-exit-3,arrive |
| a,f | ab,ef,ef | depart,bgecb-exit-2,arrive |
| a,h | ab,gh,gh | depart,bgecb-exit-1,arrive |
| d,f | cd,ef,ef | depart,bgecb-exit-3,arrive |
| d,h | cd,gh,gh | depart,bgecb-exit-2,arrive |
| d,a | cd,ab,ab | depart,bgecb-exit-1,arrive |
| f,h | ef,gh,gh | depart,bgecb-exit-3,arrive |
| f,a | ef,ab,ab | depart,bgecb-exit-2,arrive |
| f,d | ef,cd,cd | depart,bgecb-exit-1,arrive |
| h,a | gh,ab,ab | depart,bgecb-exit-3,arrive |
| h,d | gh,cd,cd | depart,bgecb-exit-2,arrive |
| h,f | gh,ef,ef | depart,bgecb-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,bcegb-exit-undefined,arrive |
| a,e | ab,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
| a,g | ab,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
| d,e | cd,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
| d,g | cd,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
| d,b | cd,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
| f,g | ef,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
| f,b | ef,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
| f,c | ef,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
| h,b | gh,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
| h,c | gh,bcegb,bcegb | depart,bcegb-exit-undefined,arrive |
| h,e | gh,bcegb,bcegb | depart,bcegb-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,bcegb-exit-1,arrive |
| b,f | bcegb,ef,ef | depart,bcegb-exit-2,arrive |
| b,h | bcegb,gh,gh | depart,bcegb-exit-3,arrive |
| c,f | bcegb,ef,ef | depart,bcegb-exit-1,arrive |
| c,h | bcegb,gh,gh | depart,bcegb-exit-2,arrive |
| c,a | bcegb,ab,ab | depart,bcegb-exit-3,arrive |
| e,h | bcegb,gh,gh | depart,bcegb-exit-1,arrive |
| e,a | bcegb,ab,ab | depart,bcegb-exit-2,arrive |
| e,d | bcegb,cd,cd | depart,bcegb-exit-3,arrive |
| g,a | bcegb,ab,ab | depart,bcegb-exit-1,arrive |
| g,d | bcegb,cd,cd | depart,bcegb-exit-2,arrive |
| g,f | bcegb,ef,ef | depart,bcegb-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 |
#needs to be adjusted when name-discovery works for entrys
Scenario: Mixed Entry and Exit
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,rotary-exit-1,arrive |
| a,l | abc,jkl,jkl | depart,bkheb-exit-2,arrive |
| a,i | abc,ghi,ghi | depart,bkheb-exit-3,arrive |
| a,f | abc,def,def | depart,bkheb-exit-4,arrive |
| d,f | def,def,def | depart,rotary-exit-1,arrive |
| d,c | def,abc,abc | depart,bkheb-exit-2,arrive |
| d,l | def,jkl,jkl | depart,bkheb-exit-3,arrive |
| d,i | def,ghi,ghi | depart,bkheb-exit-4,arrive |
| g,i | ghi,ghi,ghi | depart,rotary-exit-1,arrive |
| g,f | ghi,def,def | depart,bkheb-exit-2,arrive |
| g,c | ghi,abc,abc | depart,bkheb-exit-3,arrive |
| g,l | ghi,jkl,jkl | depart,bkheb-exit-4,arrive |
| j,l | jkl,jkl,jkl | depart,rotary-exit-1,arrive |
| j,i | jkl,ghi,ghi | depart,bkheb-exit-2,arrive |
| j,f | jkl,def,def | depart,bkheb-exit-3,arrive |
| j,c | jkl,abc,abc | depart,bkheb-exit-4,arrive |

View File

@ -0,0 +1,166 @@
@routing @guidance
Feature: Basic Roundabout
Background:
Given the profile "bicycle"
Given a grid size of 10 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-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 |
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
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 |

View File

@ -2,7 +2,7 @@
Feature: Basic Roundabout Feature: Basic Roundabout
Background: Background:
Given the profile "testbot" Given the profile "car"
Given a grid size of 10 meters Given a grid size of 10 meters
Scenario: Enter and Exit Scenario: Enter and Exit
@ -19,28 +19,28 @@ Feature: Basic Roundabout
| cd | | | cd | |
| ef | | | ef | |
| gh | | | gh | |
| bcegb | roundabout | | bgecb | roundabout |
When I route I should get When I route I should get
| waypoints | route | turns | | waypoints | route | turns |
| a,d | ab,cd,cd | depart,roundabout-exit-1,arrive | | a,d | ab,cd,cd | depart,roundabout-exit-3,arrive |
| a,f | ab,ef,ef | depart,roundabout-exit-2,arrive | | a,f | ab,ef,ef | depart,roundabout-exit-2,arrive |
| a,h | ab,gh,gh | depart,roundabout-exit-3,arrive | | a,h | ab,gh,gh | depart,roundabout-exit-1,arrive |
| d,f | cd,ef,ef | 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,h | cd,gh,gh | depart,roundabout-exit-2,arrive |
| d,a | cd,ab,ab | depart,roundabout-exit-3,arrive | | d,a | cd,ab,ab | depart,roundabout-exit-1,arrive |
| f,h | ef,gh,gh | 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,a | ef,ab,ab | depart,roundabout-exit-2,arrive |
| f,d | ef,cd,cd | depart,roundabout-exit-3,arrive | | f,d | ef,cd,cd | depart,roundabout-exit-1,arrive |
| h,a | gh,ab,ab | 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,d | gh,cd,cd | depart,roundabout-exit-2,arrive |
| h,f | gh,ef,ef | depart,roundabout-exit-3,arrive | | h,f | gh,ef,ef | depart,roundabout-exit-1,arrive |
Scenario: Only Enter Scenario: Only Enter
Given the node map Given the node map
| | | a | | | | | | a | | |
| | | b | | | | | | b | | |
| h | g | | c | d | | d | c | | g | h |
| | | e | | | | | | e | | |
| | | f | | | | | | f | | |
@ -53,29 +53,25 @@ Feature: Basic Roundabout
| bcegb | roundabout | | bcegb | roundabout |
When I route I should get When I route I should get
| waypoints | route | turns | | waypoints | route | turns |
| a,b | ab,ab | depart,arrive | | a,c | ab,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
| a,c | ab,bcegb | depart,roundabout-enter,arrive | | a,e | ab,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
| a,e | ab,bcegb | depart,roundabout-enter,arrive | | a,g | ab,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
| a,g | ab,bcegb | depart,roundabout-enter,arrive | | d,e | cd,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
| d,c | cd,cd | depart,arrive | | d,g | cd,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
| d,e | cd,bcegb | depart,roundabout-enter,arrive | | d,b | cd,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
| d,g | cd,bcegb | depart,roundabout-enter,arrive | | f,g | ef,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
| d,b | cd,bcegb | depart,roundabout-enter,arrive | | f,b | ef,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
| f,e | ef,ef | depart,arrive | | f,c | ef,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
| f,g | ef,bcegb | depart,roundabout-enter,arrive | | h,b | gh,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
| f,b | ef,bcegb | depart,roundabout-enter,arrive | | h,c | gh,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
| f,c | ef,bcegb | depart,roundabout-enter,arrive | | h,e | gh,bcegb,bcegb | depart,roundabout-exit-undefined,arrive |
| h,g | gh,gh | depart,arrive |
| h,b | gh,bcegb | depart,roundabout-enter,arrive |
| h,c | gh,bcegb | depart,roundabout-enter,arrive |
| h,e | gh,bcegb | depart,roundabout-enter,arrive |
Scenario: Only Exit Scenario: Only Exit
Given the node map Given the node map
| | | a | | | | | | a | | |
| | | b | | | | | | b | | |
| h | g | | c | d | | d | c | | g | h |
| | | e | | | | | | e | | |
| | | f | | | | | | f | | |
@ -89,28 +85,25 @@ Feature: Basic Roundabout
When I route I should get When I route I should get
| waypoints | route | turns | | waypoints | route | turns |
| b,a | ab,ab | depart,arrive |
| b,d | bcegb,cd,cd | depart,roundabout-exit-1,arrive | | b,d | bcegb,cd,cd | depart,roundabout-exit-1,arrive |
| b,f | bcegb,ef,ef | depart,roundabout-exit-2,arrive | | b,f | bcegb,ef,ef | depart,roundabout-exit-2,arrive |
| b,h | bcegb,gh,gh | depart,roundabout-exit-3,arrive | | b,h | bcegb,gh,gh | depart,roundabout-exit-3,arrive |
| c,d | cd,cd | depart,arrive |
| c,f | bcegb,ef,ef | depart,roundabout-exit-1,arrive | | c,f | bcegb,ef,ef | depart,roundabout-exit-1,arrive |
| c,h | bcegb,gh,gh | depart,roundabout-exit-2,arrive | | c,h | bcegb,gh,gh | depart,roundabout-exit-2,arrive |
| c,a | bcegb,ab,ab | depart,roundabout-exit-3,arrive | | c,a | bcegb,ab,ab | depart,roundabout-exit-3,arrive |
| e,f | ef,ef | depart,arrive |
| e,h | bcegb,gh,gh | depart,roundabout-exit-1,arrive | | e,h | bcegb,gh,gh | depart,roundabout-exit-1,arrive |
| e,a | bcegb,ab,ab | depart,roundabout-exit-2,arrive | | e,a | bcegb,ab,ab | depart,roundabout-exit-2,arrive |
| e,d | bcegb,cd,cd | depart,roundabout-exit-3,arrive | | e,d | bcegb,cd,cd | depart,roundabout-exit-3,arrive |
| g,h | gh,gh | depart,arrive |
| g,a | bcegb,ab,ab | depart,roundabout-exit-1,arrive | | g,a | bcegb,ab,ab | depart,roundabout-exit-1,arrive |
| g,d | bcegb,cd,cd | depart,roundabout-exit-2,arrive | | g,d | bcegb,cd,cd | depart,roundabout-exit-2,arrive |
| g,f | bcegb,ef,ef | depart,roundabout-exit-3,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 Scenario: Drive Around
Given the node map Given the node map
| | | a | | | | | | a | | |
| | | b | | | | | | b | | |
| h | g | | c | d | | d | c | | g | h |
| | | e | | | | | | e | | |
| | | f | | | | | | f | | |
@ -139,11 +132,11 @@ Feature: Basic Roundabout
Scenario: Mixed Entry and Exit Scenario: Mixed Entry and Exit
Given the node map Given the node map
| | a | | c | | | | c | | a | |
| l | | b | | d | | j | | b | | f |
| | k | | e | | | | k | | e | |
| j | | h | | f | | l | | h | | d |
| | i | | g | | | | g | | i | |
And the ways And the ways
| nodes | junction | oneway | | nodes | junction | oneway |
@ -151,23 +144,23 @@ Feature: Basic Roundabout
| def | | yes | | def | | yes |
| ghi | | yes | | ghi | | yes |
| jkl | | yes | | jkl | | yes |
| behkb | roundabout | yes | | bkheb | roundabout | yes |
When I route I should get When I route I should get
| waypoints | route | turns | | waypoints | route | turns |
| a,c | abc,abc,abc | depart,roundabout-exit-1,arrive | | a,c | abc,abc,abc | depart,roundabout-exit-1,arrive |
| a,f | abc,def,def | depart,roundabout-exit-2,arrive | | a,l | abc,jkl,jkl | depart,roundabout-exit-2,arrive |
| a,i | abc,ghi,ghi | depart,roundabout-exit-3,arrive | | a,i | abc,ghi,ghi | depart,roundabout-exit-3,arrive |
| a,l | abc,jkl,jkl | depart,roundabout-exit-4,arrive | | a,f | abc,def,def | depart,roundabout-exit-4,arrive |
| d,f | def,def,def | depart,roundabout-exit-1,arrive | | d,f | def,def,def | depart,roundabout-exit-1,arrive |
| d,i | def,ghi,ghi | depart,roundabout-exit-2,arrive | | d,c | def,abc,abc | depart,roundabout-exit-2,arrive |
| d,l | def,jkl,jkl | depart,roundabout-exit-3,arrive | | d,l | def,jkl,jkl | depart,roundabout-exit-3,arrive |
| d,c | def,abc,abc | depart,roundabout-exit-4,arrive | | d,i | def,ghi,ghi | depart,roundabout-exit-4,arrive |
| g,i | ghi,ghi,ghi | depart,roundabout-exit-1,arrive | | g,i | ghi,ghi,ghi | depart,roundabout-exit-1,arrive |
| g,l | ghi,jkl,jkl | depart,roundabout-exit-2,arrive | | g,f | ghi,def,def | depart,roundabout-exit-2,arrive |
| g,c | ghi,abc,abc | depart,roundabout-exit-3,arrive | | g,c | ghi,abc,abc | depart,roundabout-exit-3,arrive |
| g,f | ghi,edf,edf | depart,roundabout-exit-4,arrive | | g,l | ghi,jkl,jkl | depart,roundabout-exit-4,arrive |
| j,l | jkl,jkl,jkl | depart,roundabout-exit-1,arrive | | j,l | jkl,jkl,jkl | depart,roundabout-exit-1,arrive |
| j,c | jkl,abc,abc | depart,roundabout-exit-2,arrive | | j,i | jkl,ghi,ghi | depart,roundabout-exit-2,arrive |
| j,f | jkl,def,def | depart,roundabout-exit-3,arrive | | j,f | jkl,def,def | depart,roundabout-exit-3,arrive |
| j,i | jkl,ghi,ghi | depart,roundabout-exit-4,arrive | | j,c | jkl,abc,abc | depart,roundabout-exit-4,arrive |

View File

@ -0,0 +1,66 @@
@routing @guidance
Feature: Suppressed Turns
Background:
Given the profile "car"
Given a grid size of 10 meters
Scenario: Do not announce passing a exit ramp
Given the node map
| a | b | c | d | e |
| | | | f | g |
And the ways
| nodes | highway |
| abcde | motorway |
| bfg | motorway_link |
When I route I should get
| waypoints | route | turns |
| a,e | abcde,abcde | depart,arrive |
Scenario: Do not announce reference changes
Given the node map
| a | b | c | d | e | f |
And the ways
| nodes | highway | name | ref |
| ab | motorway | highway | A1 |
| bc | motorway | highway | A1,A2 |
| cd | motorway | highway | A2 |
| de | motorway | highway | |
| ef | motorway | highway | A1 |
When I route I should get
| waypoints | route | turns |
| a,f | highway (A1),highway (A1) | depart,arrive |
Scenario: Don't Announce Turn on following major road class -- service
Given the node map
| a | b | d |
| | | c |
And the ways
| nodes | highway |
| abc | primary |
| bd | service |
When I route I should get
| waypoints | route | turns |
| a,c | abc,abc | depart,arrive |
Scenario: Don't Announce Turn on following major road class -- residential
Given the node map
| a | b | d |
| | | c |
And the ways
| nodes | highway |
| abc | primary |
| bd | residential |
When I route I should get
| waypoints | route | turns |
| a,c | abc,abc | depart,arrive |
| a,d | abc,bd,bd | depart,turn straight,arrive |

View File

@ -0,0 +1,284 @@
@routing @guidance
Feature: Simple Turns
Background:
Given the profile "car"
Given a grid size of 10 meters
Scenario: Four Way Intersection
Given the node map
| | c | |
| a | b | e |
| | d | |
And the ways
| nodes | highway |
| ab | primary |
| cb | primary |
| db | primary |
| eb | primary |
When I route I should get
| waypoints | route | turns |
| a,c | ab,cb,cb | depart,turn left,arrive |
| a,e | ab,eb,eb | depart,new name straight,arrive |
| a,d | ab,db,db | depart,turn right,arrive |
| c,a | cb,ab,ab | depart,turn right,arrive |
| c,d | cb,db,db | depart,new name straight,arrive |
| c,e | cb,eb,eb | depart,turn left,arrive |
| d,a | db,ab,ab | depart,turn left,arrive |
| d,c | db,cb,cb | depart,new name straight,arrive |
| d,e | db,eb,eb | depart,turn right,arrive |
| e,a | eb,ab,ab | depart,new name straight,arrive |
| e,c | eb,cb,cb | depart,turn right,arrive |
| e,d | eb,db,db | depart,turn left,arrive |
Scenario: Rotated Four Way Intersection
Given the node map
| a | | c |
| | b | |
| d | | e |
And the ways
| nodes | highway |
| ab | primary |
| cb | primary |
| db | primary |
| eb | primary |
When I route I should get
| waypoints | route | turns |
| a,c | ab,cb,cb | depart,turn left,arrive |
| a,e | ab,eb,eb | depart,new name straight,arrive |
| a,d | ab,db,db | depart,turn right,arrive |
| c,a | cb,ab,ab | depart,turn right,arrive |
| c,d | cb,db,db | depart,new name straight,arrive |
| c,e | cb,eb,eb | depart,turn left,arrive |
| d,a | db,ab,ab | depart,turn left,arrive |
| d,c | db,cb,cb | depart,new name straight,arrive |
| d,e | db,eb,eb | depart,turn right,arrive |
| e,a | eb,ab,ab | depart,new name straight,arrive |
| e,c | eb,cb,cb | depart,turn right,arrive |
| e,d | eb,db,db | depart,turn left,arrive |
Scenario: Four Way Intersection Through Street
Given the node map
| | c | |
| a | b | e |
| | d | |
And the ways
| nodes | highway |
| abe | primary |
| cb | primary |
| db | primary |
When I route I should get
| waypoints | route | turns |
| a,c | abe,cb,cb | depart,turn left,arrive |
| a,e | abe,abe | depart,arrive |
| a,d | abe,db,db | depart,turn right,arrive |
| c,a | cb,abe,abe | depart,turn right,arrive |
| c,d | cb,db,db | depart,new name straight,arrive |
| c,e | cb,abe,abe | depart,turn left,arrive |
| d,a | db,abe,abe | depart,turn left,arrive |
| d,c | db,cb,cb | depart,new name straight,arrive |
| d,e | db,abe,abe | depart,turn right,arrive |
| e,a | abe,abe | depart,arrive |
| e,c | abe,cb,cb | depart,turn right,arrive |
| e,d | abe,db,db | depart,turn left,arrive |
Scenario: Four Way Intersection Double Through Street
Given the node map
| | c | |
| a | b | e |
| | d | |
And the ways
| nodes | highway |
| abe | primary |
| cbd | primary |
When I route I should get
| waypoints | route | turns |
| a,c | abe,cbd,cbd | depart,turn left,arrive |
| a,e | abe,abe | depart,arrive |
| a,d | abe,cbd,cbd | depart,turn right,arrive |
| c,a | cbd,abe,abe | depart,turn right,arrive |
| c,d | cbd,cbd | depart,arrive |
| c,e | cbd,abe,abe | depart,turn left,arrive |
| d,a | cbd,abe,abe | depart,turn left,arrive |
| d,c | cbd,cbd | depart,arrive |
| d,e | cbd,abe,abe | depart,turn right,arrive |
| e,a | abe,abe | depart,arrive |
| e,c | abe,cbd,cbd | depart,turn right,arrive |
| e,d | abe,cbd,cbd | depart,turn left,arrive |
Scenario: Three Way Intersection
Given the node map
| | c | |
| a | b | d |
And the ways
| nodes | highway |
| ab | primary |
| cb | primary |
| db | primary |
When I route I should get
| waypoints | route | turns |
| a,c | ab,cb,cb | depart,turn left,arrive |
| a,d | ab,db,db | depart,new name straight,arrive |
| d,c | db,cb,cb | depart,turn right,arrive |
| d,a | db,ab,ab | depart,new name straight,arrive |
Scenario: Three Way Intersection on Through Street
Given the node map
| | d | |
| a | b | c |
And the ways
| nodes | highway |
| abc | primary |
| db | primary |
When I route I should get
| waypoints | route | turns |
| a,c | abc,abc | depart,arrive |
| a,d | abc,db,db | depart,turn left,arrive |
| c,a | abc,abc | depart,arrive |
| c,d | abc,db,db | depart,turn right,arrive |
Scenario: High Degree Intersection
Given the node map
| i | | b | | c |
| | | | | |
| | | | | |
| h | | a | | d |
| | | | | |
| | | | | |
| g | | f | | e |
And the ways
| nodes | highway |
| ab | primary |
| ac | primary |
| ad | primary |
| ae | primary |
| af | primary |
| ag | primary |
| ah | primary |
| ai | primary |
When I route I should get
| waypoints | route | turns |
| b,c | ab,ac,ac | depart,turn sharp left,arrive |
| b,d | ab,ad,ad | depart,turn left,arrive |
| b,e | ab,ae,ae | depart,turn slight left,arrive |
| b,f | ab,af,af | depart,new name straight,arrive |
| b,g | ab,ag,ag | depart,turn slight right,arrive |
| b,h | ab,ah,ah | depart,turn right,arrive |
| b,i | ab,ai,ai | depart,turn sharp right,arrive |
Scenario: Disturbed High Degree Intersection
Given the node map
| | | b | | |
| i | | | | c |
| | | | | |
| h | | a | | d |
| | | | | |
| g | | | | e |
| | | f | | |
And the ways
| nodes | highway |
| ab | primary |
| ac | primary |
| ad | primary |
| ae | primary |
| af | primary |
| ag | primary |
| ah | primary |
| ai | primary |
When I route I should get
| waypoints | route | turns |
| b,c | ab,ac,ac | depart,turn sharp left,arrive |
| b,d | ab,ad,ad | depart,turn left,arrive |
| b,e | ab,ae,ae | depart,turn slight left,arrive |
| b,f | ab,af,af | depart,new name straight,arrive |
| b,g | ab,ag,ag | depart,turn slight right,arrive |
| b,h | ab,ah,ah | depart,turn right,arrive |
| b,i | ab,ai,ai | depart,turn sharp right,arrive |
Scenario: Turn instructions at high latitude
Given the node locations
| node | lat | lon |
| a | 55.68740 | 12.52430 |
| b | 55.68745 | 12.52409 |
| c | 55.68711 | 12.52383 |
| d | 55.68745 | 12.52450 |
| e | 55.68755 | 12.52450 |
| x | -55.68740 | 12.52430 |
| y | -55.68745 | 12.52409 |
| z | -55.68711 | 12.52383 |
| v | -55.68745 | 12.52450 |
| w | -55.68755 | 12.52450 |
And the ways
| nodes |
| ab |
| bc |
| bd |
| be |
| xy |
| yz |
| vy |
| wy |
When I route I should get
| from | to | route | turns |
| a | c | ab,bc,bc | depart,turn left,arrive |
| c | a | bc,ab,ab | depart,turn right,arrive |
| x | z | xy,yz,yz | depart,turn right,arrive |
| z | x | yz,xy,xy | depart,turn left,arrive |
Scenario: Four Way Intersection Double Through Street Segregated
Given the node map
| | b | | c | |
| i | | | | d |
| | | a | | |
| h | | | | e |
| | g | | f | |
And the ways
| nodes | highway | oneway | name |
| ha | primary | yes | first |
| ai | primary | yes | first |
| ae | primary | yes | first |
| da | primary | yes | first |
| ba | primary | yes | second |
| ac | primary | yes | second |
| fa | primary | yes | second |
| ag | primary | yes | second |
When I route I should get
| waypoints | route | turns |
| f,e | second,first,first | depart,turn right,arrive |
| f,c | second,second | depart,arrive |
| f,i | second,first,first | depart,turn left,arrive |
| f,g | second,second,second | depart,continue uturn,arrive |
| d,c | first,second,second | depart,turn right,arrive |
| d,i | first,first | depart,arrive |
| d,g | first,second,second | depart,turn left,arrive |
| d,e | first,first,first | depart,continue uturn,arrive |
| b,i | second,first,first | depart,turn right,arrive |
| b,g | second,second | depart,arrive |
| b,e | second,first,first | depart,turn left,arrive |
| b,c | second,second,second | depart,continue uturn,arrive |
| h,g | first,second,second | depart,turn right,arrive |
| h,e | first,first | depart,arrive |
| h,c | first,second,second | depart,turn left,arrive |
| h,i | first,first,first | depart,continue uturn,arrive |

View File

@ -144,9 +144,14 @@ module.exports = function () {
return v.maneuver.type; return v.maneuver.type;
case 'roundabout': case 'roundabout':
return 'roundabout-exit-' + v.maneuver.exit; return 'roundabout-exit-' + v.maneuver.exit;
case 'rotary':
if( 'rotary_name' in v )
return v.rotary_name + '-exit-' + v.maneuver.exit;
else
return 'rotary-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.modifier; return v.maneuver.type + ' ' + v.maneuver.modifier;
} }
}) })
.join(','); .join(',');

View File

@ -36,5 +36,5 @@ Feature: Basic Routing
| fy | last | | fy | last |
When I route I should get When I route I should get
| from | to | route | turns | | from | to | route |
| x | y | first,compr,last,last | depart,right,left,arrive | | x | y | first,compr,last,last |

View File

@ -1,10 +1,9 @@
@routing @testbot @overlap @routing @testbot @overlap @todo
Feature: Testbot - overlapping ways Feature: Testbot - overlapping ways
Background: Background:
Given the profile "testbot" Given the profile "testbot"
@bug @610
Scenario: Testbot - multiple way between same nodes Scenario: Testbot - multiple way between same nodes
Note that cb is connecting the same two nodes as bc Note that cb is connecting the same two nodes as bc
Given the node map Given the node map
@ -18,11 +17,10 @@ Feature: Testbot - overlapping ways
| cb | secondary | | cb | secondary |
When I route I should get When I route I should get
| from | to | route | | from | to | route |
| a | d | ab,bc,cd | | a | d | ab,bc,cd,cd |
| d | a | cd,bc,ab | | d | a | cd,bc,ab,ab |
@bug @610
Scenario: Testbot - area on top of way Scenario: Testbot - area on top of way
Given the node map Given the node map
| x | a | b | y | | x | a | b | y |
@ -34,6 +32,6 @@ Feature: Testbot - overlapping ways
| abcda | secondary | yes | | abcda | secondary | yes |
When I route I should get When I route I should get
| from | to | route | | from | to | route |
| x | y | xaby | | x | y | xaby,xaby |
| y | x | xaby | | y | x | xaby,xaby |

View File

@ -1,76 +0,0 @@
@routing @testbot @roundabout @instruction
Feature: Roundabout Instructions
Background:
Given the profile "testbot"
Scenario: Testbot - Roundabout
Given the node map
| | | v | | |
| | | d | | |
| s | a | | c | u |
| | | b | | |
| | | t | | |
And the ways
| nodes | junction |
| sa | |
| tb | |
| uc | |
| vd | |
| abcda | roundabout |
When I route I should get
| from | to | route | turns |
| s | t | sa,tb,tb | depart,roundabout-exit-1,arrive |
| s | u | sa,uc,uc | depart,roundabout-exit-2,arrive |
| s | v | sa,vd,vd | depart,roundabout-exit-3,arrive |
| t | u | tb,uc,uc | depart,roundabout-exit-1,arrive |
| t | v | tb,vd,vd | depart,roundabout-exit-2,arrive |
| t | s | tb,sa,sa | depart,roundabout-exit-3,arrive |
| u | v | uc,vd,vd | depart,roundabout-exit-1,arrive |
| u | s | uc,sa,sa | depart,roundabout-exit-2,arrive |
| u | t | uc,tb,tb | depart,roundabout-exit-3,arrive |
| v | s | vd,sa,sa | depart,roundabout-exit-1,arrive |
| v | t | vd,tb,tb | depart,roundabout-exit-2,arrive |
| v | u | vd,uc,uc | depart,roundabout-exit-3,arrive |
Scenario: Testbot - Roundabout with oneway links
Given the node map
| | | p | o | | |
| | | h | g | | |
| i | a | | | f | n |
| j | b | | | e | m |
| | | c | d | | |
| | | k | l | | |
And the ways
| nodes | junction | oneway |
| ai | | yes |
| jb | | yes |
| ck | | yes |
| ld | | yes |
| em | | yes |
| nf | | yes |
| go | | yes |
| ph | | yes |
| abcdefgha | roundabout | |
When I route I should get
| from | to | route | turns |
| j | k | jb,ck,ck | depart,roundabout-exit-1,arrive |
| j | m | jb,em,em | depart,roundabout-exit-2,arrive |
| j | o | jb,go,go | depart,roundabout-exit-3,arrive |
| j | i | jb,ai,ai | depart,roundabout-exit-4,arrive |
| l | m | ld,em,em | depart,roundabout-exit-1,arrive |
| l | o | ld,go,go | depart,roundabout-exit-2,arrive |
| l | i | ld,ai,ai | depart,roundabout-exit-3,arrive |
| l | k | ld,ck,ck | depart,roundabout-exit-4,arrive |
| n | o | nf,go,go | depart,roundabout-exit-1,arrive |
| n | i | nf,ai,ai | depart,roundabout-exit-2,arrive |
| n | k | nf,ck,ck | depart,roundabout-exit-3,arrive |
| n | m | nf,em,em | depart,roundabout-exit-4,arrive |
| p | i | ph,ai,ai | depart,roundabout-exit-1,arrive |
| p | k | ph,ck,ck | depart,roundabout-exit-2,arrive |
| p | m | ph,em,em | depart,roundabout-exit-3,arrive |
| p | o | ph,go,go | depart,roundabout-exit-4,arrive |

View File

@ -1,74 +0,0 @@
@routing @testbot @via
Feature: Via points
Background:
Given the profile "testbot"
And a grid size of 4 meters
Scenario: Basic Right Turn
Given the node map
| a | b | c | d | e | f | g |
| | | | | | h | |
| | | | | | i | |
| | | | | | j | |
| | | | | | k | |
And the ways
| nodes | oneway |
| abcdefg | yes |
| ehijk | yes |
When I route I should get
| from | to | route | distance | turns |
| a | k | abcdefg,ehijk,ehijk | 34m +-1 | depart,right,arrive |
Scenario: Slight Turn
Given the node map
| a | b | c | d | e | f | g | |
| | | | | | h | i | |
| | | | | | | | j |
| | | | | | | | k |
And the ways
| nodes | oneway |
| abcdefg | yes |
| ehijk | yes |
When I route I should get
| from | to | route | distance | turns |
| a | k | abcdefg,ehijk,ehijk | 35m +-1 | depart,slight right,arrive |
Scenario: Nearly Slight Turn
Given the node map
| a | b | c | d | e | f | g | |
| | | | | | h | | |
| | | | | | | i | |
| | | | | | | | j |
| | | | | | | | k |
And the ways
| nodes | oneway |
| abcdefg | yes |
| ehijk | yes |
When I route I should get
| from | to | route | distance | turns |
| a | k | abcdefg,ehijk,ehijk | 37m +-1 | depart,right,arrive |
Scenario: Nearly Slight Turn (Variation)
Given the node map
| a | b | c | d | e | f | g | |
| | | | | | h | | |
| | | | | | | i | |
| | | | | | | j | |
| | | | | | | | k |
And the ways
| nodes | oneway |
| abcdefg | yes |
| ehijk | yes |
When I route I should get
| from | to | route | distance | turns |
| a | k | abcdefg,ehijk,ehijk | 37m +-1 | depart,right,arrive |

View File

@ -1,115 +0,0 @@
@routing @turns @testbot
Feature: Turn directions/codes
Background:
Given the profile "testbot"
Scenario: Turn directions
Given the node map
| o | p | a | b | c |
| n | | | | d |
| m | | x | | e |
| l | | | | f |
| k | j | i | h | g |
And the ways
| nodes |
| xi |
| xk |
| xm |
| xo |
| xa |
| xc |
| xe |
| xg |
When I route I should get
| from | to | route | turns |
| i | k | xi,xk,xk | depart,sharp left,arrive |
| i | m | xi,xm,xm | depart,left,arrive |
| i | o | xi,xo,xo | depart,slight left,arrive |
| i | a | xi,xa,xa | depart,straight,arrive |
| i | c | xi,xc,xc | depart,slight right,arrive |
| i | e | xi,xe,xe | depart,right,arrive |
| i | g | xi,xg,xg | depart,sharp right,arrive |
| k | m | xk,xm,xm | depart,sharp left,arrive |
| k | o | xk,xo,xo | depart,left,arrive |
| k | a | xk,xa,xa | depart,slight left,arrive |
| k | c | xk,xc,xc | depart,straight,arrive |
| k | e | xk,xe,xe | depart,slight right,arrive |
| k | g | xk,xg,xg | depart,right,arrive |
| k | i | xk,xi,xi | depart,sharp right,arrive |
| m | o | xm,xo,xo | depart,sharp left,arrive |
| m | a | xm,xa,xa | depart,left,arrive |
| m | c | xm,xc,xc | depart,slight left,arrive |
| m | e | xm,xe,xe | depart,straight,arrive |
| m | g | xm,xg,xg | depart,slight right,arrive |
| m | i | xm,xi,xi | depart,right,arrive |
| m | k | xm,xk,xk | depart,sharp right,arrive |
| o | a | xo,xa,xa | depart,sharp left,arrive |
| o | c | xo,xc,xc | depart,left,arrive |
| o | e | xo,xe,xe | depart,slight left,arrive |
| o | g | xo,xg,xg | depart,straight,arrive |
| o | i | xo,xi,xi | depart,slight right,arrive |
| o | k | xo,xk,xk | depart,right,arrive |
| o | m | xo,xm,xm | depart,sharp right,arrive |
| a | c | xa,xc,xc | depart,sharp left,arrive |
| a | e | xa,xe,xe | depart,left,arrive |
| a | g | xa,xg,xg | depart,slight left,arrive |
| a | i | xa,xi,xi | depart,straight,arrive |
| a | k | xa,xk,xk | depart,slight right,arrive |
| a | m | xa,xm,xm | depart,right,arrive |
| a | o | xa,xo,xo | depart,sharp right,arrive |
| c | e | xc,xe,xe | depart,sharp left,arrive |
| c | g | xc,xg,xg | depart,left,arrive |
| c | i | xc,xi,xi | depart,slight left,arrive |
| c | k | xc,xk,xk | depart,straight,arrive |
| c | m | xc,xm,xm | depart,slight right,arrive |
| c | o | xc,xo,xo | depart,right,arrive |
| c | a | xc,xa,xa | depart,sharp right,arrive |
| e | g | xe,xg,xg | depart,sharp left,arrive |
| e | i | xe,xi,xi | depart,left,arrive |
| e | k | xe,xk,xk | depart,slight left,arrive |
| e | m | xe,xm,xm | depart,straight,arrive |
| e | o | xe,xo,xo | depart,slight right,arrive |
| e | a | xe,xa,xa | depart,right,arrive |
| e | c | xe,xc,xc | depart,sharp right,arrive |
| g | i | xg,xi,xi | depart,sharp left,arrive |
| g | k | xg,xk,xk | depart,left,arrive |
| g | m | xg,xm,xm | depart,slight left,arrive |
| g | o | xg,xo,xo | depart,straight,arrive |
| g | a | xg,xa,xa | depart,slight right,arrive |
| g | c | xg,xc,xc | depart,right,arrive |
| g | e | xg,xe,xe | depart,sharp right,arrive |
Scenario: Turn instructions at high latitude
# https://github.com/DennisOSRM/Project-OSRM/issues/532
Given the node locations
| node | lat | lon |
| a | 55.68740 | 12.52430 |
| b | 55.68745 | 12.52409 |
| c | 55.68711 | 12.52383 |
| x | -55.68740 | 12.52430 |
| y | -55.68745 | 12.52409 |
| z | -55.68711 | 12.52383 |
And the ways
| nodes |
| ab |
| bc |
| xy |
| yz |
When I route I should get
| from | to | route | turns |
| a | c | ab,bc,bc | depart,left,arrive |
| c | a | bc,ab,ab | depart,right,arrive |
| x | z | xy,yz,yz | depart,right,arrive |
| z | x | yz,xy,xy | depart,left,arrive |

View File

@ -20,8 +20,8 @@ Feature: U-turns at via points
| fg | | fg |
When I route I should get When I route I should get
| waypoints | route | turns | | waypoints | route |
| a,e,c | ab,be,be,ef,fg,dg,cd,cd | depart,right,arrive,depart,straight,left,left,arrive | | a,e,c | ab,be,be,ef,fg,dg,cd,cd |
Scenario: Query param to allow U-turns at all via points Scenario: Query param to allow U-turns at all via points
Given the node map Given the node map
@ -45,7 +45,6 @@ Feature: U-turns at via points
| waypoints | route | | waypoints | route |
| a,e,c | ab,be,be,be,bc,bc | | a,e,c | ab,be,be,be,bc,bc |
@todo
Scenario: Instructions at via points at u-turns Scenario: Instructions at via points at u-turns
Given the node map Given the node map
| a | b | c | d | | a | b | c | d |
@ -65,8 +64,8 @@ Feature: U-turns at via points
| fg | | fg |
When I route I should get When I route I should get
| waypoints | route | turns | | waypoints | route |
| a,e,c | ab,be,be,bc,bc | depart,right,uturn,right,arrive | | a,e,c | ab,be,be,be,bc,bc |
Scenario: u-turn mixed with non-uturn vias Scenario: u-turn mixed with non-uturn vias
Given the node map Given the node map

View File

@ -1,20 +1,20 @@
#ifndef ENGINE_GUIDANCE_ASSEMBLE_STEPS_HPP_ #ifndef ENGINE_GUIDANCE_ASSEMBLE_STEPS_HPP_
#define ENGINE_GUIDANCE_ASSEMBLE_STEPS_HPP_ #define ENGINE_GUIDANCE_ASSEMBLE_STEPS_HPP_
#include "engine/guidance/leg_geometry.hpp"
#include "engine/guidance/route_step.hpp" #include "engine/guidance/route_step.hpp"
#include "engine/guidance/step_maneuver.hpp" #include "engine/guidance/step_maneuver.hpp"
#include "engine/guidance/leg_geometry.hpp"
#include "engine/guidance/toolkit.hpp" #include "engine/guidance/toolkit.hpp"
#include "extractor/guidance/turn_instruction.hpp"
#include "engine/internal_route_result.hpp" #include "engine/internal_route_result.hpp"
#include "engine/phantom_node.hpp" #include "engine/phantom_node.hpp"
#include "util/coordinate_calculation.hpp" #include "extractor/guidance/turn_instruction.hpp"
#include "util/coordinate.hpp"
#include "util/bearing.hpp"
#include "extractor/travel_mode.hpp" #include "extractor/travel_mode.hpp"
#include "util/bearing.hpp"
#include "util/coordinate.hpp"
#include "util/coordinate_calculation.hpp"
#include <vector>
#include <boost/optional.hpp> #include <boost/optional.hpp>
#include <vector>
namespace osrm namespace osrm
{ {
@ -44,7 +44,7 @@ std::vector<RouteStep> assembleSteps(const DataFacadeT &facade,
const bool target_traversed_in_reverse) const bool target_traversed_in_reverse)
{ {
const double constexpr ZERO_DURATION = 0., ZERO_DISTANCE = 0.; const double constexpr ZERO_DURATION = 0., ZERO_DISTANCE = 0.;
const constexpr char* NO_ROTARY_NAME = ""; const constexpr char *NO_ROTARY_NAME = "";
const EdgeWeight source_duration = const EdgeWeight source_duration =
source_traversed_in_reverse ? source_node.reverse_weight : source_node.forward_weight; source_traversed_in_reverse ? source_node.reverse_weight : source_node.forward_weight;
const auto source_mode = source_traversed_in_reverse ? source_node.backward_travel_mode const auto source_mode = source_traversed_in_reverse ? source_node.backward_travel_mode
@ -85,14 +85,9 @@ std::vector<RouteStep> assembleSteps(const DataFacadeT &facade,
BOOST_ASSERT(segment_duration >= 0); BOOST_ASSERT(segment_duration >= 0);
const auto name = facade.GetNameForID(path_point.name_id); const auto name = facade.GetNameForID(path_point.name_id);
const auto distance = leg_geometry.segment_distances[segment_index]; const auto distance = leg_geometry.segment_distances[segment_index];
steps.push_back(RouteStep{path_point.name_id, steps.push_back(RouteStep{path_point.name_id, name, NO_ROTARY_NAME,
name, segment_duration / 10.0, distance, path_point.travel_mode,
NO_ROTARY_NAME, maneuver, leg_geometry.FrontIndex(segment_index),
segment_duration / 10.0,
distance,
path_point.travel_mode,
maneuver,
leg_geometry.FrontIndex(segment_index),
leg_geometry.BackIndex(segment_index) + 1}); leg_geometry.BackIndex(segment_index) + 1});
maneuver = detail::stepManeuverFromGeometry(path_point.turn_instruction, maneuver = detail::stepManeuverFromGeometry(path_point.turn_instruction,
leg_geometry, segment_index); leg_geometry, segment_index);
@ -103,13 +98,8 @@ std::vector<RouteStep> assembleSteps(const DataFacadeT &facade,
const auto distance = leg_geometry.segment_distances[segment_index]; const auto distance = leg_geometry.segment_distances[segment_index];
const int duration = segment_duration + target_duration; const int duration = segment_duration + target_duration;
BOOST_ASSERT(duration >= 0); BOOST_ASSERT(duration >= 0);
steps.push_back(RouteStep{target_node.name_id, steps.push_back(RouteStep{target_node.name_id, facade.GetNameForID(target_node.name_id),
facade.GetNameForID(target_node.name_id), NO_ROTARY_NAME, duration / 10., distance, target_mode, maneuver,
NO_ROTARY_NAME,
duration / 10.,
distance,
target_mode,
maneuver,
leg_geometry.FrontIndex(segment_index), leg_geometry.FrontIndex(segment_index),
leg_geometry.BackIndex(segment_index) + 1}); leg_geometry.BackIndex(segment_index) + 1});
} }
@ -127,14 +117,10 @@ std::vector<RouteStep> assembleSteps(const DataFacadeT &facade,
int duration = target_duration - source_duration; int duration = target_duration - source_duration;
BOOST_ASSERT(duration >= 0); BOOST_ASSERT(duration >= 0);
steps.push_back(RouteStep{source_node.name_id, steps.push_back(RouteStep{source_node.name_id, facade.GetNameForID(source_node.name_id),
facade.GetNameForID(source_node.name_id), NO_ROTARY_NAME, duration / 10.,
NO_ROTARY_NAME, leg_geometry.segment_distances[segment_index], source_mode,
duration / 10., std::move(maneuver), leg_geometry.FrontIndex(segment_index),
leg_geometry.segment_distances[segment_index],
source_mode,
std::move(maneuver),
leg_geometry.FrontIndex(segment_index),
leg_geometry.BackIndex(segment_index) + 1}); leg_geometry.BackIndex(segment_index) + 1});
} }
@ -142,14 +128,9 @@ std::vector<RouteStep> assembleSteps(const DataFacadeT &facade,
// This step has length zero, the only reason we need it is the target location // This step has length zero, the only reason we need it is the target location
auto final_maneuver = detail::stepManeuverFromGeometry( auto final_maneuver = detail::stepManeuverFromGeometry(
extractor::guidance::TurnInstruction::NO_TURN(), WaypointType::Arrive, leg_geometry); extractor::guidance::TurnInstruction::NO_TURN(), WaypointType::Arrive, leg_geometry);
steps.push_back(RouteStep{target_node.name_id, steps.push_back(RouteStep{target_node.name_id, facade.GetNameForID(target_node.name_id),
facade.GetNameForID(target_node.name_id), NO_ROTARY_NAME, ZERO_DURATION, ZERO_DISTANCE, target_mode,
NO_ROTARY_NAME, final_maneuver, leg_geometry.locations.size(),
ZERO_DURATION,
ZERO_DISTANCE,
target_mode,
final_maneuver,
leg_geometry.locations.size(),
leg_geometry.locations.size()}); leg_geometry.locations.size()});
return steps; return steps;

View File

@ -1,8 +1,8 @@
#ifndef ROUTE_STEP_HPP #ifndef ROUTE_STEP_HPP
#define ROUTE_STEP_HPP #define ROUTE_STEP_HPP
#include "extractor/travel_mode.hpp"
#include "engine/guidance/step_maneuver.hpp" #include "engine/guidance/step_maneuver.hpp"
#include "extractor/travel_mode.hpp"
#include <cstddef> #include <cstddef>

View File

@ -0,0 +1,32 @@
#ifndef OSRM_EXTRACTOR_GUIDANCE_CONSTANTS_HPP_
#define OSRM_EXTRACTOR_GUIDANCE_CONSTANTS_HPP_
namespace osrm
{
namespace extractor
{
namespace guidance
{
const bool constexpr INVERT = true;
// what angle is interpreted as going straight
const double constexpr STRAIGHT_ANGLE = 180.;
// if a turn deviates this much from going straight, it will be kept straight
const double constexpr MAXIMAL_ALLOWED_NO_TURN_DEVIATION = 3.;
// angle that lies between two nearly indistinguishable roads
const double constexpr NARROW_TURN_ANGLE = 40.;
const double constexpr GROUP_ANGLE = 90;
// angle difference that can be classified as straight, if its the only narrow turn
const double constexpr FUZZY_ANGLE_DIFFERENCE = 15.;
const double constexpr DISTINCTION_RATIO = 2;
const unsigned constexpr INVALID_NAME_ID = 0;
const double constexpr MAX_ROUNDABOUT_RADIUS = 15; // 30 m diameter as final distinction
const double constexpr INCREASES_BY_FOURTY_PERCENT = 1.4;
} // namespace guidance
} // namespace extractor
} // namespace osrm
#endif // OSRM_EXTRACTOR_GUIDANCE_CONSTANTS_HPP_

View File

@ -8,14 +8,14 @@
#include "extractor/compressed_edge_container.hpp" #include "extractor/compressed_edge_container.hpp"
#include "extractor/query_node.hpp" #include "extractor/query_node.hpp"
#include "extractor/guidance/discrete_angle.hpp"
#include "extractor/guidance/classification_data.hpp" #include "extractor/guidance/classification_data.hpp"
#include "extractor/guidance/discrete_angle.hpp"
#include "extractor/guidance/turn_instruction.hpp" #include "extractor/guidance/turn_instruction.hpp"
#include <algorithm> #include <algorithm>
#include <map>
#include <cmath> #include <cmath>
#include <cstdint> #include <cstdint>
#include <map>
#include <string> #include <string>
namespace osrm namespace osrm
@ -42,16 +42,15 @@ getCoordinateFromCompressedRange(util::Coordinate current_coordinate,
const util::Coordinate final_coordinate, const util::Coordinate final_coordinate,
const std::vector<extractor::QueryNode> &query_nodes) const std::vector<extractor::QueryNode> &query_nodes)
{ {
const auto extractCoordinateFromNode = [](const extractor::QueryNode &node) -> util::Coordinate const auto extractCoordinateFromNode =
{ [](const extractor::QueryNode &node) -> util::Coordinate {
return {node.lon, node.lat}; return {node.lon, node.lat};
}; };
double distance_to_current_coordinate = 0; double distance_to_current_coordinate = 0;
double distance_to_next_coordinate = 0; double distance_to_next_coordinate = 0;
// get the length that is missing from the current segment to reach DESIRED_SEGMENT_LENGTH // get the length that is missing from the current segment to reach DESIRED_SEGMENT_LENGTH
const auto getFactor = [](const double first_distance, const double second_distance) const auto getFactor = [](const double first_distance, const double second_distance) {
{
BOOST_ASSERT(first_distance < detail::DESIRED_SEGMENT_LENGTH); BOOST_ASSERT(first_distance < detail::DESIRED_SEGMENT_LENGTH);
double segment_length = second_distance - first_distance; double segment_length = second_distance - first_distance;
BOOST_ASSERT(segment_length > 0); BOOST_ASSERT(segment_length > 0);
@ -104,8 +103,8 @@ getRepresentativeCoordinate(const NodeID from_node,
const extractor::CompressedEdgeContainer &compressed_geometries, const extractor::CompressedEdgeContainer &compressed_geometries,
const std::vector<extractor::QueryNode> &query_nodes) const std::vector<extractor::QueryNode> &query_nodes)
{ {
const auto extractCoordinateFromNode = [](const extractor::QueryNode &node) -> util::Coordinate const auto extractCoordinateFromNode =
{ [](const extractor::QueryNode &node) -> util::Coordinate {
return {node.lon, node.lat}; return {node.lon, node.lat};
}; };
@ -298,14 +297,10 @@ inline DirectionModifier getTurnDirection(const double angle)
// swaps left <-> right modifier types // swaps left <-> right modifier types
inline DirectionModifier mirrorDirectionModifier(const DirectionModifier modifier) inline DirectionModifier mirrorDirectionModifier(const DirectionModifier modifier)
{ {
const constexpr DirectionModifier results[] = {DirectionModifier::UTurn, const constexpr DirectionModifier results[] = {
DirectionModifier::SharpLeft, DirectionModifier::UTurn, DirectionModifier::SharpLeft, DirectionModifier::Left,
DirectionModifier::Left, DirectionModifier::SlightLeft, DirectionModifier::Straight, DirectionModifier::SlightRight,
DirectionModifier::SlightLeft, DirectionModifier::Right, DirectionModifier::SharpRight};
DirectionModifier::Straight,
DirectionModifier::SlightRight,
DirectionModifier::Right,
DirectionModifier::SharpRight};
return results[modifier]; return results[modifier];
} }
@ -345,14 +340,14 @@ inline bool requiresNameAnnounced(const std::string &from, const std::string &to
std::string to_ref; std::string to_ref;
// Split from the format "{name} ({ref})" -> name, ref // Split from the format "{name} ({ref})" -> name, ref
auto split = [](const std::string &name, std::string &out_name, std::string &out_ref) auto split = [](const std::string &name, std::string &out_name, std::string &out_ref) {
{
const auto ref_begin = name.find_first_of('('); const auto ref_begin = name.find_first_of('(');
if (ref_begin != std::string::npos) if (ref_begin != std::string::npos)
{ {
//we might need to trim a space, if there is a reference if (ref_begin != 0)
out_name = name.substr(0, ref_begin - (ref_begin > 0 && name[ref_begin-1] == ' ')); out_name = name.substr(0, ref_begin - 1);
out_ref = name.substr(ref_begin + 1, name.find_first_of(')') - 1); const auto ref_end = name.find_first_of(')');
out_ref = name.substr(ref_begin + 1, ref_end - ref_begin - 1);
} }
else else
{ {
@ -364,35 +359,38 @@ inline bool requiresNameAnnounced(const std::string &from, const std::string &to
split(to, to_name, to_ref); split(to, to_name, to_ref);
// check similarity of names // check similarity of names
auto names_are_empty = from_name.empty() && to_name.empty(); const auto names_are_empty = from_name.empty() && to_name.empty();
auto names_are_equal = from_name == to_name; const auto names_are_equal = from_name == to_name;
auto name_is_removed = !from_name.empty() && to_name.empty(); const auto name_is_removed = !from_name.empty() && to_name.empty();
// references are contained in one another // references are contained in one another
auto refs_are_empty = from_ref.empty() && to_ref.empty(); const auto refs_are_empty = from_ref.empty() && to_ref.empty();
auto ref_is_contained = const auto ref_is_contained =
!from_ref.empty() && !to_ref.empty() && from_ref.empty() || to_ref.empty() ||
(from_ref.find(to_ref) != std::string::npos || to_ref.find(from_ref) != std::string::npos); (from_ref.find(to_ref) != std::string::npos || to_ref.find(from_ref) != std::string::npos);
auto ref_is_removed = !from_ref.empty() && to_ref.empty(); const auto ref_is_removed = !from_ref.empty() && to_ref.empty();
auto obvious_change = ref_is_contained || names_are_equal || const auto obvious_change =
(names_are_empty && refs_are_empty) || name_is_removed || ref_is_removed; (names_are_empty && refs_are_empty) || (names_are_equal && ref_is_contained) ||
(names_are_equal && refs_are_empty) || name_is_removed || ref_is_removed;
return !obvious_change; return !obvious_change;
} }
inline int getPriority( const FunctionalRoadClass road_class ) inline int getPriority(const FunctionalRoadClass road_class)
{ {
//The road priorities indicate which roads can bee seen as more or less equal. // The road priorities indicate which roads can bee seen as more or less equal.
//They are used in Fork-Discovery. Possibly should be moved to profiles post v5? // They are used in Fork-Discovery. Possibly should be moved to profiles post v5?
//A fork can happen between road types that are at most 1 priority apart from each other // A fork can happen between road types that are at most 1 priority apart from each other
const constexpr int road_priority[] = {10, 0, 10, 2, 10, 4, 10, 6, 10, 8, 10, 11, 10, 12, 10, 14}; const constexpr int road_priority[] = {10, 0, 10, 2, 10, 4, 10, 6,
10, 8, 10, 11, 10, 12, 10, 14};
return road_priority[static_cast<int>(road_class)]; return road_priority[static_cast<int>(road_class)];
} }
inline bool canBeSeenAsFork(const FunctionalRoadClass first, const FunctionalRoadClass second) inline bool canBeSeenAsFork(const FunctionalRoadClass first, const FunctionalRoadClass second)
{ {
// forks require similar road categories // forks require similar road categories
// Based on the priorities assigned above, we can set forks only if the road priorities match closely. // Based on the priorities assigned above, we can set forks only if the road priorities match
// closely.
// Potentially we could include features like number of lanes here and others? // Potentially we could include features like number of lanes here and others?
// Should also be moved to profiles // Should also be moved to profiles
return std::abs(getPriority(first) - getPriority(second)) <= 1; return std::abs(getPriority(first) - getPriority(second)) <= 1;

View File

@ -1,20 +1,20 @@
#ifndef OSRM_EXTRACTOR_TURN_ANALYSIS #ifndef OSRM_EXTRACTOR_TURN_ANALYSIS
#define OSRM_EXTRACTOR_TURN_ANALYSIS #define OSRM_EXTRACTOR_TURN_ANALYSIS
#include "extractor/guidance/turn_classification.hpp"
#include "extractor/guidance/toolkit.hpp"
#include "extractor/restriction_map.hpp"
#include "extractor/compressed_edge_container.hpp" #include "extractor/compressed_edge_container.hpp"
#include "extractor/guidance/toolkit.hpp"
#include "extractor/guidance/turn_classification.hpp"
#include "extractor/restriction_map.hpp"
#include "util/name_table.hpp" #include "util/name_table.hpp"
#include <cstdint> #include <cstdint>
#include <string>
#include <vector>
#include <memory> #include <memory>
#include <utility> #include <string>
#include <unordered_set> #include <unordered_set>
#include <utility>
#include <vector>
namespace osrm namespace osrm
{ {
@ -129,6 +129,7 @@ class TurnAnalysis
// Instruction will be a silent instruction // Instruction will be a silent instruction
TurnInstruction getInstructionForObvious(const std::size_t number_of_candidates, TurnInstruction getInstructionForObvious(const std::size_t number_of_candidates,
const EdgeID via_edge, const EdgeID via_edge,
const bool through_street,
const ConnectedRoad &candidate) const; const ConnectedRoad &candidate) const;
// Helper Function that decides between NoTurn or NewName // Helper Function that decides between NoTurn or NewName

View File

@ -1,8 +1,8 @@
#ifndef OSRM_UTIL_NAME_TABLE_HPP #ifndef OSRM_UTIL_NAME_TABLE_HPP
#define OSRM_UTIL_NAME_TABLE_HPP #define OSRM_UTIL_NAME_TABLE_HPP
#include "util/shared_memory_vector_wrapper.hpp"
#include "util/range_table.hpp" #include "util/range_table.hpp"
#include "util/shared_memory_vector_wrapper.hpp"
#include <string> #include <string>

View File

@ -4,8 +4,8 @@
#include "util/integer_range.hpp" #include "util/integer_range.hpp"
#include "util/shared_memory_vector_wrapper.hpp" #include "util/shared_memory_vector_wrapper.hpp"
#include <fstream>
#include <array> #include <array>
#include <fstream>
#include <utility> #include <utility>
namespace osrm namespace osrm
@ -61,8 +61,7 @@ template <unsigned BLOCK_SIZE, bool USE_SHARED_MEMORY> class RangeTable
// construct table from length vector // construct table from length vector
template <typename VectorT> explicit RangeTable(const VectorT &lengths) template <typename VectorT> explicit RangeTable(const VectorT &lengths)
{ {
const unsigned number_of_blocks = [&lengths]() const unsigned number_of_blocks = [&lengths]() {
{
unsigned num = (lengths.size() + 1) / (BLOCK_SIZE + 1); unsigned num = (lengths.size() + 1) / (BLOCK_SIZE + 1);
if ((lengths.size() + 1) % (BLOCK_SIZE + 1) != 0) if ((lengths.size() + 1) % (BLOCK_SIZE + 1) != 0)
{ {
@ -169,7 +168,7 @@ template <unsigned BLOCK_SIZE, bool USE_SHARED_MEMORY> class RangeTable
end_idx = block_offsets[block_idx + 1]; end_idx = block_offsets[block_idx + 1];
} }
BOOST_ASSERT(begin_idx < sum_lengths && end_idx <= sum_lengths); BOOST_ASSERT(end_idx <= sum_lengths);
BOOST_ASSERT(begin_idx <= end_idx); BOOST_ASSERT(begin_idx <= end_idx);
return irange(begin_idx, end_idx); return irange(begin_idx, end_idx);

View File

@ -1,16 +1,16 @@
#include "engine/guidance/post_processing.hpp" #include "engine/guidance/post_processing.hpp"
#include "extractor/guidance/turn_instruction.hpp" #include "extractor/guidance/turn_instruction.hpp"
#include "engine/guidance/toolkit.hpp"
#include "engine/guidance/assemble_steps.hpp" #include "engine/guidance/assemble_steps.hpp"
#include "engine/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>
#include <algorithm> #include <algorithm>
#include <iostream>
#include <cmath> #include <cmath>
#include <cstddef> #include <cstddef>
#include <iostream>
#include <limits> #include <limits>
#include <utility> #include <utility>
@ -55,8 +55,8 @@ void fixFinalRoundabout(std::vector<RouteStep> &steps)
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;
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; break;
@ -130,7 +130,7 @@ void closeOffRoundabout(const bool on_roundabout,
steps[1].maneuver.instruction.type = step.maneuver.instruction.type == TurnType::ExitRotary steps[1].maneuver.instruction.type = step.maneuver.instruction.type == TurnType::ExitRotary
? TurnType::EnterRotary ? TurnType::EnterRotary
: TurnType::EnterRoundabout; : TurnType::EnterRoundabout;
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;
} }
@ -154,8 +154,8 @@ void closeOffRoundabout(const bool on_roundabout,
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;
propagation_step.name = step.name; propagation_step.name = step.name;
@ -219,9 +219,8 @@ std::vector<RouteStep> postProcess(std::vector<RouteStep> steps)
// adds an intersection to the initial route step // adds an intersection to the initial route step
// It includes the length of the last step, until the intersection // It includes the length of the last step, until the intersection
// Also updates the length of the respective segment // Also updates the length of the respective segment
auto addIntersection = auto addIntersection = [](RouteStep into, const RouteStep &last_step,
[](RouteStep into, const RouteStep &last_step, const RouteStep &intersection) const RouteStep &intersection) {
{
into.maneuver.intersections.push_back( into.maneuver.intersections.push_back(
{last_step.duration, last_step.distance, intersection.maneuver.location}); {last_step.duration, last_step.distance, intersection.maneuver.location});
@ -294,8 +293,7 @@ std::vector<RouteStep> postProcess(std::vector<RouteStep> steps)
// Two valid NO_TURNs exist in each leg in the form of Depart/Arrive // Two valid NO_TURNs exist in each leg in the form of Depart/Arrive
// keep valid instructions // keep valid instructions
const auto not_is_valid = [](const RouteStep &step) const auto not_is_valid = [](const RouteStep &step) {
{
return step.maneuver.instruction == TurnInstruction::NO_TURN() && return step.maneuver.instruction == TurnInstruction::NO_TURN() &&
step.maneuver.waypoint_type == WaypointType::None; step.maneuver.waypoint_type == WaypointType::None;
}; };
@ -352,10 +350,8 @@ void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry)
// geometry offsets have to be adjusted. Move all offsets to the front and reduce by // geometry offsets have to be adjusted. Move all offsets to the front and reduce by
// one. (This is an inplace forward one and reduce by one) // one. (This is an inplace forward one and reduce by one)
std::transform(geometry.segment_offsets.begin() + 1, geometry.segment_offsets.end(), std::transform(geometry.segment_offsets.begin() + 1, geometry.segment_offsets.end(),
geometry.segment_offsets.begin(), [](const std::size_t val) geometry.segment_offsets.begin(),
{ [](const std::size_t val) { return val - 1; });
return val - 1;
});
geometry.segment_offsets.pop_back(); geometry.segment_offsets.pop_back();
const auto &current_depart = steps.front(); const auto &current_depart = steps.front();
@ -378,21 +374,18 @@ void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry)
steps.front().geometry_begin = 1; steps.front().geometry_begin = 1;
// reduce all offsets by one (inplace) // reduce all offsets by one (inplace)
std::transform(geometry.segment_offsets.begin(), geometry.segment_offsets.end(), std::transform(geometry.segment_offsets.begin(), geometry.segment_offsets.end(),
geometry.segment_offsets.begin(), [](const std::size_t val) geometry.segment_offsets.begin(),
{ [](const std::size_t val) { return val - 1; });
return val - 1;
});
steps.front().maneuver = detail::stepManeuverFromGeometry( steps.front().maneuver = detail::stepManeuverFromGeometry(
TurnInstruction::NO_TURN(), WaypointType::Depart, geometry); TurnInstruction::NO_TURN(), WaypointType::Depart, geometry);
} }
// and update the leg geometry indices for the removed entry // and update the leg geometry indices for the removed entry
std::for_each(steps.begin(), steps.end(), [](RouteStep &step) std::for_each(steps.begin(), steps.end(), [](RouteStep &step) {
{ --step.geometry_begin;
--step.geometry_begin; --step.geometry_end;
--step.geometry_end; });
});
} }
// make sure we still have enough segments // make sure we still have enough segments

View File

@ -1,12 +1,13 @@
#include "extractor/guidance/constants.hpp"
#include "extractor/guidance/turn_analysis.hpp" #include "extractor/guidance/turn_analysis.hpp"
#include "util/simple_logger.hpp"
#include "util/coordinate.hpp" #include "util/coordinate.hpp"
#include "util/coordinate_calculation.hpp" #include "util/coordinate_calculation.hpp"
#include "util/simple_logger.hpp"
#include <cstddef> #include <cstddef>
#include <limits>
#include <iomanip> #include <iomanip>
#include <limits>
#include <set> #include <set>
#include <unordered_set> #include <unordered_set>
@ -16,20 +17,6 @@ namespace extractor
{ {
namespace guidance namespace guidance
{ {
// configuration of turn classification
const bool constexpr INVERT = true;
// what angle is interpreted as going straight
const double constexpr STRAIGHT_ANGLE = 180.;
// if a turn deviates this much from going straight, it will be kept straight
const double constexpr MAXIMAL_ALLOWED_NO_TURN_DEVIATION = 3.;
// angle that lies between two nearly indistinguishable roads
const double constexpr NARROW_TURN_ANGLE = 30.;
const double constexpr GROUP_ANGLE = 90;
// angle difference that can be classified as straight, if its the only narrow turn
const double constexpr FUZZY_ANGLE_DIFFERENCE = 15.;
const double constexpr DISTINCTION_RATIO = 2;
const unsigned constexpr INVALID_NAME_ID = 0;
using EdgeData = util::NodeBasedDynamicGraph::EdgeData; using EdgeData = util::NodeBasedDynamicGraph::EdgeData;
@ -101,17 +88,15 @@ inline bool isRampClass(EdgeID eid, const util::NodeBasedDynamicGraph &node_base
bool TurnAnalysis::isRotary(const NodeID nid) const bool TurnAnalysis::isRotary(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) {
{
return util::Coordinate(node_info_list[node].lon, node_info_list[node].lat); return util::Coordinate(node_info_list[node].lon, node_info_list[node].lat);
}; };
unsigned roundabout_name_id = 0; unsigned roundabout_name_id = 0;
std::unordered_set<unsigned> connected_names; std::unordered_set<unsigned> connected_names;
const auto getNextOnRoundabout = const auto getNextOnRoundabout = [this, &roundabout_name_id,
[this, &roundabout_name_id, &connected_names](const NodeID node) &connected_names](const NodeID node) {
{
EdgeID continue_edge = SPECIAL_EDGEID; EdgeID continue_edge = SPECIAL_EDGEID;
for (const auto edge : node_based_graph.GetAdjacentEdgeRange(node)) for (const auto edge : node_based_graph.GetAdjacentEdgeRange(node))
{ {
@ -183,15 +168,20 @@ bool TurnAnalysis::isRotary(const NodeID nid) const
// 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).
// Otherwise, we construct a circle through the first tree vertices. // Otherwise, we construct a circle through the first tree vertices.
auto node_itr = roundabout_nodes.begin(); const auto getRadius = [&roundabout_nodes,&getCoordinate](){
const double radius = roundabout_nodes.size() >= 3 auto node_itr = roundabout_nodes.begin();
? util::coordinate_calculation::circleRadius( if( roundabout_nodes.size() == 2 )
getCoordinate(*node_itr++), {
getCoordinate(*node_itr++), const auto first = getCoordinate(*node_itr++), second = getCoordinate(*node_itr++);
getCoordinate(*node_itr)) return 0.5 * util::coordinate_calculation::haversineDistance( first, second );
: 0.5 * util::coordinate_calculation::haversineDistance( }
getCoordinate(*node_itr++), else
getCoordinate(*node_itr)); {
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 // check whether the circle computation has gone wrong
// 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.
@ -199,7 +189,6 @@ bool TurnAnalysis::isRotary(const NodeID nid) const
if (std::isinf(radius)) if (std::isinf(radius))
return false; return false;
const double constexpr MAX_ROUNDABOUT_RADIUS = 15; // 30 m diameter as final distinction
return radius > MAX_ROUNDABOUT_RADIUS; return radius > MAX_ROUNDABOUT_RADIUS;
} }
@ -240,10 +229,10 @@ std::vector<TurnOperation> TurnAnalysis::getTurns(const NodeID from, const EdgeI
} }
if (on_roundabout || can_enter_roundabout) if (on_roundabout || can_enter_roundabout)
{ {
bool is_rotary = isRotary(node_based_graph.GetTarget(via_edge)); const bool is_rotary = isRotary(node_based_graph.GetTarget(via_edge));
// find the radius of the roundabout // find the radius of the roundabout
intersection = handleRoundabouts(is_rotary, via_edge, on_roundabout, can_exit_roundabout_separately, intersection = handleRoundabouts(is_rotary, via_edge, on_roundabout,
std::move(intersection)); can_exit_roundabout_separately, std::move(intersection));
} }
else else
{ {
@ -283,10 +272,8 @@ std::vector<TurnOperation> TurnAnalysis::getTurns(const NodeID from, const EdgeI
inline std::size_t countValid(const std::vector<ConnectedRoad> &intersection) inline std::size_t countValid(const std::vector<ConnectedRoad> &intersection)
{ {
return std::count_if(intersection.begin(), intersection.end(), [](const ConnectedRoad &road) return std::count_if(intersection.begin(), intersection.end(),
{ [](const ConnectedRoad &road) { return road.entry_allowed; });
return road.entry_allowed;
});
} }
std::vector<ConnectedRoad> std::vector<ConnectedRoad>
@ -377,14 +364,23 @@ TurnAnalysis::fallbackTurnAssignmentMotorway(std::vector<ConnectedRoad> intersec
const auto type = detail::isMotorwayClass(out_data.road_classification.road_class) const auto type = detail::isMotorwayClass(out_data.road_classification.road_class)
? TurnType::Merge ? TurnType::Merge
: TurnType::Turn; : TurnType::Turn;
if (angularDeviation(road.turn.angle, STRAIGHT_ANGLE) < FUZZY_ANGLE_DIFFERENCE)
road.turn.instruction = {type, DirectionModifier::Straight}; if (type == TurnType::Turn)
{
if (angularDeviation(road.turn.angle, STRAIGHT_ANGLE) < FUZZY_ANGLE_DIFFERENCE)
road.turn.instruction = {type, DirectionModifier::Straight};
else
{
road.turn.instruction = {type, road.turn.angle > STRAIGHT_ANGLE
? DirectionModifier::SlightLeft
: DirectionModifier::SlightRight};
}
}
else else
{ {
road.turn.instruction = {type, road.turn.instruction = {type, road.turn.angle < STRAIGHT_ANGLE
road.turn.angle > STRAIGHT_ANGLE ? DirectionModifier::SlightLeft
? DirectionModifier::SlightLeft : DirectionModifier::SlightRight};
: DirectionModifier::SlightRight};
} }
} }
return intersection; return intersection;
@ -397,8 +393,7 @@ TurnAnalysis::handleFromMotorway(const EdgeID via_edge,
const auto &in_data = node_based_graph.GetEdgeData(via_edge); const auto &in_data = node_based_graph.GetEdgeData(via_edge);
BOOST_ASSERT(detail::isMotorwayClass(in_data.road_classification.road_class)); BOOST_ASSERT(detail::isMotorwayClass(in_data.road_classification.road_class));
const auto countExitingMotorways = [this](const std::vector<ConnectedRoad> &intersection) const auto countExitingMotorways = [this](const std::vector<ConnectedRoad> &intersection) {
{
unsigned count = 0; unsigned count = 0;
for (const auto &road : intersection) for (const auto &road : intersection)
{ {
@ -409,22 +404,20 @@ TurnAnalysis::handleFromMotorway(const EdgeID via_edge,
}; };
// find the angle that continues on our current highway // find the angle that continues on our current highway
const auto getContinueAngle = [this, in_data](const std::vector<ConnectedRoad> &intersection) const auto getContinueAngle = [this, in_data](const std::vector<ConnectedRoad> &intersection) {
{
for (const auto &road : intersection) for (const auto &road : intersection)
{ {
const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid); const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
if (road.turn.angle != 0 && in_data.name_id == out_data.name_id && if (road.turn.angle != 0 && in_data.name_id == out_data.name_id &&
in_data.name_id != 0 && in_data.name_id != INVALID_NAME_ID &&
detail::isMotorwayClass(out_data.road_classification.road_class)) detail::isMotorwayClass(out_data.road_classification.road_class))
return road.turn.angle; return road.turn.angle;
} }
return intersection[0].turn.angle; return intersection[0].turn.angle;
}; };
const auto getMostLikelyContinue = const auto getMostLikelyContinue = [this,
[this, in_data](const std::vector<ConnectedRoad> &intersection) in_data](const std::vector<ConnectedRoad> &intersection) {
{
double angle = intersection[0].turn.angle; double angle = intersection[0].turn.angle;
double best = 180; double best = 180;
for (const auto &road : intersection) for (const auto &road : intersection)
@ -440,18 +433,33 @@ TurnAnalysis::handleFromMotorway(const EdgeID via_edge,
return angle; return angle;
}; };
const auto findBestContinue = [&]() const auto findBestContinue = [&]() {
{
const double continue_angle = getContinueAngle(intersection); const double continue_angle = getContinueAngle(intersection);
if (continue_angle != intersection[0].turn.angle) if (continue_angle != intersection[0].turn.angle)
return continue_angle; return continue_angle;
else else
return getMostLikelyContinue(intersection); return getMostLikelyContinue(intersection);
}; };
// check whether the obvious choice is actually a through street
const auto isThroughStreet = [&intersection, this](const ConnectedRoad &connection) {
if (node_based_graph.GetEdgeData(connection.turn.eid).name_id == INVALID_NAME_ID)
return false;
for (const auto &road : intersection)
{
// a through street cannot start at our own position
if (road.turn.angle < std::numeric_limits<double>::epsilon())
continue;
if (angularDeviation(road.turn.angle, connection.turn.angle) >
(STRAIGHT_ANGLE - NARROW_TURN_ANGLE) &&
node_based_graph.GetEdgeData(road.turn.eid).name_id ==
node_based_graph.GetEdgeData(connection.turn.eid).name_id)
return true;
}
return false;
};
// find continue angle // find continue angle
const double continue_angle = findBestContinue(); const double continue_angle = findBestContinue();
// highway does not continue and has no obvious choice // highway does not continue and has no obvious choice
if (continue_angle == intersection[0].turn.angle) if (continue_angle == intersection[0].turn.angle)
{ {
@ -524,12 +532,11 @@ TurnAnalysis::handleFromMotorway(const EdgeID via_edge,
BOOST_ASSERT(!detail::isRampClass(intersection[1].turn.eid, node_based_graph)); BOOST_ASSERT(!detail::isRampClass(intersection[1].turn.eid, node_based_graph));
intersection[1].turn.instruction = intersection[1].turn.instruction =
getInstructionForObvious(intersection.size(), via_edge, intersection[1]); getInstructionForObvious(intersection.size(), via_edge,
isThroughStreet(intersection[1]), intersection[1]);
} }
else else
{ {
// continue on the same highway
bool continues = (getContinueAngle(intersection) != intersection[0].turn.angle);
// Normal Highway exit or merge // Normal Highway exit or merge
for (auto &road : intersection) for (auto &road : intersection)
{ {
@ -539,11 +546,8 @@ TurnAnalysis::handleFromMotorway(const EdgeID via_edge,
if (road.turn.angle == continue_angle) if (road.turn.angle == continue_angle)
{ {
if (continues) road.turn.instruction = getInstructionForObvious(
road.turn.instruction = intersection.size(), via_edge, isThroughStreet(road), road);
TurnInstruction::SUPPRESSED(DirectionModifier::Straight);
else // TODO handle turn direction correctly
road.turn.instruction = {TurnType::Merge, DirectionModifier::Straight};
} }
else if (road.turn.angle < continue_angle) else if (road.turn.angle < continue_angle)
{ {
@ -570,7 +574,8 @@ TurnAnalysis::handleFromMotorway(const EdgeID via_edge,
if (exiting_motorways == 2 && intersection.size() == 2) if (exiting_motorways == 2 && intersection.size() == 2)
{ {
intersection[1].turn.instruction = intersection[1].turn.instruction =
getInstructionForObvious(intersection.size(), via_edge, intersection[1]); getInstructionForObvious(intersection.size(), via_edge,
isThroughStreet(intersection[1]), intersection[1]);
util::SimpleLogger().Write(logWARNING) util::SimpleLogger().Write(logWARNING)
<< "Disabled U-Turn on a freeway at " << "Disabled U-Turn on a freeway at "
<< localizer(node_based_graph.GetTarget(via_edge)); << localizer(node_based_graph.GetTarget(via_edge));
@ -633,8 +638,9 @@ TurnAnalysis::handleFromMotorway(const EdgeID via_edge,
auto coord = localizer(node_based_graph.GetTarget(via_edge)); auto coord = localizer(node_based_graph.GetTarget(via_edge));
util::SimpleLogger().Write(logWARNING) util::SimpleLogger().Write(logWARNING)
<< "Found motorway junction with more than " << "Found motorway junction with more than "
"2 exiting motorways or additional ramps at " << std::setprecision(12) "2 exiting motorways or additional ramps at "
<< toFloating(coord.lat) << " " << toFloating(coord.lon); << std::setprecision(12) << toFloating(coord.lat) << " "
<< toFloating(coord.lon);
fallbackTurnAssignmentMotorway(intersection); fallbackTurnAssignmentMotorway(intersection);
} }
} // done for more than one highway exit } // done for more than one highway exit
@ -647,14 +653,30 @@ TurnAnalysis::handleMotorwayRamp(const EdgeID via_edge,
std::vector<ConnectedRoad> intersection) const std::vector<ConnectedRoad> intersection) const
{ {
auto num_valid_turns = countValid(intersection); auto num_valid_turns = countValid(intersection);
const auto isThroughStreet = [&intersection, this](const ConnectedRoad &connection) {
if (node_based_graph.GetEdgeData(connection.turn.eid).name_id == INVALID_NAME_ID)
return false;
for (const auto &road : intersection)
{
// a through street cannot start at our own position
if (road.turn.angle < std::numeric_limits<double>::epsilon())
continue;
if (angularDeviation(road.turn.angle, connection.turn.angle) >
(STRAIGHT_ANGLE - NARROW_TURN_ANGLE) &&
node_based_graph.GetEdgeData(road.turn.eid).name_id ==
node_based_graph.GetEdgeData(connection.turn.eid).name_id)
return true;
}
return false;
};
// ramp straight into a motorway/ramp // ramp straight into a motorway/ramp
if (intersection.size() == 2 && num_valid_turns == 1) if (intersection.size() == 2 && num_valid_turns == 1)
{ {
BOOST_ASSERT(!intersection[0].entry_allowed); BOOST_ASSERT(!intersection[0].entry_allowed);
BOOST_ASSERT(detail::isMotorwayClass(intersection[1].turn.eid, node_based_graph)); BOOST_ASSERT(detail::isMotorwayClass(intersection[1].turn.eid, node_based_graph));
intersection[1].turn.instruction = intersection[1].turn.instruction = getInstructionForObvious(
getInstructionForObvious(intersection.size(), via_edge, intersection[1]); intersection.size(), via_edge, isThroughStreet(intersection[1]), intersection[1]);
} }
else if (intersection.size() == 3) else if (intersection.size() == 3)
{ {
@ -672,7 +694,11 @@ TurnAnalysis::handleMotorwayRamp(const EdgeID via_edge,
// 0 // 0
if (intersection[1].entry_allowed) if (intersection[1].entry_allowed)
{ {
if (detail::isMotorwayClass(intersection[1].turn.eid, node_based_graph)) if (detail::isMotorwayClass(intersection[1].turn.eid, node_based_graph) &&
node_based_graph.GetEdgeData(intersection[2].turn.eid).name_id !=
INVALID_NAME_ID &&
node_based_graph.GetEdgeData(intersection[2].turn.eid).name_id ==
node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id)
{ {
// circular order indicates a merge to the left (0-3 onto 4 // circular order indicates a merge to the left (0-3 onto 4
if (angularDeviation(intersection[1].turn.angle, STRAIGHT_ANGLE) < if (angularDeviation(intersection[1].turn.angle, STRAIGHT_ANGLE) <
@ -684,13 +710,20 @@ TurnAnalysis::handleMotorwayRamp(const EdgeID via_edge,
TurnType::Merge, getTurnDirection(intersection[1].turn.angle)}; TurnType::Merge, getTurnDirection(intersection[1].turn.angle)};
} }
else // passing by the end of a motorway else // passing by the end of a motorway
{
intersection[1].turn.instruction = intersection[1].turn.instruction =
getInstructionForObvious(intersection.size(), via_edge, intersection[1]); getInstructionForObvious(intersection.size(), via_edge,
isThroughStreet(intersection[1]), intersection[1]);
}
} }
else else
{ {
BOOST_ASSERT(intersection[2].entry_allowed); BOOST_ASSERT(intersection[2].entry_allowed);
if (detail::isMotorwayClass(intersection[2].turn.eid, node_based_graph)) if (detail::isMotorwayClass(intersection[2].turn.eid, node_based_graph) &&
node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id !=
INVALID_NAME_ID &&
node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id ==
node_based_graph.GetEdgeData(intersection[0].turn.eid).name_id)
{ {
// circular order (5-0) onto 4 // circular order (5-0) onto 4
if (angularDeviation(intersection[2].turn.angle, STRAIGHT_ANGLE) < if (angularDeviation(intersection[2].turn.angle, STRAIGHT_ANGLE) <
@ -702,8 +735,11 @@ TurnAnalysis::handleMotorwayRamp(const EdgeID via_edge,
TurnType::Merge, getTurnDirection(intersection[2].turn.angle)}; TurnType::Merge, getTurnDirection(intersection[2].turn.angle)};
} }
else // passing the end of a highway else // passing the end of a highway
intersection[1].turn.instruction = {
getInstructionForObvious(intersection.size(), via_edge, intersection[1]); intersection[2].turn.instruction =
getInstructionForObvious(intersection.size(), via_edge,
isThroughStreet(intersection[2]), intersection[2]);
}
} }
} }
else else
@ -733,17 +769,14 @@ TurnAnalysis::handleMotorwayRamp(const EdgeID via_edge,
if (detail::isMotorwayClass(node_based_graph.GetEdgeData(intersection[1].turn.eid) if (detail::isMotorwayClass(node_based_graph.GetEdgeData(intersection[1].turn.eid)
.road_classification.road_class)) .road_classification.road_class))
{ {
intersection[1].turn.instruction = {TurnType::Merge, intersection[1].turn.instruction = {TurnType::Turn,
DirectionModifier::SlightRight}; DirectionModifier::SlightRight};
intersection[2].turn.instruction = {TurnType::Fork, intersection[2].turn.instruction = {TurnType::Continue,
DirectionModifier::SlightLeft}; DirectionModifier::SlightLeft};
} }
else else
{ {
intersection[1].turn.instruction = {TurnType::Fork, assignFork(via_edge, intersection[2], intersection[1]);
DirectionModifier::SlightRight};
intersection[2].turn.instruction = {TurnType::Merge,
DirectionModifier::SlightLeft};
} }
} }
} }
@ -762,8 +795,8 @@ TurnAnalysis::handleMotorwayRamp(const EdgeID via_edge,
} }
else if (detail::isMotorwayClass(edge_data.road_classification.road_class)) else if (detail::isMotorwayClass(edge_data.road_classification.road_class))
{ {
road.turn.instruction = {TurnType::Merge, road.turn.instruction = {TurnType::Merge, passed_highway_entry
passed_highway_entry ? DirectionModifier::SlightRight ? DirectionModifier::SlightRight
: DirectionModifier::SlightLeft}; : DirectionModifier::SlightLeft};
} }
else else
@ -814,9 +847,7 @@ bool TurnAnalysis::isMotorwayJunction(const EdgeID via_edge,
{ {
const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid); const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
// not merging or forking? // not merging or forking?
if ((angularDeviation(road.turn.angle, 0) > 35 && if (road.entry_allowed && angularDeviation(road.turn.angle, STRAIGHT_ANGLE) > 60)
angularDeviation(road.turn.angle, 180) > 35) ||
(road.entry_allowed && angularDeviation(road.turn.angle, 0) < 35))
return false; return false;
else if (out_data.road_classification.road_class == FunctionalRoadClass::MOTORWAY || else if (out_data.road_classification.road_class == FunctionalRoadClass::MOTORWAY ||
out_data.road_classification.road_class == FunctionalRoadClass::TRUNK) out_data.road_classification.road_class == FunctionalRoadClass::TRUNK)
@ -860,6 +891,7 @@ TurnType TurnAnalysis::findBasicTurnType(const EdgeID via_edge, const ConnectedR
TurnInstruction TurnAnalysis::getInstructionForObvious(const std::size_t num_roads, TurnInstruction TurnAnalysis::getInstructionForObvious(const std::size_t num_roads,
const EdgeID via_edge, const EdgeID via_edge,
const bool through_street,
const ConnectedRoad &road) const const ConnectedRoad &road) const
{ {
const auto type = findBasicTurnType(via_edge, road); const auto type = findBasicTurnType(via_edge, road);
@ -882,7 +914,19 @@ TurnInstruction TurnAnalysis::getInstructionForObvious(const std::size_t num_roa
if (in_data.name_id != out_data.name_id && if (in_data.name_id != out_data.name_id &&
requiresNameAnnounced(name_table.GetNameForID(in_data.name_id), requiresNameAnnounced(name_table.GetNameForID(in_data.name_id),
name_table.GetNameForID(out_data.name_id))) name_table.GetNameForID(out_data.name_id)))
return {TurnType::NewName, getTurnDirection(road.turn.angle)}; {
// obvious turn onto a through street is a merge
if (through_street)
{
return {TurnType::Merge, road.turn.angle > STRAIGHT_ANGLE
? DirectionModifier::SlightRight
: DirectionModifier::SlightLeft};
}
else
{
return {TurnType::NewName, getTurnDirection(road.turn.angle)};
}
}
else else
{ {
if (in_mode == out_mode) if (in_mode == out_mode)
@ -918,7 +962,7 @@ TurnAnalysis::handleTwoWayTurn(const EdgeID via_edge, std::vector<ConnectedRoad>
{ {
BOOST_ASSERT(intersection[0].turn.angle < 0.001); BOOST_ASSERT(intersection[0].turn.angle < 0.001);
intersection[1].turn.instruction = intersection[1].turn.instruction =
getInstructionForObvious(intersection.size(), via_edge, intersection[1]); getInstructionForObvious(intersection.size(), via_edge, false, intersection[1]);
if (intersection[1].turn.instruction.type == TurnType::Suppressed) if (intersection[1].turn.instruction.type == TurnType::Suppressed)
intersection[1].turn.instruction.type = TurnType::NoTurn; intersection[1].turn.instruction.type = TurnType::NoTurn;
@ -931,15 +975,28 @@ TurnAnalysis::handleThreeWayTurn(const EdgeID via_edge,
std::vector<ConnectedRoad> intersection) const std::vector<ConnectedRoad> intersection) const
{ {
BOOST_ASSERT(intersection[0].turn.angle < 0.001); BOOST_ASSERT(intersection[0].turn.angle < 0.001);
const auto isObviousOfTwo = [](const ConnectedRoad road, const ConnectedRoad other) const auto isObviousOfTwo = [this](const ConnectedRoad road, const ConnectedRoad other) {
{ const auto first_class =
return (angularDeviation(road.turn.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE && node_based_graph.GetEdgeData(road.turn.eid).road_classification.road_class;
angularDeviation(other.turn.angle, STRAIGHT_ANGLE) > 85) || const bool is_ramp = isRampClass(first_class);
(angularDeviation(road.turn.angle, STRAIGHT_ANGLE) < const auto second_class =
std::numeric_limits<double>::epsilon()) || node_based_graph.GetEdgeData(other.turn.eid).road_classification.road_class;
(angularDeviation(other.turn.angle, STRAIGHT_ANGLE) / const bool is_narrow_turn =
angularDeviation(road.turn.angle, STRAIGHT_ANGLE) > angularDeviation(road.turn.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE;
1.4); const bool other_turn_is_at_least_orthogonal =
angularDeviation(other.turn.angle, STRAIGHT_ANGLE) > 85;
const bool turn_is_perfectly_straight = angularDeviation(road.turn.angle, STRAIGHT_ANGLE) <
std::numeric_limits<double>::epsilon();
const bool is_obvious_by_road_class =
(!is_ramp && (2 * getPriority(first_class) < getPriority(second_class))) ||
(!isLowPriorityRoadClass(first_class) && isLowPriorityRoadClass(second_class));
const bool is_much_narrower_than_other =
angularDeviation(other.turn.angle, STRAIGHT_ANGLE) /
angularDeviation(road.turn.angle, STRAIGHT_ANGLE) >
INCREASES_BY_FOURTY_PERCENT;
return (is_narrow_turn && other_turn_is_at_least_orthogonal) ||
turn_is_perfectly_straight || is_much_narrower_than_other ||
is_obvious_by_road_class;
}; };
/* Two nearly straight turns -> FORK /* Two nearly straight turns -> FORK
@ -959,30 +1016,39 @@ TurnAnalysis::handleThreeWayTurn(const EdgeID via_edge,
const auto right_class = node_based_graph.GetEdgeData(intersection[1].turn.eid) const auto right_class = node_based_graph.GetEdgeData(intersection[1].turn.eid)
.road_classification.road_class; .road_classification.road_class;
if (canBeSeenAsFork(left_class, right_class)) if (canBeSeenAsFork(left_class, right_class))
{
assignFork(via_edge, intersection[2], intersection[1]); assignFork(via_edge, intersection[2], intersection[1]);
else if (getPriority(left_class) > getPriority(right_class)) }
else if (isObviousOfTwo(intersection[1], intersection[2]))
{ {
intersection[1].turn.instruction = intersection[1].turn.instruction =
getInstructionForObvious(intersection.size(), via_edge, intersection[1]); getInstructionForObvious(intersection.size(), via_edge, false, intersection[1]);
intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]), intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
DirectionModifier::SlightLeft}; DirectionModifier::SlightLeft};
} }
else else if (isObviousOfTwo(intersection[2], intersection[1]))
{ {
intersection[2].turn.instruction = intersection[2].turn.instruction =
getInstructionForObvious(intersection.size(), via_edge, intersection[2]); getInstructionForObvious(intersection.size(), via_edge, false, intersection[2]);
intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]), intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
DirectionModifier::SlightRight}; DirectionModifier::SlightRight};
} }
else
{
intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
DirectionModifier::SlightRight};
intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
DirectionModifier::SlightLeft};
}
} }
else else
{ {
if (intersection[1].entry_allowed) if (intersection[1].entry_allowed)
intersection[1].turn.instruction = intersection[1].turn.instruction =
getInstructionForObvious(intersection.size(), via_edge, intersection[1]); getInstructionForObvious(intersection.size(), via_edge, false, intersection[1]);
if (intersection[2].entry_allowed) if (intersection[2].entry_allowed)
intersection[2].turn.instruction = intersection[2].turn.instruction =
getInstructionForObvious(intersection.size(), via_edge, intersection[2]); getInstructionForObvious(intersection.size(), via_edge, false, intersection[2]);
} }
} }
/* T Intersection /* T Intersection
@ -1028,7 +1094,7 @@ TurnAnalysis::handleThreeWayTurn(const EdgeID via_edge,
{ {
if (TurnType::Ramp != findBasicTurnType(via_edge, intersection[1])) if (TurnType::Ramp != findBasicTurnType(via_edge, intersection[1]))
intersection[1].turn.instruction = intersection[1].turn.instruction =
getInstructionForObvious(intersection.size(), via_edge, intersection[1]); getInstructionForObvious(intersection.size(), via_edge, false, intersection[1]);
else else
intersection[1].turn.instruction = {TurnType::Ramp, DirectionModifier::Straight}; intersection[1].turn.instruction = {TurnType::Ramp, DirectionModifier::Straight};
} }
@ -1052,7 +1118,7 @@ TurnAnalysis::handleThreeWayTurn(const EdgeID via_edge,
{ {
if (intersection[2].entry_allowed) if (intersection[2].entry_allowed)
intersection[2].turn.instruction = intersection[2].turn.instruction =
getInstructionForObvious(intersection.size(), via_edge, intersection[2]); getInstructionForObvious(intersection.size(), via_edge, false, intersection[2]);
if (intersection[1].entry_allowed) if (intersection[1].entry_allowed)
intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]), intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
DirectionModifier::Right}; DirectionModifier::Right};
@ -1062,11 +1128,18 @@ TurnAnalysis::handleThreeWayTurn(const EdgeID via_edge,
node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id == node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id ==
node_based_graph.GetEdgeData(intersection[2].turn.eid).name_id) node_based_graph.GetEdgeData(intersection[2].turn.eid).name_id)
{ {
const auto findTurn = [isObviousOfTwo](const ConnectedRoad turn, const ConnectedRoad other) const auto findTurn = [isObviousOfTwo](const ConnectedRoad turn,
-> TurnInstruction const ConnectedRoad other) -> TurnInstruction {
{ if (isObviousOfTwo(turn, other))
return {isObviousOfTwo(turn, other) ? TurnType::Merge : TurnType::Turn, {
getTurnDirection(turn.turn.angle)}; return {TurnType::Merge, turn.turn.angle < STRAIGHT_ANGLE
? DirectionModifier::SlightLeft
: DirectionModifier::SlightRight};
}
else
{
return {TurnType::Turn, getTurnDirection(turn.turn.angle)};
}
}; };
intersection[1].turn.instruction = findTurn(intersection[1], intersection[2]); intersection[1].turn.instruction = findTurn(intersection[1], intersection[2]);
intersection[2].turn.instruction = findTurn(intersection[2], intersection[1]); intersection[2].turn.instruction = findTurn(intersection[2], intersection[1]);
@ -1087,7 +1160,7 @@ TurnAnalysis::handleThreeWayTurn(const EdgeID via_edge,
intersection[1].turn.instruction = {TurnType::Continue, intersection[1].turn.instruction = {TurnType::Continue,
getTurnDirection(intersection[1].turn.angle)}; getTurnDirection(intersection[1].turn.angle)};
} }
intersection[2].turn.instruction = {TurnType::Turn, intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
getTurnDirection(intersection[2].turn.angle)}; getTurnDirection(intersection[2].turn.angle)};
} }
// other street merges from the right // other street merges from the right
@ -1105,28 +1178,30 @@ TurnAnalysis::handleThreeWayTurn(const EdgeID via_edge,
intersection[2].turn.instruction = {TurnType::Continue, intersection[2].turn.instruction = {TurnType::Continue,
getTurnDirection(intersection[2].turn.angle)}; getTurnDirection(intersection[2].turn.angle)};
} }
intersection[1].turn.instruction = {TurnType::Turn, intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
getTurnDirection(intersection[1].turn.angle)}; getTurnDirection(intersection[1].turn.angle)};
} }
else else
{ {
if (isObviousOfTwo(intersection[1], intersection[2])) if (isObviousOfTwo(intersection[1], intersection[2]))
{ {
intersection[1].turn.instruction = getInstructionForObvious(3,via_edge,intersection[1]); intersection[1].turn.instruction =
getInstructionForObvious(3, via_edge, false, intersection[1]);
} }
else else
{ {
intersection[1].turn.instruction = {TurnType::Turn, intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
getTurnDirection(intersection[1].turn.angle)}; getTurnDirection(intersection[1].turn.angle)};
} }
if (isObviousOfTwo(intersection[2], intersection[1])) if (isObviousOfTwo(intersection[2], intersection[1]))
{ {
intersection[2].turn.instruction = getInstructionForObvious(3,via_edge,intersection[2]); intersection[2].turn.instruction =
getInstructionForObvious(3, via_edge, false, intersection[2]);
} }
else else
{ {
intersection[2].turn.instruction = {TurnType::Turn, intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
getTurnDirection(intersection[2].turn.angle)}; getTurnDirection(intersection[2].turn.angle)};
} }
} }
@ -1167,14 +1242,18 @@ void TurnAnalysis::handleDistinctConflict(const EdgeID via_edge,
else if (getPriority(left_class) > getPriority(right_class)) else if (getPriority(left_class) > getPriority(right_class))
{ {
// FIXME this should possibly know about the actual roads? // FIXME this should possibly know about the actual roads?
right.turn.instruction = getInstructionForObvious(4, via_edge, right); // here we don't know about the intersection size. To be on the save side, we declare it
// as complex (at least size 4)
right.turn.instruction = getInstructionForObvious(4, via_edge, false, right);
left.turn.instruction = {findBasicTurnType(via_edge, left), left.turn.instruction = {findBasicTurnType(via_edge, left),
DirectionModifier::SlightLeft}; DirectionModifier::SlightLeft};
} }
else else
{ {
// FIXME this should possibly know aboat the actual roads? // FIXME this should possibly know about the actual roads?
left.turn.instruction = getInstructionForObvious(4, via_edge, left); // here we don't know about the intersection size. To be on the save side, we declare it
// as complex (at least size 4)
left.turn.instruction = getInstructionForObvious(4, via_edge, false, left);
right.turn.instruction = {findBasicTurnType(via_edge, right), right.turn.instruction = {findBasicTurnType(via_edge, right),
DirectionModifier::SlightRight}; DirectionModifier::SlightRight};
} }
@ -1288,10 +1367,29 @@ TurnAnalysis::handleComplexTurn(const EdgeID via_edge,
} }
} }
// check whether the obvious choice is actually a through street
const auto isThroughStreet = [&intersection, this](const std::size_t index) {
if (node_based_graph.GetEdgeData(intersection[index].turn.eid).name_id == INVALID_NAME_ID)
return false;
for (const auto &road : intersection)
{
// a through street cannot start at our own position
if (road.turn.angle < std::numeric_limits<double>::epsilon())
continue;
if (angularDeviation(road.turn.angle, intersection[index].turn.angle) >
(STRAIGHT_ANGLE - NARROW_TURN_ANGLE) &&
node_based_graph.GetEdgeData(road.turn.eid).name_id ==
node_based_graph.GetEdgeData(intersection[index].turn.eid).name_id)
return true;
}
return false;
};
if (obvious_index != 0) if (obvious_index != 0)
{ {
intersection[obvious_index].turn.instruction = intersection[obvious_index].turn.instruction =
getInstructionForObvious(intersection.size(), via_edge, intersection[obvious_index]); getInstructionForObvious(intersection.size(), via_edge, isThroughStreet(obvious_index),
intersection[obvious_index]);
// assign left/right turns // assign left/right turns
intersection = assignLeftTurns(via_edge, std::move(intersection), obvious_index + 1); intersection = assignLeftTurns(via_edge, std::move(intersection), obvious_index + 1);
@ -1312,14 +1410,14 @@ TurnAnalysis::handleComplexTurn(const EdgeID via_edge,
else if (getPriority(left_class) > getPriority(right_class)) else if (getPriority(left_class) > getPriority(right_class))
{ {
right.turn.instruction = right.turn.instruction =
getInstructionForObvious(intersection.size(), via_edge, right); getInstructionForObvious(intersection.size(), via_edge, false, right);
left.turn.instruction = {findBasicTurnType(via_edge, left), left.turn.instruction = {findBasicTurnType(via_edge, left),
DirectionModifier::SlightLeft}; DirectionModifier::SlightLeft};
} }
else else
{ {
left.turn.instruction = left.turn.instruction =
getInstructionForObvious(intersection.size(), via_edge, left); getInstructionForObvious(intersection.size(), via_edge, false, left);
right.turn.instruction = {findBasicTurnType(via_edge, right), right.turn.instruction = {findBasicTurnType(via_edge, right),
DirectionModifier::SlightRight}; DirectionModifier::SlightRight};
} }
@ -1489,8 +1587,7 @@ std::vector<ConnectedRoad> TurnAnalysis::getConnectedRoads(const NodeID from_nod
{TurnOperation{via_eid, 0., {TurnType::Invalid, DirectionModifier::UTurn}}, false}); {TurnOperation{via_eid, 0., {TurnType::Invalid, DirectionModifier::UTurn}}, false});
} }
const auto ByAngle = [](const ConnectedRoad &first, const ConnectedRoad second) const auto ByAngle = [](const ConnectedRoad &first, const ConnectedRoad second) {
{
return first.turn.angle < second.turn.angle; return first.turn.angle < second.turn.angle;
}; };
std::sort(std::begin(intersection), std::end(intersection), ByAngle); std::sort(std::begin(intersection), std::end(intersection), ByAngle);
@ -1527,13 +1624,11 @@ std::vector<ConnectedRoad> TurnAnalysis::getConnectedRoads(const NodeID from_nod
std::vector<ConnectedRoad> std::vector<ConnectedRoad>
TurnAnalysis::mergeSegregatedRoads(std::vector<ConnectedRoad> intersection) const TurnAnalysis::mergeSegregatedRoads(std::vector<ConnectedRoad> intersection) const
{ {
const auto getRight = [&](std::size_t index) const auto getRight = [&](std::size_t index) {
{
return (index + intersection.size() - 1) % intersection.size(); return (index + intersection.size() - 1) % intersection.size();
}; };
const auto mergable = [&](std::size_t first, std::size_t second) -> bool const auto mergable = [&](std::size_t first, std::size_t second) -> bool {
{
const auto &first_data = node_based_graph.GetEdgeData(intersection[first].turn.eid); const auto &first_data = node_based_graph.GetEdgeData(intersection[first].turn.eid);
const auto &second_data = node_based_graph.GetEdgeData(intersection[second].turn.eid); const auto &second_data = node_based_graph.GetEdgeData(intersection[second].turn.eid);
@ -1547,8 +1642,8 @@ TurnAnalysis::mergeSegregatedRoads(std::vector<ConnectedRoad> intersection) cons
first_data.reversed != second_data.reversed; first_data.reversed != second_data.reversed;
}; };
const auto merge = [](const ConnectedRoad &first, const ConnectedRoad &second) -> ConnectedRoad const auto merge = [](const ConnectedRoad &first,
{ const ConnectedRoad &second) -> ConnectedRoad {
if (!first.entry_allowed) if (!first.entry_allowed)
{ {
ConnectedRoad result = second; ConnectedRoad result = second;
@ -1581,7 +1676,6 @@ TurnAnalysis::mergeSegregatedRoads(std::vector<ConnectedRoad> intersection) cons
// these result in an adjustment of all other angles // these result in an adjustment of all other angles
if (mergable(0, intersection.size() - 1)) if (mergable(0, intersection.size() - 1))
{ {
// std::cout << "First merge" << std::endl;
const double correction_factor = const double correction_factor =
(360 - intersection[intersection.size() - 1].turn.angle) / 2; (360 - intersection[intersection.size() - 1].turn.angle) / 2;
for (std::size_t i = 1; i + 1 < intersection.size(); ++i) for (std::size_t i = 1; i + 1 < intersection.size(); ++i)
@ -1592,7 +1686,6 @@ TurnAnalysis::mergeSegregatedRoads(std::vector<ConnectedRoad> intersection) cons
} }
else if (mergable(0, 1)) else if (mergable(0, 1))
{ {
// std::cout << "First merge" << std::endl;
const double correction_factor = (intersection[1].turn.angle) / 2; const double correction_factor = (intersection[1].turn.angle) / 2;
for (std::size_t i = 2; i < intersection.size(); ++i) for (std::size_t i = 2; i < intersection.size(); ++i)
intersection[i].turn.angle += correction_factor; intersection[i].turn.angle += correction_factor;
@ -1614,8 +1707,7 @@ TurnAnalysis::mergeSegregatedRoads(std::vector<ConnectedRoad> intersection) cons
} }
} }
const auto ByAngle = [](const ConnectedRoad &first, const ConnectedRoad second) const auto ByAngle = [](const ConnectedRoad &first, const ConnectedRoad second) {
{
return first.turn.angle < second.turn.angle; return first.turn.angle < second.turn.angle;
}; };
std::sort(std::begin(intersection), std::end(intersection), ByAngle); std::sort(std::begin(intersection), std::end(intersection), ByAngle);
@ -1640,7 +1732,7 @@ void TurnAnalysis::assignFork(const EdgeID via_edge,
{ {
if (low_priority_right && !low_priority_left) if (low_priority_right && !low_priority_left)
{ {
left.turn.instruction = getInstructionForObvious(3, via_edge, left); left.turn.instruction = getInstructionForObvious(3, via_edge, false, left);
right.turn.instruction = {findBasicTurnType(via_edge, right), right.turn.instruction = {findBasicTurnType(via_edge, right),
DirectionModifier::SlightRight}; DirectionModifier::SlightRight};
} }
@ -1683,7 +1775,7 @@ void TurnAnalysis::assignFork(const EdgeID via_edge,
{ {
left.turn.instruction = {findBasicTurnType(via_edge, left), left.turn.instruction = {findBasicTurnType(via_edge, left),
DirectionModifier::SlightLeft}; DirectionModifier::SlightLeft};
right.turn.instruction = getInstructionForObvious(3, via_edge, right); right.turn.instruction = getInstructionForObvious(3, via_edge, false, right);
} }
else else
{ {
@ -1887,10 +1979,24 @@ TurnAnalysis::findFork(const std::vector<ConnectedRoad> &intersection) const
best = i; best = i;
} }
} }
if (best_deviation <= NARROW_TURN_ANGLE) if (best_deviation <= NARROW_TURN_ANGLE)
{ {
std::size_t left = best, right = best; std::size_t left = best, right = best;
if (intersection[left].turn.angle >= 180)
{
// due to best > 1, we can safely decrement right
--right;
if (angularDeviation(intersection[right].turn.angle, STRAIGHT_ANGLE) >
NARROW_TURN_ANGLE)
return std::make_pair(std::size_t{0}, std::size_t{0});
}
else
{
++left;
if (left >= intersection.size() ||
angularDeviation(intersection[left].turn.angle, STRAIGHT_ANGLE) > NARROW_TURN_ANGLE)
return std::make_pair(std::size_t{0}, std::size_t{0});
}
while (left + 1 < intersection.size() && while (left + 1 < intersection.size() &&
angularDeviation(intersection[left].turn.angle, intersection[left + 1].turn.angle) < angularDeviation(intersection[left].turn.angle, intersection[left + 1].turn.angle) <
NARROW_TURN_ANGLE) NARROW_TURN_ANGLE)
@ -1909,7 +2015,7 @@ TurnAnalysis::findFork(const std::vector<ConnectedRoad> &intersection) const
2 * NARROW_TURN_ANGLE) 2 * NARROW_TURN_ANGLE)
return std::make_pair(right, left); return std::make_pair(right, left);
} }
return std::make_pair(0llu, 0llu); return std::make_pair(std::size_t{0}, std::size_t{0});
} }
// Can only assign three turns // Can only assign three turns
@ -1917,8 +2023,7 @@ std::vector<ConnectedRoad> TurnAnalysis::assignLeftTurns(const EdgeID via_edge,
std::vector<ConnectedRoad> intersection, std::vector<ConnectedRoad> intersection,
const std::size_t starting_at) const const std::size_t starting_at) const
{ {
const auto count_valid = [&intersection, starting_at]() const auto count_valid = [&intersection, starting_at]() {
{
std::size_t count = 0; std::size_t count = 0;
for (std::size_t i = starting_at; i < intersection.size(); ++i) for (std::size_t i = starting_at; i < intersection.size(); ++i)
if (intersection[i].entry_allowed) if (intersection[i].entry_allowed)
@ -1990,7 +2095,7 @@ std::vector<ConnectedRoad> TurnAnalysis::assignLeftTurns(const EdgeID via_edge,
findBasicTurnType(via_edge, intersection[starting_at + 1]), second_direction}; findBasicTurnType(via_edge, intersection[starting_at + 1]), second_direction};
if (intersection[starting_at + 2].entry_allowed) if (intersection[starting_at + 2].entry_allowed)
intersection[starting_at + 2].turn.instruction = { intersection[starting_at + 2].turn.instruction = {
findBasicTurnType(via_edge, intersection[starting_at + 2]), second_direction}; findBasicTurnType(via_edge, intersection[starting_at + 2]), third_direction};
} }
else if (2 >= (intersection[starting_at].entry_allowed + else if (2 >= (intersection[starting_at].entry_allowed +
intersection[starting_at + 1].entry_allowed + intersection[starting_at + 1].entry_allowed +
@ -2187,8 +2292,7 @@ std::vector<ConnectedRoad> TurnAnalysis::assignRightTurns(const EdgeID via_edge,
const std::size_t up_to) const const std::size_t up_to) const
{ {
BOOST_ASSERT(up_to <= intersection.size()); BOOST_ASSERT(up_to <= intersection.size());
const auto count_valid = [&intersection, up_to]() const auto count_valid = [&intersection, up_to]() {
{
std::size_t count = 0; std::size_t count = 0;
for (std::size_t i = 1; i < up_to; ++i) for (std::size_t i = 1; i < up_to; ++i)
if (intersection[i].entry_allowed) if (intersection[i].entry_allowed)

View File

@ -122,8 +122,9 @@ double perpendicularDistance(const Coordinate segment_source,
BOOST_ASSERT(query_location.IsValid()); BOOST_ASSERT(query_location.IsValid());
FloatCoordinate projected_nearest; FloatCoordinate projected_nearest;
std::tie(ratio, projected_nearest) = std::tie(ratio, projected_nearest) = projectPointOnSegment(mercator::fromWGS84(segment_source),
projectPointOnSegment(mercator::fromWGS84(segment_source), mercator::fromWGS84(segment_target), mercator::fromWGS84(query_location)); mercator::fromWGS84(segment_target),
mercator::fromWGS84(query_location));
nearest_location = mercator::toWGS84(projected_nearest); nearest_location = mercator::toWGS84(projected_nearest);
const double approximate_distance = greatCircleDistance(query_location, nearest_location); const double approximate_distance = greatCircleDistance(query_location, nearest_location);
@ -215,7 +216,9 @@ circleCenter(const Coordinate C1, const Coordinate C2, const Coordinate C3)
// free after http://paulbourke.net/geometry/circlesphere/ // free after http://paulbourke.net/geometry/circlesphere/
// require three distinct points // require three distinct points
if (C1 == C2 || C2 == C3 || C1 == C3) if (C1 == C2 || C2 == C3 || C1 == C3)
{
return boost::none; return boost::none;
}
// define line through c1, c2 and c2,c3 // define line through c1, c2 and c2,c3
const double C2C1_lat = static_cast<double>(toFloating(C2.lat - C1.lat)); // yDelta_a const double C2C1_lat = static_cast<double>(toFloating(C2.lat - C1.lat)); // yDelta_a
@ -255,7 +258,7 @@ circleCenter(const Coordinate C1, const Coordinate C2, const Coordinate C3)
const double C2C1_slope = C2C1_lat / C2C1_lon; const double C2C1_slope = C2C1_lat / C2C1_lon;
const double C3C2_slope = C3C2_lat / C3C2_lon; const double C3C2_slope = C3C2_lat / C3C2_lon;
//can this ever happen? // can this ever happen?
if (std::abs(C2C1_slope - C3C2_slope) < std::numeric_limits<double>::epsilon()) if (std::abs(C2C1_slope - C3C2_slope) < std::numeric_limits<double>::epsilon())
return boost::none; return boost::none;
@ -356,12 +359,14 @@ double degreeToPixel(FloatLatitude lat, unsigned zoom)
FloatCoordinate fromWGS84(const FloatCoordinate &wgs84_coordinate) FloatCoordinate fromWGS84(const FloatCoordinate &wgs84_coordinate)
{ {
return {wgs84_coordinate.lon, FloatLatitude{coordinate_calculation::mercator::latToY(wgs84_coordinate.lat)}}; return {wgs84_coordinate.lon,
FloatLatitude{coordinate_calculation::mercator::latToY(wgs84_coordinate.lat)}};
} }
FloatCoordinate toWGS84(const FloatCoordinate &mercator_coordinate) FloatCoordinate toWGS84(const FloatCoordinate &mercator_coordinate)
{ {
return {mercator_coordinate.lon, coordinate_calculation::mercator::yToLat(static_cast<double>(mercator_coordinate.lat))}; return {mercator_coordinate.lon,
coordinate_calculation::mercator::yToLat(static_cast<double>(mercator_coordinate.lat))};
} }
// Converts a WMS tile coordinate (z,x,y) into a wgs bounding box // Converts a WMS tile coordinate (z,x,y) into a wgs bounding box

View File

@ -1,10 +1,10 @@
#include "util/exception.hpp"
#include "util/name_table.hpp" #include "util/name_table.hpp"
#include "util/simple_logger.hpp" #include "util/simple_logger.hpp"
#include "util/exception.hpp"
#include <algorithm> #include <algorithm>
#include <limits>
#include <fstream> #include <fstream>
#include <limits>
#include <boost/filesystem/fstream.hpp> #include <boost/filesystem/fstream.hpp>
@ -17,27 +17,30 @@ NameTable::NameTable(const std::string &filename)
{ {
boost::filesystem::ifstream name_stream(filename, std::ios::binary); boost::filesystem::ifstream name_stream(filename, std::ios::binary);
if( !name_stream ) if (!name_stream)
throw exception("Failed to open " + filename + " for reading."); throw exception("Failed to open " + filename + " for reading.");
name_stream >> m_name_table; name_stream >> m_name_table;
unsigned number_of_chars = 0; unsigned number_of_chars = 0;
name_stream.read(reinterpret_cast<char *>(&number_of_chars), sizeof(number_of_chars)); name_stream.read(reinterpret_cast<char *>(&number_of_chars), sizeof(number_of_chars));
if( !name_stream ) if (!name_stream)
throw exception("Encountered invalid file, failed to read number of contained chars"); throw exception("Encountered invalid file, failed to read number of contained chars");
BOOST_ASSERT_MSG(0 != number_of_chars, "name file broken");
m_names_char_list.resize(number_of_chars + 1); //+1 gives sentinel element m_names_char_list.resize(number_of_chars + 1); //+1 gives sentinel element
name_stream.read(reinterpret_cast<char *>(&m_names_char_list[0]), m_names_char_list.back() = 0;
number_of_chars * sizeof(m_names_char_list[0])); if (number_of_chars > 0)
if( !name_stream ) {
throw exception("Failed to read " + std::to_string(number_of_chars) + " characters from file."); name_stream.read(reinterpret_cast<char *>(&m_names_char_list[0]),
number_of_chars * sizeof(m_names_char_list[0]));
if (0 == m_names_char_list.size()) }
else
{ {
util::SimpleLogger().Write(logWARNING) << "list of street names is empty"; util::SimpleLogger().Write(logWARNING) << "list of street names is empty";
} }
if (!name_stream)
throw exception("Failed to read " + std::to_string(number_of_chars) +
" characters from file.");
} }
std::string NameTable::GetNameForID(const unsigned name_id) const std::string NameTable::GetNameForID(const unsigned name_id) const