Skip to content

Commit 5531cac

Browse files
authored
Support maneuver relations (#4676)
1 parent 1aed135 commit 5531cac

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1474
-89
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# UNRELEASED
22
- Changes from 5.15.1:
33
- Guidance
4+
- ADDED #4676: Support for maneuver override relation, allowing data-driven overrides for turn-by-turn instructions [#4676](https://github.com/Project-OSRM/osrm-backend/pull/4676)
45
- CHANGED #4830: Announce reference change if names are empty
56
- CHANGED #4835: MAXIMAL_ALLOWED_SEPARATION_WIDTH increased to 12 meters
67
- Profile:

features/car/restrictions.feature

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1061,3 +1061,28 @@ Feature: Car - Turn restrictions
10611061
When I route I should get
10621062
| from | to | route |
10631063
| a | d | ab,bc,bc,bge,de,de |
1064+
1065+
1066+
Scenario: Ambiguous ways
1067+
Given the node map
1068+
"""
1069+
x---a----b-----c---z
1070+
|
1071+
d
1072+
"""
1073+
1074+
And the ways
1075+
| nodes |
1076+
| abc |
1077+
| bd |
1078+
| xa |
1079+
| cz |
1080+
1081+
And the relations
1082+
| type | way:from | way:to | node:via | restriction |
1083+
| restriction | bd | abc | b | no_left_turn |
1084+
1085+
When I route I should get
1086+
| from | to | route |
1087+
| d | x | bd,abc,xa,xa |
1088+
| d | z | bd,abc,cz,cz |
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
# The route results with #original are what the result should be if the maneuver tag is removed
2+
@routing @guidance @maneuver
3+
Feature: Maneuver tag support
4+
5+
Background:
6+
Given the profile "car"
7+
Given a grid size of 5 meters
8+
9+
Scenario: simple override #1
10+
Given the node map
11+
"""
12+
a--b---c----d---e
13+
|
14+
g
15+
|
16+
h------i--------j
17+
"""
18+
And the ways
19+
| nodes | name | oneway |
20+
| abc | A Street | no |
21+
| cde | B Street | no |
22+
| cgi | C Street | no |
23+
| hij | J Street | no |
24+
25+
And the relations
26+
| type | way:from | node:via | way:to | maneuver | direction |
27+
| maneuver | abc | c | cgi | turn | sharp_right |
28+
| maneuver | hij | i | cde | turn | sharp_left |
29+
| maneuver | abc | c | cde | turn | slight_left |
30+
31+
When I route I should get
32+
| waypoints | route | turns |
33+
# Testing directly connected from/to
34+
| a,j | A Street,C Street,J Street,J Street | depart,turn sharp right,turn left,arrive |
35+
| b,g | A Street,C Street,C Street | depart,turn sharp right,arrive |
36+
# Testing re-awakening suppressed turns
37+
| a,e | A Street,B Street,B Street | depart,turn slight left,arrive |
38+
39+
Scenario: single via-way
40+
Given the node map
41+
""""
42+
a--b---c----d---e
43+
|
44+
g
45+
|
46+
h------i--------j
47+
"""
48+
49+
And the ways
50+
| nodes | name | oneway |
51+
| abc | A Street | no |
52+
| cde | B Street | no |
53+
| cgi | C Street | no |
54+
| hi | J Street | no |
55+
| ij | J Street | no |
56+
57+
And the relations
58+
| type | way:from | way:via | way:to | node:via | maneuver | direction |
59+
| maneuver | abc | cgi | ij | c | turn | sharp_right |
60+
61+
When I route I should get
62+
| waypoints | route | turns |
63+
| a,j | A Street,C Street,J Street,J Street | depart,turn sharp right,turn left,arrive |
64+
65+
66+
Scenario: multiple via-way
67+
Given the node map
68+
""""
69+
a--b---c----d---e
70+
|
71+
g-----k
72+
|
73+
h------i--------j
74+
"""
75+
76+
And the ways
77+
| nodes | name | oneway |
78+
| abc | A Street | no |
79+
| cde | B Street | no |
80+
| cg | C Street | no |
81+
| gi | C Street | no |
82+
| hi | J Street | no |
83+
| ij | J Street | no |
84+
| gk | G Street | no |
85+
86+
And the relations
87+
| type | way:from | way:via | way:via | way:to | node:via | maneuver | direction |
88+
| maneuver | abc | cg | gi | ij | c | turn | sharp_right |
89+
90+
When I route I should get
91+
| waypoints | route | turns |
92+
| a,j | A Street,C Street,J Street,J Street | depart,turn sharp right,end of road left,arrive |
93+
94+
95+
Scenario: Use maneuver tag to announce a particular turn type
96+
Given the node map
97+
"""
98+
f
99+
*
100+
*
101+
*
102+
*
103+
*
104+
*
105+
*
106+
*
107+
*
108+
t. .. * h
109+
.. ....m** *
110+
/ * *
111+
/ * * *
112+
/
113+
/
114+
|
115+
|
116+
\
117+
\
118+
o
119+
"""
120+
121+
And the ways
122+
| nodes | name | oneway | highway |
123+
| fm | CA-120 | no | secondary |
124+
| mh | CA-120 | no | secondary |
125+
| mt | Priest Rd | no | unclassified |
126+
| mo | | no | service |
127+
128+
And the relations
129+
| type | way:from | node:via | way:to | maneuver | direction |
130+
| maneuver | mh | m | mt | turn | left |
131+
132+
When I route I should get
133+
| waypoints | route | turns |
134+
| h,t | CA-120,Priest Rd,Priest Rd | depart,turn left,arrive |
135+
#original | h,t | CA-120,Priest Rd,Priest Rd | depart,turn straight,arrive |
136+
137+
Scenario: Use maneuver tag to announce lane guidance
138+
Given a grid size of 10 meters
139+
Given the node map
140+
"""
141+
ad
142+
/ \
143+
/ \
144+
/ \
145+
| |
146+
| |
147+
| |
148+
b-----c------e
149+
| |
150+
| |
151+
| |
152+
| |
153+
r w
154+
"""
155+
156+
And the ways
157+
| nodes | name | oneway | highway |
158+
| ab | Marsh Rd | yes | secondary |
159+
| br | Marsh Rd | yes | secondary |
160+
| cd | Marsh Rd | yes | secondary |
161+
| cw | Marsh Rd | yes | secondary |
162+
| bc | service | no | service |
163+
| ce | service | no | service |
164+
165+
And the relations
166+
| type | way:from | node:via | way:via | way:to | maneuver |
167+
| maneuver | ab | c | bc | cd | uturn |
168+
| maneuver | ab | b | bc | cd | suppress |
169+
170+
When I route I should get
171+
| waypoints | route | turns |
172+
| a,d | Marsh Rd,Marsh Rd,Marsh Rd | depart,turn uturn,arrive |
173+
#original | a,d | Marsh Rd,service,Marsh Rd,Marsh Rd | depart,turn left,turn left,arrive |
174+
175+
Scenario: Use maneuver tag to suppress a turn
176+
Given the node map
177+
"""
178+
c
179+
|
180+
|
181+
v---y----------z
182+
|
183+
n---p----------k
184+
|\
185+
| \
186+
b t
187+
"""
188+
189+
And the ways
190+
| nodes | name | oneway | highway |
191+
| zy | NY Ave | yes | primary |
192+
| yv | NY Ave | yes | primary |
193+
| np | NY Ave | yes | primary |
194+
| pk | NY Ave | yes | primary |
195+
| cp | 4th St | no | tertiary |
196+
| yp | | no | motorway_link |
197+
| pb | 4th St | no | primary |
198+
| pt | 395 | no | primary |
199+
200+
And the relations
201+
| type | way:from | node:via | way:via | way:to | maneuver |
202+
| maneuver | zy | p | yp | pt | suppress |
203+
204+
When I route I should get
205+
| waypoints | route | turns |
206+
| z,t | NY Ave,395,395 | depart,on ramp left,arrive |
207+
#original | z,t | NY Ave,,395,395 | depart,on ramp left,fork slight left,arrive |
208+

features/step_definitions/data.js

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -185,40 +185,43 @@ module.exports = function () {
185185

186186
let q = d3.queue();
187187

188-
let addRelation = (row, cb) => {
188+
let addRelation = (headers, row, cb) => {
189189
let relation = new OSM.Relation(this.makeOSMId(), this.OSM_USER, this.OSM_TIMESTAMP, this.OSM_UID);
190190

191191

192192
var name = null;
193-
for (let key in row) {
193+
for (let index in row) {
194+
195+
var key = headers[index];
196+
var value = row[index];
194197
let isNode = key.match(/^node:?(.*)/),
195198
isWay = key.match(/^way:?(.*)/),
196199
isRelation = key.match(/^relation:?(.*)/),
197200
isColonSeparated = key.match(/^(.*):(.*)/);
198201
if (isNode) {
199-
row[key].split(',').map(function(v) { return v.trim(); }).forEach((nodeName) => {
202+
value.split(',').map(function(v) { return v.trim(); }).forEach((nodeName) => {
200203
if (nodeName.length !== 1) throw new Error(util.format('*** invalid relation node member "%s"', nodeName));
201204
let node = this.findNodeByName(nodeName);
202205
if (!node) throw new Error(util.format('*** unknown relation node member "%s"', nodeName));
203206
relation.addMember('node', node.id, isNode[1]);
204207
});
205208
} else if (isWay) {
206-
row[key].split(',').map(function(v) { return v.trim(); }).forEach((wayName) => {
209+
value.split(',').map(function(v) { return v.trim(); }).forEach((wayName) => {
207210
let way = this.findWayByName(wayName);
208211
if (!way) throw new Error(util.format('*** unknown relation way member "%s"', wayName));
209212
relation.addMember('way', way.id, isWay[1]);
210213
});
211214
} else if (isRelation) {
212-
row[key].split(',').map(function(v) { return v.trim(); }).forEach((relName) => {
215+
value.split(',').map(function(v) { return v.trim(); }).forEach((relName) => {
213216
let otherrelation = this.findRelationByName(relName);
214217
if (!otherrelation) throw new Error(util.format('*** unknown relation relation member "%s"', relName));
215218
relation.addMember('relation', otherrelation.id, isRelation[1]);
216219
});
217220
} else if (isColonSeparated && isColonSeparated[1] !== 'restriction') {
218221
throw new Error(util.format('*** unknown relation member type "%s:%s", must be either "node" or "way"', isColonSeparated[1], isColonSeparated[2]));
219222
} else {
220-
relation.addTag(key, row[key]);
221-
if (key.match(/name/)) name = row[key];
223+
relation.addTag(key, value);
224+
if (key.match(/name/)) name = value;
222225
}
223226
}
224227
relation.uid = this.OSM_UID;
@@ -233,7 +236,8 @@ module.exports = function () {
233236
cb();
234237
};
235238

236-
table.hashes().forEach((row) => q.defer(addRelation, row));
239+
var headers = table.raw()[0];
240+
table.rows().forEach((row) => q.defer(addRelation, headers, row));
237241

238242
q.awaitAll(callback);
239243
});

include/engine/api/route_api.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#ifndef ENGINE_API_ROUTE_HPP
22
#define ENGINE_API_ROUTE_HPP
33

4+
#include "extractor/maneuver_override.hpp"
45
#include "engine/api/base_api.hpp"
56
#include "engine/api/json_factory.hpp"
67
#include "engine/api/route_parameters.hpp"
@@ -19,6 +20,8 @@
1920

2021
#include "engine/internal_route_result.hpp"
2122

23+
#include "guidance/turn_instruction.hpp"
24+
2225
#include "util/coordinate.hpp"
2326
#include "util/integer_range.hpp"
2427
#include "util/json_util.hpp"
@@ -130,6 +133,7 @@ class RouteAPI : public BaseAPI
130133
reversed_target,
131134
parameters.steps);
132135

136+
util::Log(logDEBUG) << "Assembling steps " << std::endl;
133137
if (parameters.steps)
134138
{
135139
auto steps = guidance::assembleSteps(BaseAPI::facade,
@@ -140,6 +144,10 @@ class RouteAPI : public BaseAPI
140144
reversed_source,
141145
reversed_target);
142146

147+
// Apply maneuver overrides before any other post
148+
// processing is performed
149+
guidance::applyOverrides(BaseAPI::facade, steps, leg_geometry);
150+
143151
/* Perform step-based post-processing.
144152
*
145153
* Using post-processing on basis of route-steps for a single leg at a time

0 commit comments

Comments
 (0)