Skip to content

Commit bba4765

Browse files
Initial commit
1 parent f5e9241 commit bba4765

33 files changed

+2684
-155
lines changed

docs/areas.md

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
# Areas
2+
3+
This OSRM feature provides routing through areas. The area type is configurable.
4+
5+
## Routing over pedestrian areas
6+
7+
Pedestrian areas in OSM are either closed ways or multipolygon relations. Currently OSRM
8+
routes along the perimeter of a closed way area. It does not route over multipolygon
9+
areas at all.
10+
11+
This feature routes over the inside of the area. It does so by "meshing" the area, ie.
12+
by creating virtual ways between every two entry points of the area. These new ways
13+
follow lines of sight, they never go through obstacles in the area.
14+
15+
This feature is opt-in: To enable it you must define a `process_relation` function in
16+
your profile and return it like this:
17+
18+
```lua
19+
return {
20+
setup = setup,
21+
process_way = process_way,
22+
process_node = process_node,
23+
process_turn = process_turn,
24+
process_relation = process_relation
25+
}
26+
```
27+
28+
You must also keep multipolygon relations, so that you can use the name on the relation
29+
for turn directions. (Remember that the ways in the relation are untagged.) In your
30+
profile's setup function add or edit the `relation_types` sequence to include the type
31+
"multipolygon":
32+
33+
```lua
34+
function setup()
35+
...
36+
return {
37+
...
38+
relation_types = Sequence {
39+
"multipolygon"
40+
}
41+
...
42+
}
43+
end
44+
```
45+
46+
### process_relation(profile, relation, relations)
47+
48+
The `process_relation` function is called for every relation in the input file. If you
49+
want a relation to be meshed, call `area_manager:relation(relation)`.
50+
51+
Example of a process_relation function:
52+
53+
```lua
54+
function process_relation(profile, relation, relations)
55+
type = relation:get_value_by_key('type')
56+
highway = relation:get_value_by_key('highway')
57+
if type == 'multipolygon' and highway == 'pedestrian' then
58+
-- register the relation
59+
area_manager:relation(relation)
60+
end
61+
end
62+
```
63+
64+
### process_way(profile, way, result, relations)
65+
66+
The `process_way` function is called for every way in the input file. If you want a
67+
closed way to be meshed, call `area_manager:way(way)`. (Note that open ways cannot be
68+
meshed and will be ignored.)
69+
70+
Multipolygons need some support too. Since the member ways of a multipolygon relation
71+
are as a rule untagged, you have to copy at least the defining tag (and maybe the name)
72+
from the relation to the way. OSRM discards untagged ways.
73+
74+
Example of a process_way function:
75+
76+
```lua
77+
function process_way(profile, way, result, relations)
78+
...
79+
if way:get_value_by_key('highway') == 'pedestrian' then
80+
-- register the way
81+
area_manager:way(way)
82+
end
83+
84+
for _, rel_id in pairs(area_manager:get_relations(way)) do
85+
-- if this way is a member of a registered relation
86+
-- we have to set at least one defining tag
87+
local rel = relations:relation(rel_id)
88+
data.highway = rel:get_value_by_key('highway')
89+
end
90+
...
91+
end
92+
```
93+
94+
### area_manager
95+
96+
A global user type.
97+
98+
#### area_manager:relation(relation)
99+
Call this function inside `process_relation()` to register a relation for meshing. The
100+
relation must be a multipolygon relation.
101+
102+
Argument | Type | Notes
103+
---------|-------------|-----------------------------------------------------
104+
relation | OSMRelation | The same relation as passed into `process_relation`.
105+
106+
#### area_manager:way(way)
107+
Call this function inside `process_way()` to register a way for meshing. The way must be
108+
closed.
109+
110+
Argument | Type | Notes
111+
---------|----------|-------------------------------------------
112+
way | OSMWay | The same way as passed into `process_way`.
113+
114+
#### area_manager:get_relations(way)
115+
Call this function inside `process_way()`. If this way is a member of a relation that
116+
was registered for meshing, that relation will be returned. Since the member ways of a
117+
multipolygon relation are as a rule untagged, you have to copy at least the defining tag
118+
(and maybe the name) from the relation to the way. OSRM discards untagged ways.
119+
120+
Argument | Type | Notes
121+
---------|----------|-------------------------------------------
122+
way | OSMWay | The same way as passed into `process_way`.
123+
124+
Usage example:
125+
126+
```lua
127+
for _, rel_id in pairs(area_manager:get_relations(way)) do
128+
local rel = relations:relation(rel_id)
129+
data.highway = rel:get_value_by_key('highway')
130+
WayHandlers.names(profile, rel, result, data)
131+
end
132+
```

features/bicycle/alley.feature

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@ Feature: Bicycle - Route around alleys
2727
| cf | residential | |
2828

2929
When I route I should get
30-
| from | to | a:nodes | weight | # |
31-
| a | f | 1:2:3:6 | 196.2 | Avoids d,e,f |
32-
| a | e | 1:2:5 | 172.2 | Take the alley b,e if neccessary |
33-
| d | f | 4:1:2:3:6 | 248.4 | Avoids the alley d,e,f |
34-
30+
| from | to | a:nodes | weight | # |
31+
| a | f | abcf | 196.2 | Avoids d,e,f |
32+
| a | e | abe | 172.2 | Take the alley b,e if neccessary |
33+
| d | f | dabcf | 248.4 | Avoids the alley d,e,f |

features/car/traffic_light_penalties.feature

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -294,8 +294,8 @@ Feature: Car - Handle traffic lights
294294

295295
When I route I should get
296296
| from | to | route | speed | weights | time | distances | a:datasources | a:nodes | a:speed | a:duration | a:weight |
297-
| a | c | abc,abc | 60 km/h | 24.2,0 | 24.2s | 400m,0m | 1:0 | 1:2:3 | 18:18 | 11.1:11.1 | 11.1:11.1 |
298-
| c | a | abc,abc | 60 km/h | 24.2,0 | 24.2s | 400m,0m | 0:1 | 3:2:1 | 18:18 | 11.1:11.1 | 11.1:11.1 |
297+
| a | c | abc,abc | 60 km/h | 24.2,0 | 24.2s | 400m,0m | 1:0 | abc | 18:18 | 11.1:11.1 | 11.1:11.1 |
298+
| c | a | abc,abc | 60 km/h | 24.2,0 | 24.2s | 400m,0m | 0:1 | cba | 18:18 | 11.1:11.1 | 11.1:11.1 |
299299

300300

301301
@traffic
@@ -326,8 +326,8 @@ Feature: Car - Handle traffic lights
326326

327327
When I route I should get
328328
| from | to | route | speed | weights | time | distances | a:datasources | a:nodes | a:speed | a:duration | a:weight |
329-
| a | c | abc,abc | 60 km/h | 24.2,0 | 24.2s | 400m,0m | 1:0 | 1:2:3 | 18:18 | 11.1:11.1 | 11.1:11.1 |
330-
| c | a | abc,abc | 65 km/h | 22.2,0 | 22.2s | 400m,0m | 0:1 | 3:2:1 | 18:18 | 11.1:11.1 | 11.1:11.1 |
329+
| a | c | abc,abc | 60 km/h | 24.2,0 | 24.2s | 400m,0m | 1:0 | abc | 18:18 | 11.1:11.1 | 11.1:11.1 |
330+
| c | a | abc,abc | 65 km/h | 22.2,0 | 22.2s | 400m,0m | 0:1 | cba | 18:18 | 11.1:11.1 | 11.1:11.1 |
331331

332332

333333
@traffic
@@ -358,8 +358,8 @@ Feature: Car - Handle traffic lights
358358

359359
When I route I should get
360360
| from | to | route | speed | weights | time | distances | a:datasources | a:nodes | a:speed | a:duration | a:weight |
361-
| a | c | abc,abc | 65 km/h | 22.2,0 | 22.2s | 400m,0m | 1:0 | 1:2:3 | 18:18 | 11.1:11.1 | 11.1:11.1 |
362-
| c | a | abc,abc | 60 km/h | 24.2,0 | 24.2s | 400m,0m | 0:1 | 3:2:1 | 18:18 | 11.1:11.1 | 11.1:11.1 |
361+
| a | c | abc,abc | 65 km/h | 22.2,0 | 22.2s | 400m,0m | 1:0 | abc | 18:18 | 11.1:11.1 | 11.1:11.1 |
362+
| c | a | abc,abc | 60 km/h | 24.2,0 | 24.2s | 400m,0m | 0:1 | cba | 18:18 | 11.1:11.1 | 11.1:11.1 |
363363

364364

365365
Scenario: Car - Traffic signal straight direction with edge compression

features/foot/area_mesh.feature

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
@routing @foot @area
2+
Feature: Foot - Pedestrian areas
3+
4+
Background:
5+
Given the profile "foot_area"
6+
Given a grid size of 50 meters
7+
Given the extract extra arguments "--verbosity DEBUG"
8+
Given the query options
9+
| annotations | nodes |
10+
11+
Scenario: Foot - Route across a closed way area
12+
Given the node map
13+
"""
14+
e-a---b-f
15+
| |
16+
h-d---c-g
17+
"""
18+
19+
And the ways
20+
| nodes | highway | area |
21+
| abcda | pedestrian | yes |
22+
| ea | pedestrian | |
23+
| bf | pedestrian | |
24+
| hd | pedestrian | |
25+
| cg | pedestrian | |
26+
27+
When I route I should get
28+
| from | to | a:nodes |
29+
| e | g | eacg |
30+
| g | e | gcae |
31+
| h | f | hdbf |
32+
| f | h | fbdh |
33+
34+
Scenario: Foot - Route across a multipolygon area
35+
Given the node map
36+
"""
37+
e-a-------b-f
38+
| u-v |
39+
| x-w |
40+
h-d-------c-g
41+
"""
42+
43+
And the ways
44+
| nodes | highway |
45+
| abcda | (nil) |
46+
| uvwxu | (nil) |
47+
| ea | pedestrian |
48+
| bf | pedestrian |
49+
| hd | pedestrian |
50+
| cg | pedestrian |
51+
52+
And the relations
53+
| type | highway | way:outer | way:inner |
54+
| multipolygon | pedestrian | abcda | uvwxu |
55+
56+
When I route I should get
57+
| from | to | a:nodes |
58+
| e | g | eavcg |
59+
| g | e | gcvae |
60+
| f | h | fbwdh |
61+
| h | f | hdwbf |
62+
63+
Scenario: Foot - Route across a complex multipolygon area
64+
Given the node map
65+
"""
66+
g-a---------------b-h
67+
| z-y |
68+
| | | |
69+
l-f | | |
70+
| w-x v-u |
71+
| | | c-i
72+
| | | |
73+
| s-t |
74+
k-e---------------d-j
75+
"""
76+
77+
And the ways
78+
| nodes | highway |
79+
| abcdefa | (nil) |
80+
| zwxyz | (nil) |
81+
| vstuv | (nil) |
82+
| ag | pedestrian |
83+
| bh | pedestrian |
84+
| ci | pedestrian |
85+
| dj | pedestrian |
86+
| ek | pedestrian |
87+
| fl | pedestrian |
88+
89+
And the relations
90+
| type | highway | way:outer | way:inner |
91+
| multipolygon | pedestrian | abcdefa | vstuv,zwxyz |
92+
93+
When I route I should get
94+
| from | to | a:nodes | # |
95+
| g | h | gabh | |
96+
| g | i | gayuci | |
97+
| g | j | gaysdj | |
98+
| l | h | lfzybh | use existing segment zy |
99+
| l | i | lfwxvuci | use existing segments wx, vu |
100+
| l | j | lfwsdj | |
101+
| k | h | kebh | |
102+
| k | i | kestci | use existing segment st |
103+
| k | j | kedj | |

features/lib/osm.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ class DB {
8080
this.relations.forEach((r) => {
8181
var relation = xml.ele('relation', {
8282
id: r.id,
83+
version: 1,
8384
user: r.OSM_USER,
8485
timestamp: r.OSM_TIMESTAMP,
8586
uid: r.OSM_UID

features/support/data.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ module.exports = function () {
117117
var node = new OSM.Node(id, this.OSM_USER, this.OSM_TIMESTAMP, this.OSM_UID, lon, lat, {name: name});
118118
this.OSMDB.addNode(node);
119119
this.nameNodeHash[name] = node;
120+
this.idNodeHash[id] = node;
120121
};
121122

122123
this.addLocation = (name, lon, lat) => {
@@ -137,6 +138,16 @@ module.exports = function () {
137138
return fromNode;
138139
};
139140

141+
this.findNodeById = (id) => {
142+
return this.idNodeHash[id.toString()];
143+
};
144+
145+
this.nodeNameById = (id) => {
146+
const fromNode = this.findNodeById(id) || {};
147+
const tags = fromNode.tags || {};
148+
return tags.name || '?';
149+
};
150+
140151
// find a node based on an array containing lon/lat
141152
this.findNodeByLocation = (node_location) => {
142153
var searched_coordinate = new classes.Location(node_location[0],node_location[1]);
@@ -167,6 +178,7 @@ module.exports = function () {
167178
this.resetOSM = () => {
168179
this.OSMDB.clear();
169180
this.nameNodeHash = {};
181+
this.idNodeHash = {};
170182
this.locationHash = {};
171183
this.shortcutsHash = {};
172184
this.nameWayHash = {};

features/support/shared_steps.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,10 @@ module.exports = function () {
178178
if (annotation && !annotation[a_type])
179179
return cb(new Error('Annotation not found in response', a_type));
180180
got[k] = annotation && annotation[a_type] || '';
181+
// replaces node ids by their names: "0:1:2:3" -> "abcd"
182+
if (a_type == 'nodes') {
183+
got[k] = got[k].split(':').map(this.nodeNameById).join('');
184+
}
181185
} else if (k.match(/^am:/)) {
182186
let a_type = k.slice(3);
183187
if (metadata_whitelist.indexOf(a_type) == -1)

features/testbot/annotations.feature

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ Feature: Annotations
2323

2424
When I route I should get
2525
| from | to | route | a:speed | a:weight | a:nodes |
26-
| h | j | hk,jk,jk | 6.7:6.7 | 15:15 | 1:4:3 |
27-
| i | m | il,lm,lm | 6.7:6.7 | 15:15 | 2:5:6 |
28-
| j | m | jk,lm | 6.7:6.7:6.7 | 15:15:15 | 3:4:5:6 |
26+
| h | j | hk,jk,jk | 6.7:6.7 | 15:15 | hkj |
27+
| i | m | il,lm,lm | 6.7:6.7 | 15:15 | ilm |
28+
| j | m | jk,lm | 6.7:6.7:6.7 | 15:15:15 | jklm |
2929

3030

3131
Scenario: There should be different forward/reverse datasources
@@ -114,5 +114,5 @@ Feature: Annotations
114114
| bearings | 90,5;180,5 |
115115

116116
When I route I should get
117-
| from | to | route | a:speed | a:distance | a:duration | a:nodes |
118-
| a | c | abc,abc | 10:10 | 249.9876189:299.962882 | 25:30 | 1:2:3 |
117+
| from | to | route | a:speed | a:distance | a:duration | a:nodes |
118+
| a | c | abc,abc | 10:10 | 249.9876189:299.962882 | 25:30 | abc |

features/testbot/traffic_speeds.feature

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -136,13 +136,13 @@ Feature: Traffic - speeds
136136

137137
When I route I should get
138138
| from | to | route | speed | weights | a:datasources | a:speed | a:nodes|
139-
| a | b | fb,fb | 36 km/h | 328.9,0 | 0 | 10 | 6:2 |
140-
| a | c | fb,bc,bc | 30 km/h | 328.9,737.2,0 | 0:1 | 10:7.5 | 6:2:3 |
141-
| b | c | bc,bc | 27 km/h | 737.2,0 | 1 | 7.5 | 2:3 |
142-
| a | d | fb,df,df | 36 km/h | 139.8,486.8,0 | 0:0 | 10:10 | 2:6:4 |
143-
| d | c | dc,dc | 36 km/h | 955.4,0 | 0 | 10 | 4:3 |
144-
| g | b | fb,fb | 36 km/h | 164.4,0 | 0 | 10 | 6:2 |
145-
| a | g | fb,fb | 36 km/h | 164.5,0 | 0 | 10 | 6:2 |
139+
| a | b | fb,fb | 36 km/h | 328.9,0 | 0 | 10 | fb |
140+
| a | c | fb,bc,bc | 30 km/h | 328.9,737.2,0 | 0:1 | 10:7.5 | fbc |
141+
| b | c | bc,bc | 27 km/h | 737.2,0 | 1 | 7.5 | bc |
142+
| a | d | fb,df,df | 36 km/h | 139.8,486.8,0 | 0:0 | 10:10 | bfd |
143+
| d | c | dc,dc | 36 km/h | 955.4,0 | 0 | 10 | dc |
144+
| g | b | fb,fb | 36 km/h | 164.4,0 | 0 | 10 | fb |
145+
| a | g | fb,fb | 36 km/h | 164.5,0 | 0 | 10 | fb |
146146

147147

148148
Scenario: Verify that negative values cause an error, they're not valid at all

0 commit comments

Comments
 (0)