Making the turn function more flexible (#4789)
* set and store highway and access classification for the turn function * expose highway turn classification and access turn classification and speed to the lua profile turn function * expose whether connection road at turn is incoming or outgoing * add lua tests for exposed information to turn function * update docs about attributes in process_turn * add turn_classification info to docs * adding warning if uturn and intersection dont match * handle u turns that do not turn into intersection[0] * split OSM link generation in an accessible coordinate function
This commit is contained in:
parent
13bb997525
commit
61e06fcaba
@ -2,6 +2,7 @@
|
|||||||
- Changes from 5.15.0:
|
- Changes from 5.15.0:
|
||||||
- Profile:
|
- Profile:
|
||||||
- FIXED: `highway=service` will now be used for restricted access, `access=private` is still disabled for snapping.
|
- FIXED: `highway=service` will now be used for restricted access, `access=private` is still disabled for snapping.
|
||||||
|
- ADDED #4775: Exposes more information to the turn function, now being able to set turn weights with highway and access information of the turn as well as other roads at the intersection [#4775](https://github.com/Project-OSRM/osrm-backend/issues/4775)
|
||||||
|
|
||||||
# 5.15.0
|
# 5.15.0
|
||||||
- Changes from 5.14.3:
|
- Changes from 5.14.3:
|
||||||
|
107
docs/profiles.md
107
docs/profiles.md
@ -208,19 +208,100 @@ The `process_turn` function is called for every possible turn in the network. Ba
|
|||||||
|
|
||||||
The following attributes can be read and set on the result in `process_turn`:
|
The following attributes can be read and set on the result in `process_turn`:
|
||||||
|
|
||||||
Attribute | Read/write? | Type | Notes
|
Attribute | Read/write? | Type | Notes
|
||||||
---------------------|-------------|---------|------------------------------------------------------
|
--------------------- | ------------- | --------- | ------------------------------------------------------
|
||||||
angle | Read | Float | Angle of turn in degrees (`0-360`: `0`=u-turn, `180`=straight on)
|
angle | Read | Float | Angle of turn in degrees (`[-179, 180]`: `0`=straight, `180`=u turn, `+x`=x degrees to the right, `-x`= x degrees to the left)
|
||||||
number_of_roads | Read | Integer | Number of ways at the intersection of the turn
|
number_of_roads | Read | Integer | Number of ways at the intersection of the turn
|
||||||
is_u_turn | Read | Boolean | Is the turn a u-turn?
|
is_u_turn | Read | Boolean | Is the turn a u-turn?
|
||||||
has_traffic_light | Read | Boolean | Is a traffic light present at this turn?
|
has_traffic_light | Read | Boolean | Is a traffic light present at this turn?
|
||||||
source_restricted | Read | Boolean | Is it from a restricted access road? (See definition in `process_way`)
|
is_left_hand_driving | Read | Boolean | Is left-hand traffic?
|
||||||
target_restricted | Read | Boolean | Is it to a restricted access road? (See definition in `process_way`)
|
source_restricted | Read | Boolean | Is it from a restricted access road? (See definition in `process_way`)
|
||||||
is_left_hand_driving | Read | Boolean | Is left-hand traffic?
|
source_mode | Read | Enum | Travel mode before the turn. Defined in `include/extractor/travel_mode.hpp`
|
||||||
weight | Read/write | Float | Penalty to be applied for this turn (routing weight)
|
source_is_motorway | Read | Boolean | Is the source road a motorway?
|
||||||
duration | Read/write | Float | Penalty to be applied for this turn (duration in deciseconds)
|
source_is_link | Read | Boolean | Is the source road a link?
|
||||||
source_mode | Read | Enum | Travel mode before the turn. Defined in `include/extractor/travel_mode.hpp`
|
source_number_of_lanes | Read | Integer | How many lanes does the source road have? (default when not tagged: 0)
|
||||||
target_mode | Read | Enum | Travel mode after the turn. Defined in `include/extractor/travel_mode.hpp`
|
source_highway_turn_classification | Read | Integer | Classification based on highway tag defined by user during setup. (default when not set: 0, allowed classification values are: 0-15))
|
||||||
|
source_access_turn_classification | Read | Integer | Classification based on access tag defined by user during setup. (default when not set: 0, allowed classification values are: 0-15))
|
||||||
|
source_speed | Read | Integer | Speed on this source road in km/h
|
||||||
|
target_restricted | Read | Boolean | Is it from a restricted access road? (See definition in `process_way`)
|
||||||
|
target_mode | Read | Enum | Travel mode before the turn. Defined in `include/extractor/travel_mode.hpp`
|
||||||
|
target_is_motorway | Read | Boolean | Is the target road a motorway?
|
||||||
|
target_is_link | Read | Boolean | Is the target road a link?
|
||||||
|
target_number_of_lanes | Read | Integer | How many lanes does the target road have? (default when not tagged: 0)
|
||||||
|
target_highway_turn_classification | Read | Integer | Classification based on highway tag defined by user during setup. (default when not set: 0, allowed classification values are: 0-15))
|
||||||
|
target_access_turn_classification | Read | Integer | Classification based on access tag defined by user during setup. (default when not set: 0, allowed classification values are: 0-15))
|
||||||
|
target_speed | Read | Integer | Speed on this target road in km/h
|
||||||
|
roads_on_the_right | Read | Vector<ExtractionTurnLeg> | Vector with information about other roads on the right of the turn that are also connected at the intersection
|
||||||
|
roads_on_the_left | Read | Vector<ExtractionTurnLeg> | Vector with information about other roads on the left of the turn that are also connected at the intersection. If turn is a u turn, this is empty.
|
||||||
|
weight | Read/write | Float | Penalty to be applied for this turn (routing weight)
|
||||||
|
duration | Read/write | Float | Penalty to be applied for this turn (duration in deciseconds)
|
||||||
|
|
||||||
|
#### `roads_on_the_right` and `roads_on_the_left`
|
||||||
|
|
||||||
|
The information of `roads_on_the_right` and `roads_on_the_left` that can be read are as follows:
|
||||||
|
|
||||||
|
Attribute | Read/write? | Type | Notes
|
||||||
|
--------------------- | ------------- | --------- | ------------------------------------------------------
|
||||||
|
is_restricted | Read | Boolean | Is it a restricted access road? (See definition in `process_way`)
|
||||||
|
mode | Read | Enum | Travel mode before the turn. Defined in `include/extractor/travel_mode.hpp`
|
||||||
|
is_motorway | Read | Boolean | Is the road a motorway?
|
||||||
|
is_link | Read | Boolean | Is the road a link?
|
||||||
|
number_of_lanes | Read | Integer | How many lanes does the road have? (default when not tagged: 0)
|
||||||
|
highway_turn_classification | Read | Integer | Classification based on highway tag defined by user during setup. (default when not set: 0, allowed classification values are: 0-15)
|
||||||
|
access_turn_classification | Read | Integer | Classification based on access tag defined by user during setup. (default when not set: 0, allowed classification values are: 0-15)
|
||||||
|
speed | Read | Integer | Speed on this road in km/h
|
||||||
|
is_incoming | Read | Boolean | Is the road an incoming road of the intersection
|
||||||
|
is_outgoing | Read | Boolean | Is the road an outgoing road of the intersection
|
||||||
|
|
||||||
|
The order of the roads in `roads_on_the_right` and `roads_on_the_left` are *counter clockwise*. If the turn is a u turn, all other connected roads will be in `roads_on_the_right`.
|
||||||
|
|
||||||
|
**Example**
|
||||||
|
|
||||||
|
```
|
||||||
|
c e
|
||||||
|
| /
|
||||||
|
| /
|
||||||
|
a ---- x ---- b
|
||||||
|
/|
|
||||||
|
/ |
|
||||||
|
f d
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
When turning from `a` to `b` via `x`,
|
||||||
|
* `roads_on_the_right[1]` is the road `xf`
|
||||||
|
* `roads_on_the_right[2]` is the road `xd`
|
||||||
|
* `roads_on_the_left[1]` is the road `xe`
|
||||||
|
* `roads_on_the_left[2]` is the road `xc`
|
||||||
|
|
||||||
|
Note that indices of arrays in lua are 1-based.
|
||||||
|
|
||||||
|
#### `highway_turn_classification` and `access_turn_classification`
|
||||||
|
When setting appropriate turn weights and duration, information about the highway and access tags of roads that are involved in the turn are necessary. The lua turn function `process_turn` does not have access to the original osrm tags anymore. However, `highway_turn_classification` and `access_turn_classification` can be set during setup. The classification set during setup can be later used in `process_turn`.
|
||||||
|
|
||||||
|
**Example**
|
||||||
|
|
||||||
|
In the following example we use `highway_turn_classification` to set the turn weight to `10` if the turn is on a highway and to `5` if the turn is on a primary.
|
||||||
|
|
||||||
|
```
|
||||||
|
function setup()
|
||||||
|
return {
|
||||||
|
highway_turn_classification = {
|
||||||
|
['motorway'] = 2,
|
||||||
|
['primary'] = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function process_turn(profile, turn) {
|
||||||
|
if turn.source_highway_turn_classification == 2 and turn.target_highway_turn_classification == 2 then
|
||||||
|
turn.weight = 10
|
||||||
|
end
|
||||||
|
if turn.source_highway_turn_classification == 1 and turn.target_highway_turn_classification == 1 then
|
||||||
|
turn.weight = 5
|
||||||
|
end
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Guidance
|
## Guidance
|
||||||
The guidance parameters in profiles are currently a work in progress. They can and will change.
|
The guidance parameters in profiles are currently a work in progress. They can and will change.
|
||||||
|
176
features/options/extract/turn_function.feature
Normal file
176
features/options/extract/turn_function.feature
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
@routing @testbot @turn_function
|
||||||
|
Feature: Turn Function Information
|
||||||
|
|
||||||
|
|
||||||
|
Background:
|
||||||
|
Given the profile file
|
||||||
|
"""
|
||||||
|
functions = require('car')
|
||||||
|
|
||||||
|
function test_setup()
|
||||||
|
profile = functions.setup()
|
||||||
|
profile.highway_turn_classification = {
|
||||||
|
['motorway'] = 4,
|
||||||
|
['motorway_link'] = 4,
|
||||||
|
['trunk'] = 4,
|
||||||
|
['trunk_link'] = 4,
|
||||||
|
['primary'] = 4,
|
||||||
|
['primary_link'] = 4,
|
||||||
|
['secondary'] = 3,
|
||||||
|
['secondary_link'] = 3,
|
||||||
|
['tertiary'] = 2,
|
||||||
|
['tertiary_link'] = 2,
|
||||||
|
['residential'] = 1,
|
||||||
|
['living_street'] = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
profile.access_turn_classification = {
|
||||||
|
['discouraged'] = 1;
|
||||||
|
['permissive'] = 1;
|
||||||
|
['private'] = 1;
|
||||||
|
['customers'] = 1;
|
||||||
|
['dismount'] = 1;
|
||||||
|
}
|
||||||
|
return profile
|
||||||
|
end
|
||||||
|
|
||||||
|
function turn_leg_string (leg)
|
||||||
|
return 'speed: ' .. tostring(leg.speed)
|
||||||
|
.. ', is_incoming: ' .. tostring(leg.is_incoming)
|
||||||
|
.. ', is_outgoing: ' .. tostring(leg.is_outgoing)
|
||||||
|
.. ', highway_turn_classification: ' .. tostring(leg.highway_turn_classification)
|
||||||
|
.. ', access_turn_classification: ' .. tostring(leg.access_turn_classification)
|
||||||
|
end
|
||||||
|
|
||||||
|
function print_turn (profile, turn)
|
||||||
|
print ('source_restricted ' .. string.format("%s", tostring(turn.source_restricted)))
|
||||||
|
print ('source_is_motorway ' .. string.format("%s", tostring(turn.source_is_motorway)))
|
||||||
|
print ('source_is_link ' .. string.format("%s", tostring(turn.source_is_link)))
|
||||||
|
print ('source_number_of_lanes ' .. string.format("%s", tostring(turn.source_number_of_lanes)))
|
||||||
|
print ('source_highway_turn_classification ' .. string.format("%s", tostring(turn.source_highway_turn_classification)))
|
||||||
|
print ('source_access_turn_classification ' .. string.format("%s", tostring(turn.source_access_turn_classification)))
|
||||||
|
print ('source_speed ' .. string.format("%s", tostring(turn.source_speed)))
|
||||||
|
|
||||||
|
print ('target_restricted ' .. string.format("%s", tostring(turn.target_restricted)))
|
||||||
|
print ('target_is_motorway ' .. string.format("%s", tostring(turn.target_is_motorway)))
|
||||||
|
print ('target_is_link ' .. string.format("%s", tostring(turn.target_is_link)))
|
||||||
|
print ('target_number_of_lanes ' .. string.format("%s", tostring(turn.target_number_of_lanes)))
|
||||||
|
print ('target_highway_turn_classification ' .. string.format("%s", tostring(turn.target_highway_turn_classification)))
|
||||||
|
print ('target_access_turn_classification ' .. string.format("%s", tostring(turn.target_access_turn_classification)))
|
||||||
|
print ('target_speed ' .. string.format("%s", tostring(turn.target_speed)))
|
||||||
|
|
||||||
|
print ('number_of_roads ' .. string.format("%s", tostring(turn.number_of_roads)))
|
||||||
|
if not turn.is_u_turn then
|
||||||
|
for roadCount, road in ipairs(turn.roads_on_the_right) do
|
||||||
|
print('roads_on_the_right [' .. tostring(roadCount) .. '] ' .. turn_leg_string(road))
|
||||||
|
end
|
||||||
|
|
||||||
|
for roadCount, road in ipairs(turn.roads_on_the_left) do
|
||||||
|
print('roads_on_the_left [' .. tostring(roadCount) .. '] ' .. turn_leg_string(road))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
setup = test_setup,
|
||||||
|
process_way = functions.process_way,
|
||||||
|
process_node = functions.process_node,
|
||||||
|
process_turn = print_turn
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: Turns should have correct information of source and target
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
|
||||||
|
a b c
|
||||||
|
|
||||||
|
"""
|
||||||
|
And the ways
|
||||||
|
| nodes | highway |
|
||||||
|
| ab | motorway |
|
||||||
|
| bc | motorway |
|
||||||
|
And the data has been saved to disk
|
||||||
|
|
||||||
|
When I run "osrm-extract --profile {profile_file} {osm_file}"
|
||||||
|
Then it should exit successfully
|
||||||
|
And stdout should contain "source_is_motorway true"
|
||||||
|
And stdout should contain "target_is_motorway true"
|
||||||
|
And stdout should contain "source_is_link false"
|
||||||
|
And stdout should contain "target_is_motorway true"
|
||||||
|
And stdout should contain "target_is_link false"
|
||||||
|
|
||||||
|
|
||||||
|
Scenario: Turns should detect when turn is leaving highway
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
|
||||||
|
a b c
|
||||||
|
|
||||||
|
"""
|
||||||
|
And the ways
|
||||||
|
| nodes | highway | lanes |
|
||||||
|
| ab | motorway | 3 |
|
||||||
|
| bc | motorway_link | |
|
||||||
|
|
||||||
|
And the data has been saved to disk
|
||||||
|
|
||||||
|
When I run "osrm-extract --profile {profile_file} {osm_file}"
|
||||||
|
Then it should exit successfully
|
||||||
|
And stdout should contain "source_is_motorway true"
|
||||||
|
And stdout should contain "source_is_link false"
|
||||||
|
And stdout should contain "source_number_of_lanes 3"
|
||||||
|
And stdout should contain "target_is_motorway false"
|
||||||
|
And stdout should contain "target_is_link true"
|
||||||
|
And stdout should contain "target_number_of_lanes 0"
|
||||||
|
And stdout should contain "number_of_roads 2"
|
||||||
|
|
||||||
|
Scenario: Turns should have correct information of other roads at intersection I
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
d
|
||||||
|
^
|
||||||
|
|
|
||||||
|
a->b->c
|
||||||
|
"""
|
||||||
|
And the ways
|
||||||
|
| nodes | highway | oneway |
|
||||||
|
| ab | primary | yes |
|
||||||
|
| bc | motorway | yes |
|
||||||
|
| bd | residential | yes |
|
||||||
|
And the data has been saved to disk
|
||||||
|
|
||||||
|
When I run "osrm-extract --profile {profile_file} {osm_file}"
|
||||||
|
Then it should exit successfully
|
||||||
|
And stdout should contain "number_of_roads 3"
|
||||||
|
# turning abd, give information about bc
|
||||||
|
And stdout should contain /roads_on_the_right \[1\] speed: [0-9]+, is_incoming: false, is_outgoing: true, highway_turn_classification: 4, access_turn_classification: 0/
|
||||||
|
# turning abc, give information about bd
|
||||||
|
And stdout should contain /roads_on_the_left \[1\] speed: [0-9]+, is_incoming: false, is_outgoing: true, highway_turn_classification: 1, access_turn_classification: 0/
|
||||||
|
|
||||||
|
Scenario: Turns should have correct information of other roads at intersection II
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
d
|
||||||
|
|
|
||||||
|
v
|
||||||
|
a->b->c
|
||||||
|
"""
|
||||||
|
And the ways
|
||||||
|
| nodes | highway | oneway | access |
|
||||||
|
| ab | secondary | yes | |
|
||||||
|
| bc | motorway | yes | |
|
||||||
|
| db | unclassified | yes | discouraged |
|
||||||
|
And the data has been saved to disk
|
||||||
|
|
||||||
|
When I run "osrm-extract --profile {profile_file} {osm_file}"
|
||||||
|
Then it should exit successfully
|
||||||
|
And stdout should contain "number_of_roads 3"
|
||||||
|
# turning dbc, give information about about ab
|
||||||
|
And stdout should contain /roads_on_the_right \[1\] speed: [0-9]+, is_incoming: true, is_outgoing: false, highway_turn_classification: 3, access_turn_classification: 0/
|
||||||
|
# turning abc, give information about about db
|
||||||
|
And stdout should contain /roads_on_the_left \[1\] speed: [0-9]+, is_incoming: true, is_outgoing: false, highway_turn_classification: 0, access_turn_classification: 1/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -50,6 +50,8 @@ module.exports = function () {
|
|||||||
.defer(mkdirp, logDir)
|
.defer(mkdirp, logDir)
|
||||||
.defer(rimraf, this.scenarioLogFile)
|
.defer(rimraf, this.scenarioLogFile)
|
||||||
.awaitAll(callback);
|
.awaitAll(callback);
|
||||||
|
// uncomment to get path to logfile
|
||||||
|
// console.log(" Writing logging output to " + this.scenarioLogFile)
|
||||||
});
|
});
|
||||||
|
|
||||||
this.After((scenario, callback) => {
|
this.After((scenario, callback) => {
|
||||||
|
@ -12,35 +12,115 @@ namespace osrm
|
|||||||
namespace extractor
|
namespace extractor
|
||||||
{
|
{
|
||||||
|
|
||||||
|
struct ExtractionTurnLeg
|
||||||
|
{
|
||||||
|
ExtractionTurnLeg(bool is_restricted,
|
||||||
|
bool is_motorway,
|
||||||
|
bool is_link,
|
||||||
|
int number_of_lanes,
|
||||||
|
int highway_turn_classification,
|
||||||
|
int access_turn_classification,
|
||||||
|
int speed,
|
||||||
|
bool is_incoming,
|
||||||
|
bool is_outgoing)
|
||||||
|
: is_restricted(is_restricted), is_motorway(is_motorway), is_link(is_link),
|
||||||
|
number_of_lanes(number_of_lanes),
|
||||||
|
highway_turn_classification(highway_turn_classification),
|
||||||
|
access_turn_classification(access_turn_classification), speed(speed),
|
||||||
|
is_incoming(is_incoming), is_outgoing(is_outgoing)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool is_restricted;
|
||||||
|
const bool is_motorway;
|
||||||
|
const bool is_link;
|
||||||
|
const int number_of_lanes;
|
||||||
|
const int highway_turn_classification;
|
||||||
|
const int access_turn_classification;
|
||||||
|
const int speed;
|
||||||
|
const bool is_incoming;
|
||||||
|
const bool is_outgoing;
|
||||||
|
};
|
||||||
|
|
||||||
struct ExtractionTurn
|
struct ExtractionTurn
|
||||||
{
|
{
|
||||||
ExtractionTurn(double angle,
|
ExtractionTurn(double angle,
|
||||||
int number_of_roads,
|
int number_of_roads,
|
||||||
bool is_u_turn,
|
bool is_u_turn,
|
||||||
bool has_traffic_light,
|
bool has_traffic_light,
|
||||||
bool source_restricted,
|
|
||||||
bool target_restricted,
|
|
||||||
bool is_left_hand_driving,
|
bool is_left_hand_driving,
|
||||||
|
bool source_restricted,
|
||||||
TravelMode source_mode,
|
TravelMode source_mode,
|
||||||
TravelMode target_mode)
|
bool source_is_motorway,
|
||||||
|
bool source_is_link,
|
||||||
|
|
||||||
|
int source_number_of_lanes,
|
||||||
|
int source_highway_turn_classification,
|
||||||
|
int source_access_turn_classification,
|
||||||
|
int source_speed,
|
||||||
|
bool target_restricted,
|
||||||
|
TravelMode target_mode,
|
||||||
|
bool target_is_motorway,
|
||||||
|
bool target_is_link,
|
||||||
|
int target_number_of_lanes,
|
||||||
|
int target_highway_turn_classification,
|
||||||
|
int target_access_turn_classification,
|
||||||
|
int target_speed,
|
||||||
|
const std::vector<ExtractionTurnLeg> &roads_on_the_right,
|
||||||
|
const std::vector<ExtractionTurnLeg> &roads_on_the_left)
|
||||||
: angle(180. - angle), number_of_roads(number_of_roads), is_u_turn(is_u_turn),
|
: angle(180. - angle), number_of_roads(number_of_roads), is_u_turn(is_u_turn),
|
||||||
has_traffic_light(has_traffic_light), source_restricted(source_restricted),
|
has_traffic_light(has_traffic_light), is_left_hand_driving(is_left_hand_driving),
|
||||||
target_restricted(target_restricted), is_left_hand_driving(is_left_hand_driving),
|
|
||||||
weight(0.), duration(0.), source_mode(source_mode), target_mode(target_mode)
|
source_restricted(source_restricted), source_mode(source_mode),
|
||||||
|
source_is_motorway(source_is_motorway), source_is_link(source_is_link),
|
||||||
|
source_number_of_lanes(source_number_of_lanes),
|
||||||
|
source_highway_turn_classification(source_highway_turn_classification),
|
||||||
|
source_access_turn_classification(source_access_turn_classification),
|
||||||
|
source_speed(source_speed),
|
||||||
|
|
||||||
|
target_restricted(target_restricted), target_mode(target_mode),
|
||||||
|
target_is_motorway(target_is_motorway), target_is_link(target_is_link),
|
||||||
|
target_number_of_lanes(target_number_of_lanes),
|
||||||
|
target_highway_turn_classification(target_highway_turn_classification),
|
||||||
|
target_access_turn_classification(target_access_turn_classification),
|
||||||
|
target_speed(target_speed),
|
||||||
|
|
||||||
|
roads_on_the_right(roads_on_the_right), roads_on_the_left(roads_on_the_left), weight(0.),
|
||||||
|
duration(0.)
|
||||||
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
const double angle;
|
const double angle;
|
||||||
const int number_of_roads;
|
const int number_of_roads;
|
||||||
const bool is_u_turn;
|
const bool is_u_turn;
|
||||||
const bool has_traffic_light;
|
const bool has_traffic_light;
|
||||||
const bool source_restricted;
|
|
||||||
const bool target_restricted;
|
|
||||||
const bool is_left_hand_driving;
|
const bool is_left_hand_driving;
|
||||||
|
|
||||||
|
// source info
|
||||||
|
const bool source_restricted;
|
||||||
|
const TravelMode source_mode;
|
||||||
|
const bool source_is_motorway;
|
||||||
|
const bool source_is_link;
|
||||||
|
const int source_number_of_lanes;
|
||||||
|
const int source_highway_turn_classification;
|
||||||
|
const int source_access_turn_classification;
|
||||||
|
const int source_speed;
|
||||||
|
|
||||||
|
// target info
|
||||||
|
const bool target_restricted;
|
||||||
|
const TravelMode target_mode;
|
||||||
|
const bool target_is_motorway;
|
||||||
|
const bool target_is_link;
|
||||||
|
const int target_number_of_lanes;
|
||||||
|
const int target_highway_turn_classification;
|
||||||
|
const int target_access_turn_classification;
|
||||||
|
const int target_speed;
|
||||||
|
|
||||||
|
const std::vector<ExtractionTurnLeg> roads_on_the_right;
|
||||||
|
const std::vector<ExtractionTurnLeg> roads_on_the_left;
|
||||||
|
|
||||||
double weight;
|
double weight;
|
||||||
double duration;
|
double duration;
|
||||||
const TravelMode source_mode;
|
|
||||||
const TravelMode target_mode;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,6 +63,8 @@ struct ExtractionWay
|
|||||||
forward_restricted = false;
|
forward_restricted = false;
|
||||||
backward_restricted = false;
|
backward_restricted = false;
|
||||||
is_left_hand_driving = false;
|
is_left_hand_driving = false;
|
||||||
|
highway_turn_classification = 0;
|
||||||
|
access_turn_classification = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// wrappers to allow assigning nil (nullptr) to string values
|
// wrappers to allow assigning nil (nullptr) to string values
|
||||||
@ -123,6 +125,10 @@ struct ExtractionWay
|
|||||||
bool backward_restricted : 1;
|
bool backward_restricted : 1;
|
||||||
bool is_left_hand_driving : 1;
|
bool is_left_hand_driving : 1;
|
||||||
bool : 2;
|
bool : 2;
|
||||||
|
|
||||||
|
// user classifications for turn penalties
|
||||||
|
std::uint8_t highway_turn_classification : 4;
|
||||||
|
std::uint8_t access_turn_classification : 4;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,8 @@ struct NodeBasedEdgeClassification
|
|||||||
std::uint8_t startpoint : 1; // 1
|
std::uint8_t startpoint : 1; // 1
|
||||||
std::uint8_t restricted : 1; // 1
|
std::uint8_t restricted : 1; // 1
|
||||||
guidance::RoadClassification road_classification; // 16 2
|
guidance::RoadClassification road_classification; // 16 2
|
||||||
|
std::uint8_t highway_turn_classification : 4; // 4
|
||||||
|
std::uint8_t access_turn_classification : 4; // 4
|
||||||
|
|
||||||
NodeBasedEdgeClassification();
|
NodeBasedEdgeClassification();
|
||||||
|
|
||||||
@ -37,10 +39,14 @@ struct NodeBasedEdgeClassification
|
|||||||
const bool circular,
|
const bool circular,
|
||||||
const bool startpoint,
|
const bool startpoint,
|
||||||
const bool restricted,
|
const bool restricted,
|
||||||
guidance::RoadClassification road_classification)
|
guidance::RoadClassification road_classification,
|
||||||
|
const std::uint8_t highway_turn_classification,
|
||||||
|
const std::uint8_t access_turn_classification)
|
||||||
: forward(forward), backward(backward), is_split(is_split), roundabout(roundabout),
|
: forward(forward), backward(backward), is_split(is_split), roundabout(roundabout),
|
||||||
circular(circular), startpoint(startpoint), restricted(restricted),
|
circular(circular), startpoint(startpoint), restricted(restricted),
|
||||||
road_classification(road_classification)
|
road_classification(road_classification),
|
||||||
|
highway_turn_classification(highway_turn_classification),
|
||||||
|
access_turn_classification(access_turn_classification)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,7 +148,7 @@ template <storage::Ownership Ownership> class MultiLevelPartitionImpl final
|
|||||||
auto offsets = MakeLevelOffsets(lidx_to_num_cells);
|
auto offsets = MakeLevelOffsets(lidx_to_num_cells);
|
||||||
auto masks = MakeLevelMasks(offsets, num_level);
|
auto masks = MakeLevelMasks(offsets, num_level);
|
||||||
auto bits = MakeBitToLevel(offsets, num_level);
|
auto bits = MakeBitToLevel(offsets, num_level);
|
||||||
return std::make_unique<LevelData>(LevelData{num_level, offsets, masks, bits, {0}});
|
return std::make_unique<LevelData>(LevelData{num_level, offsets, masks, bits, {{0}}});
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::size_t LevelIDToIndex(LevelID l) const { return l - 1; }
|
inline std::size_t LevelIDToIndex(LevelID l) const { return l - 1; }
|
||||||
|
@ -20,9 +20,7 @@
|
|||||||
if (!static_cast<bool>(cond)) \
|
if (!static_cast<bool>(cond)) \
|
||||||
{ \
|
{ \
|
||||||
::osrm::util::FloatCoordinate c_(loc); \
|
::osrm::util::FloatCoordinate c_(loc); \
|
||||||
std::cerr << "[Location] " \
|
std::cerr << "[Location] " << c_.toOSMLink() << '\n'; \
|
||||||
<< "http://www.openstreetmap.org/?mlat=" << c_.lat << "&mlon=" << c_.lon \
|
|
||||||
<< "#map=19/" << c_.lat << "/" << c_.lon << '\n'; \
|
|
||||||
} \
|
} \
|
||||||
BOOST_ASSERT_MSG(cond, msg); \
|
BOOST_ASSERT_MSG(cond, msg); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
@ -34,6 +34,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <iosfwd> //for std::ostream
|
#include <iosfwd> //for std::ostream
|
||||||
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
@ -216,6 +217,15 @@ struct Coordinate
|
|||||||
friend bool operator==(const Coordinate lhs, const Coordinate rhs);
|
friend bool operator==(const Coordinate lhs, const Coordinate rhs);
|
||||||
friend bool operator!=(const Coordinate lhs, const Coordinate rhs);
|
friend bool operator!=(const Coordinate lhs, const Coordinate rhs);
|
||||||
friend std::ostream &operator<<(std::ostream &out, const Coordinate coordinate);
|
friend std::ostream &operator<<(std::ostream &out, const Coordinate coordinate);
|
||||||
|
|
||||||
|
std::string toOSMLink() const
|
||||||
|
{
|
||||||
|
std::stringstream link;
|
||||||
|
link << "http://www.openstreetmap.org/?mlat=" << toFloating(lat)
|
||||||
|
<< "&mlon=" << toFloating(lon) << "#map=19/" << toFloating(lat) << "/"
|
||||||
|
<< toFloating(lon);
|
||||||
|
return link.str();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -257,6 +267,14 @@ struct FloatCoordinate
|
|||||||
friend bool operator==(const FloatCoordinate lhs, const FloatCoordinate rhs);
|
friend bool operator==(const FloatCoordinate lhs, const FloatCoordinate rhs);
|
||||||
friend bool operator!=(const FloatCoordinate lhs, const FloatCoordinate rhs);
|
friend bool operator!=(const FloatCoordinate lhs, const FloatCoordinate rhs);
|
||||||
friend std::ostream &operator<<(std::ostream &out, const FloatCoordinate coordinate);
|
friend std::ostream &operator<<(std::ostream &out, const FloatCoordinate coordinate);
|
||||||
|
|
||||||
|
std::string toOSMLink() const
|
||||||
|
{
|
||||||
|
std::stringstream link;
|
||||||
|
link << "http://www.openstreetmap.org/?mlat=" << lat << "&mlon=" << lon << "#map=19/" << lat
|
||||||
|
<< "/" << lon;
|
||||||
|
return link.str();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
bool operator==(const Coordinate lhs, const Coordinate rhs);
|
bool operator==(const Coordinate lhs, const Coordinate rhs);
|
||||||
|
@ -298,6 +298,14 @@ function setup()
|
|||||||
|
|
||||||
relation_types = Sequence {
|
relation_types = Sequence {
|
||||||
"route"
|
"route"
|
||||||
|
},
|
||||||
|
|
||||||
|
-- classify highway tags when necessary for turn weights
|
||||||
|
highway_turn_classification = {
|
||||||
|
},
|
||||||
|
|
||||||
|
-- classify access tags when necessary for turn weights
|
||||||
|
access_turn_classification = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
@ -413,7 +421,10 @@ function process_way(profile, way, result, relations)
|
|||||||
WayHandlers.names,
|
WayHandlers.names,
|
||||||
|
|
||||||
-- set weight properties of the way
|
-- set weight properties of the way
|
||||||
WayHandlers.weights
|
WayHandlers.weights,
|
||||||
|
|
||||||
|
-- set classification of ways relevant for turns
|
||||||
|
WayHandlers.way_classification_for_turn
|
||||||
}
|
}
|
||||||
|
|
||||||
WayHandlers.run(profile, way, result, data, handlers, relations)
|
WayHandlers.run(profile, way, result, data, handlers, relations)
|
||||||
|
@ -221,6 +221,23 @@ function WayHandlers.hov(profile,way,result,data)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- set highway and access classification by user preference
|
||||||
|
function WayHandlers.way_classification_for_turn(profile,way,result,data)
|
||||||
|
local highway = way:get_value_by_key("highway")
|
||||||
|
local access = way:get_value_by_key("access")
|
||||||
|
|
||||||
|
if highway and profile.highway_turn_classification[highway] then
|
||||||
|
assert(profile.highway_turn_classification[highway] < 16, "highway_turn_classification must be smaller than 16")
|
||||||
|
result.highway_turn_classification = profile.highway_turn_classification[highway]
|
||||||
|
end
|
||||||
|
if access and profile.access_turn_classification[access] then
|
||||||
|
assert(profile.access_turn_classification[access] < 16, "access_turn_classification must be smaller than 16")
|
||||||
|
result.access_turn_classification = profile.access_turn_classification[access]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
-- check accessibility by traversing our access tag hierarchy
|
-- check accessibility by traversing our access tag hierarchy
|
||||||
function WayHandlers.access(profile,way,result,data)
|
function WayHandlers.access(profile,way,result,data)
|
||||||
data.forward_access, data.backward_access =
|
data.forward_access, data.backward_access =
|
||||||
|
@ -267,7 +267,8 @@ void EdgeBasedGraphFactory::Run(ScriptingEnvironment &scripting_environment,
|
|||||||
/// Returns the number of edge-based nodes.
|
/// Returns the number of edge-based nodes.
|
||||||
unsigned EdgeBasedGraphFactory::LabelEdgeBasedNodes()
|
unsigned EdgeBasedGraphFactory::LabelEdgeBasedNodes()
|
||||||
{
|
{
|
||||||
// heuristic: node-based graph node is a simple intersection with four edges (edge-based nodes)
|
// heuristic: node-based graph node is a simple intersection with four edges
|
||||||
|
// (edge-based nodes)
|
||||||
m_edge_based_node_weights.reserve(4 * m_node_based_graph.GetNumberOfNodes());
|
m_edge_based_node_weights.reserve(4 * m_node_based_graph.GetNumberOfNodes());
|
||||||
nbe_to_ebn_mapping.resize(m_node_based_graph.GetEdgeCapacity(), SPECIAL_NODEID);
|
nbe_to_ebn_mapping.resize(m_node_based_graph.GetEdgeCapacity(), SPECIAL_NODEID);
|
||||||
|
|
||||||
@ -295,7 +296,7 @@ unsigned EdgeBasedGraphFactory::LabelEdgeBasedNodes()
|
|||||||
return numbered_edges_count;
|
return numbered_edges_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates the nodes in the edge expanded graph from edges in the node-based graph.
|
// Creates the nodes in the edge expanded graph from edges in the node-based graph.
|
||||||
std::vector<NBGToEBG>
|
std::vector<NBGToEBG>
|
||||||
EdgeBasedGraphFactory::GenerateEdgeExpandedNodes(const WayRestrictionMap &way_restriction_map)
|
EdgeBasedGraphFactory::GenerateEdgeExpandedNodes(const WayRestrictionMap &way_restriction_map)
|
||||||
{
|
{
|
||||||
@ -323,8 +324,8 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedNodes(const WayRestrictionMap &way_re
|
|||||||
BOOST_ASSERT(nbg_node_v != SPECIAL_NODEID);
|
BOOST_ASSERT(nbg_node_v != SPECIAL_NODEID);
|
||||||
BOOST_ASSERT(nbg_node_u != nbg_node_v);
|
BOOST_ASSERT(nbg_node_u != nbg_node_v);
|
||||||
|
|
||||||
// pick only every other edge, since we have every edge as an outgoing
|
// pick only every other edge, since we have every edge as an outgoing and incoming
|
||||||
// and incoming egde
|
// egde
|
||||||
if (nbg_node_u >= nbg_node_v)
|
if (nbg_node_u >= nbg_node_v)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
@ -410,7 +411,6 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
const ConditionalRestrictionMap &conditional_restriction_map,
|
const ConditionalRestrictionMap &conditional_restriction_map,
|
||||||
const WayRestrictionMap &way_restriction_map)
|
const WayRestrictionMap &way_restriction_map)
|
||||||
{
|
{
|
||||||
|
|
||||||
util::Log() << "Generating edge-expanded edges ";
|
util::Log() << "Generating edge-expanded edges ";
|
||||||
|
|
||||||
std::size_t node_based_edge_counter = 0;
|
std::size_t node_based_edge_counter = 0;
|
||||||
@ -472,14 +472,12 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
|
|
||||||
// filled in during next stage, kept alive through following scope
|
// filled in during next stage, kept alive through following scope
|
||||||
std::vector<Conditional> conditionals;
|
std::vector<Conditional> conditionals;
|
||||||
// The following block generates the edge-based-edges using a parallel processing
|
// The following block generates the edge-based-edges using a parallel processing pipeline.
|
||||||
// pipeline. Sets of intersection IDs are batched in groups of GRAINSIZE (100)
|
// Sets of intersection IDs are batched in groups of GRAINSIZE (100) `generator_stage`, then
|
||||||
// `generator_stage`,
|
// those groups are processed in parallel `processor_stage`. Finally, results are appended to
|
||||||
// then those groups are processed in parallel `processor_stage`. Finally, results are
|
// the various buffer vectors by the `output_stage` in the same order that the `generator_stage`
|
||||||
// appended to the various buffer vectors by the `output_stage` in the same order
|
// created them in (tbb::filter::serial_in_order creates this guarantee). The order needs to be
|
||||||
// that the `generator_stage` created them in (tbb::filter::serial_in_order creates this
|
// maintained because we depend on it later in the processing pipeline.
|
||||||
// guarantee). The order needs to be maintained because we depend on it later in the
|
|
||||||
// processing pipeline.
|
|
||||||
{
|
{
|
||||||
util::UnbufferedLog log;
|
util::UnbufferedLog log;
|
||||||
|
|
||||||
@ -488,17 +486,18 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
// This counter is used to keep track of how far along we've made it
|
// This counter is used to keep track of how far along we've made it
|
||||||
std::uint64_t nodes_completed = 0;
|
std::uint64_t nodes_completed = 0;
|
||||||
|
|
||||||
// going over all nodes (which form the center of an intersection), we compute all
|
// going over all nodes (which form the center of an intersection), we compute all possible
|
||||||
// possible turns along these intersections.
|
// turns along these intersections.
|
||||||
|
|
||||||
NodeID current_node = 0;
|
NodeID current_node = 0;
|
||||||
|
|
||||||
// Handle intersections in sets of 100. The pipeline below has a serial bottleneck
|
// Handle intersections in sets of 100. The pipeline below has a serial bottleneck during
|
||||||
// during the writing phase, so we want to make the parallel workers do more work
|
// the writing phase, so we want to make the parallel workers do more work to give the
|
||||||
// to give the serial final stage time to complete its tasks.
|
// serial final stage time to complete its tasks.
|
||||||
const constexpr unsigned GRAINSIZE = 100;
|
const constexpr unsigned GRAINSIZE = 100;
|
||||||
|
|
||||||
// First part of the pipeline generates iterator ranges of IDs in sets of GRAINSIZE
|
// First part of the pipeline generates iterator ranges of IDs in sets of
|
||||||
|
// GRAINSIZE
|
||||||
tbb::filter_t<void, tbb::blocked_range<NodeID>> generator_stage(
|
tbb::filter_t<void, tbb::blocked_range<NodeID>> generator_stage(
|
||||||
tbb::filter::serial_in_order, [&](tbb::flow_control &fc) -> tbb::blocked_range<NodeID> {
|
tbb::filter::serial_in_order, [&](tbb::flow_control &fc) -> tbb::blocked_range<NodeID> {
|
||||||
if (current_node < node_count)
|
if (current_node < node_count)
|
||||||
@ -515,8 +514,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// This struct is the buffered output of the `processor_stage`. This data is
|
// This struct is the buffered output of the `processor_stage`. This data is appended to
|
||||||
// appended to the various output arrays/files by the `output_stage`.
|
// the various output arrays/files by the `output_stage`.
|
||||||
struct IntersectionData
|
struct IntersectionData
|
||||||
{
|
{
|
||||||
std::vector<lookup::TurnIndexBlock> turn_indexes;
|
std::vector<lookup::TurnIndexBlock> turn_indexes;
|
||||||
@ -562,7 +561,10 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
const auto node_based_edge_to,
|
const auto node_based_edge_to,
|
||||||
const auto incoming_bearing,
|
const auto incoming_bearing,
|
||||||
const auto &turn,
|
const auto &turn,
|
||||||
const auto entry_class_id) {
|
const auto &road_legs_on_the_right,
|
||||||
|
const auto &road_legs_on_the_left,
|
||||||
|
const auto entry_class_id,
|
||||||
|
const auto &edge_geometries) {
|
||||||
|
|
||||||
const auto node_restricted = isRestricted(node_along_road_entering,
|
const auto node_restricted = isRestricted(node_along_road_entering,
|
||||||
intersection_node,
|
intersection_node,
|
||||||
@ -598,21 +600,46 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
|
|
||||||
// compute weight and duration penalties
|
// compute weight and duration penalties
|
||||||
auto is_traffic_light = m_traffic_lights.count(intersection_node);
|
auto is_traffic_light = m_traffic_lights.count(intersection_node);
|
||||||
|
|
||||||
ExtractionTurn extracted_turn(
|
ExtractionTurn extracted_turn(
|
||||||
|
// general info
|
||||||
turn.angle,
|
turn.angle,
|
||||||
m_node_based_graph.GetOutDegree(intersection_node),
|
road_legs_on_the_right.size() + road_legs_on_the_left.size() + 2 -
|
||||||
|
turn.instruction.IsUTurn(),
|
||||||
turn.instruction.IsUTurn(),
|
turn.instruction.IsUTurn(),
|
||||||
is_traffic_light,
|
is_traffic_light,
|
||||||
edge_data1.flags.restricted,
|
|
||||||
edge_data2.flags.restricted,
|
|
||||||
m_edge_based_node_container.GetAnnotation(edge_data1.annotation_data)
|
m_edge_based_node_container.GetAnnotation(edge_data1.annotation_data)
|
||||||
.is_left_hand_driving,
|
.is_left_hand_driving,
|
||||||
|
// source info
|
||||||
|
edge_data1.flags.restricted,
|
||||||
m_edge_based_node_container.GetAnnotation(edge_data1.annotation_data).travel_mode,
|
m_edge_based_node_container.GetAnnotation(edge_data1.annotation_data).travel_mode,
|
||||||
m_edge_based_node_container.GetAnnotation(edge_data2.annotation_data).travel_mode);
|
edge_data1.flags.road_classification.IsMotorwayClass(),
|
||||||
|
edge_data1.flags.road_classification.IsLinkClass(),
|
||||||
|
edge_data1.flags.road_classification.GetNumberOfLanes(),
|
||||||
|
edge_data1.flags.highway_turn_classification,
|
||||||
|
edge_data1.flags.access_turn_classification,
|
||||||
|
((double)intersection::findEdgeLength(edge_geometries, node_based_edge_from) /
|
||||||
|
edge_data1.duration) *
|
||||||
|
36,
|
||||||
|
// target info
|
||||||
|
edge_data2.flags.restricted,
|
||||||
|
m_edge_based_node_container.GetAnnotation(edge_data2.annotation_data).travel_mode,
|
||||||
|
edge_data2.flags.road_classification.IsMotorwayClass(),
|
||||||
|
edge_data2.flags.road_classification.IsLinkClass(),
|
||||||
|
edge_data2.flags.road_classification.GetNumberOfLanes(),
|
||||||
|
edge_data2.flags.highway_turn_classification,
|
||||||
|
edge_data2.flags.access_turn_classification,
|
||||||
|
((double)intersection::findEdgeLength(edge_geometries, node_based_edge_to) /
|
||||||
|
edge_data2.duration) *
|
||||||
|
36,
|
||||||
|
// connected roads
|
||||||
|
road_legs_on_the_right,
|
||||||
|
road_legs_on_the_left);
|
||||||
|
|
||||||
scripting_environment.ProcessTurn(extracted_turn);
|
scripting_environment.ProcessTurn(extracted_turn);
|
||||||
|
|
||||||
// turn penalties are limited to [-2^15, 2^15) which roughly
|
// turn penalties are limited to [-2^15, 2^15) which roughly translates to 54 minutes
|
||||||
// translates to 54 minutes and fits signed 16bit deci-seconds
|
// and fits signed 16bit deci-seconds
|
||||||
auto weight_penalty =
|
auto weight_penalty =
|
||||||
boost::numeric_cast<TurnPenalty>(extracted_turn.weight * weight_multiplier);
|
boost::numeric_cast<TurnPenalty>(extracted_turn.weight * weight_multiplier);
|
||||||
auto duration_penalty = boost::numeric_cast<TurnPenalty>(extracted_turn.duration * 10.);
|
auto duration_penalty = boost::numeric_cast<TurnPenalty>(extracted_turn.duration * 10.);
|
||||||
@ -634,16 +661,15 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
true,
|
true,
|
||||||
false};
|
false};
|
||||||
|
|
||||||
// We write out the mapping between the edge-expanded edges and
|
// We write out the mapping between the edge-expanded edges and the original nodes.
|
||||||
// the original nodes. Since each edge represents a possible
|
// Since each edge represents a possible maneuver, external programs can use this to
|
||||||
// maneuver, external programs can use this to quickly perform updates to edge
|
// quickly perform updates to edge weights in order to penalize certain turns.
|
||||||
// weights in order to penalize certain turns.
|
|
||||||
|
|
||||||
// If this edge is 'trivial' -- where the compressed edge
|
// If this edge is 'trivial' -- where the compressed edge corresponds exactly to an
|
||||||
// corresponds exactly to an original OSM segment -- we can pull the turn's
|
// original OSM segment -- we can pull the turn's preceding node ID directly with
|
||||||
// preceding node ID directly with `node_along_road_entering`;
|
// `node_along_road_entering`;
|
||||||
// otherwise, we need to look up the node immediately preceding the turn
|
// otherwise, we need to look up the node immediately preceding the turn from the
|
||||||
// from the compressed edge container.
|
// compressed edge container.
|
||||||
const bool isTrivial = m_compressed_edge_container.IsTrivial(node_based_edge_from);
|
const bool isTrivial = m_compressed_edge_container.IsTrivial(node_based_edge_from);
|
||||||
|
|
||||||
const auto &from_node =
|
const auto &from_node =
|
||||||
@ -660,8 +686,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
conditional);
|
conditional);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Second part of the pipeline is where the intersection analysis is done for
|
// Second part of the pipeline is where the intersection analysis is done for each
|
||||||
// each intersection
|
// intersection
|
||||||
tbb::filter_t<tbb::blocked_range<NodeID>, std::shared_ptr<PipelineBuffer>> processor_stage(
|
tbb::filter_t<tbb::blocked_range<NodeID>, std::shared_ptr<PipelineBuffer>> processor_stage(
|
||||||
tbb::filter::parallel, [&](const tbb::blocked_range<NodeID> &intersection_node_range) {
|
tbb::filter::parallel, [&](const tbb::blocked_range<NodeID> &intersection_node_range) {
|
||||||
|
|
||||||
@ -678,8 +704,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
intersection_node < end;
|
intersection_node < end;
|
||||||
++intersection_node)
|
++intersection_node)
|
||||||
{
|
{
|
||||||
// We capture the thread-local work in these objects, then flush
|
// We capture the thread-local work in these objects, then flush them in a
|
||||||
// them in a controlled manner at the end of the parallel range
|
// controlled manner at the end of the parallel range
|
||||||
const auto &incoming_edges =
|
const auto &incoming_edges =
|
||||||
intersection::getIncomingEdges(m_node_based_graph, intersection_node);
|
intersection::getIncomingEdges(m_node_based_graph, intersection_node);
|
||||||
const auto &outgoing_edges =
|
const auto &outgoing_edges =
|
||||||
@ -709,9 +735,9 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
// b: a,rev=1 c,rev=0 d,rev=0
|
// b: a,rev=1 c,rev=0 d,rev=0
|
||||||
// c: b,rev=0
|
// c: b,rev=0
|
||||||
//
|
//
|
||||||
// From the flags alone, we cannot determine which nodes are connected to
|
// From the flags alone, we cannot determine which nodes are connected to `b` by
|
||||||
// `b` by an outgoing edge. Therefore, we have to search all connected edges for
|
// an outgoing edge. Therefore, we have to search all connected edges for edges
|
||||||
// edges entering `b`
|
// entering `b`
|
||||||
|
|
||||||
for (const auto &incoming_edge : incoming_edges)
|
for (const auto &incoming_edge : incoming_edges)
|
||||||
{
|
{
|
||||||
@ -746,9 +772,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
const auto bearing_class_id =
|
const auto bearing_class_id =
|
||||||
bearing_class_hash.ConcurrentFindOrAdd(turn_classification.second);
|
bearing_class_hash.ConcurrentFindOrAdd(turn_classification.second);
|
||||||
|
|
||||||
// Note - this is strictly speaking not thread safe, but we know we
|
// Note - this is strictly speaking not thread safe, but we know we should
|
||||||
// should never be touching the same element twice, so we should
|
// never be touching the same element twice, so we should be fine.
|
||||||
// be fine.
|
|
||||||
bearing_class_by_node_based_node[intersection_node] = bearing_class_id;
|
bearing_class_by_node_based_node[intersection_node] = bearing_class_id;
|
||||||
|
|
||||||
// check if we are turning off a via way
|
// check if we are turning off a via way
|
||||||
@ -780,6 +805,76 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
OSRM_ASSERT(turn != intersection.end(),
|
OSRM_ASSERT(turn != intersection.end(),
|
||||||
m_coordinates[intersection_node]);
|
m_coordinates[intersection_node]);
|
||||||
|
|
||||||
|
std::vector<ExtractionTurnLeg> road_legs_on_the_right;
|
||||||
|
std::vector<ExtractionTurnLeg> road_legs_on_the_left;
|
||||||
|
|
||||||
|
auto get_connected_road_info = [&](const auto &connected_edge) {
|
||||||
|
const auto &edge_data =
|
||||||
|
m_node_based_graph.GetEdgeData(connected_edge.eid);
|
||||||
|
return ExtractionTurnLeg(
|
||||||
|
edge_data.flags.restricted,
|
||||||
|
edge_data.flags.road_classification.IsMotorwayClass(),
|
||||||
|
edge_data.flags.road_classification.IsLinkClass(),
|
||||||
|
edge_data.flags.road_classification.GetNumberOfLanes(),
|
||||||
|
edge_data.flags.highway_turn_classification,
|
||||||
|
edge_data.flags.access_turn_classification,
|
||||||
|
((double)intersection::findEdgeLength(edge_geometries,
|
||||||
|
connected_edge.eid) /
|
||||||
|
edge_data.duration) *
|
||||||
|
36,
|
||||||
|
!connected_edge.entry_allowed ||
|
||||||
|
(edge_data.flags.forward &&
|
||||||
|
edge_data.flags.backward), // is incoming
|
||||||
|
connected_edge.entry_allowed);
|
||||||
|
};
|
||||||
|
|
||||||
|
// all connected roads on the right of a u turn
|
||||||
|
if (turn->instruction.IsUTurn())
|
||||||
|
{
|
||||||
|
if (turn != intersection.begin())
|
||||||
|
{
|
||||||
|
std::transform(intersection.begin() + 1,
|
||||||
|
turn,
|
||||||
|
std::back_inserter(road_legs_on_the_right),
|
||||||
|
get_connected_road_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::transform(turn + 1,
|
||||||
|
intersection.end(),
|
||||||
|
std::back_inserter(road_legs_on_the_right),
|
||||||
|
get_connected_road_info);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (intersection.begin() != turn)
|
||||||
|
{
|
||||||
|
std::transform(intersection.begin() + 1,
|
||||||
|
turn,
|
||||||
|
std::back_inserter(road_legs_on_the_right),
|
||||||
|
get_connected_road_info);
|
||||||
|
}
|
||||||
|
std::transform(turn + 1,
|
||||||
|
intersection.end(),
|
||||||
|
std::back_inserter(road_legs_on_the_left),
|
||||||
|
get_connected_road_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (turn->instruction.IsUTurn() && turn != intersection.begin())
|
||||||
|
{
|
||||||
|
util::Log(logWARNING)
|
||||||
|
<< "Turn is a u turn but not turning to the first connected "
|
||||||
|
"edge of the intersection. Node ID: "
|
||||||
|
<< intersection_node << ", OSM link: "
|
||||||
|
<< m_coordinates[intersection_node].toOSMLink();
|
||||||
|
}
|
||||||
|
else if (turn == intersection.begin() && !turn->instruction.IsUTurn())
|
||||||
|
{
|
||||||
|
util::Log(logWARNING)
|
||||||
|
<< "Turn is a u turn but not classified as a u turn. Node ID: "
|
||||||
|
<< intersection_node << ", OSM link: "
|
||||||
|
<< m_coordinates[intersection_node].toOSMLink();
|
||||||
|
}
|
||||||
|
|
||||||
// In case a way restriction starts at a given location, add a turn onto
|
// In case a way restriction starts at a given location, add a turn onto
|
||||||
// every artificial node eminating here.
|
// every artificial node eminating here.
|
||||||
//
|
//
|
||||||
@ -796,10 +891,9 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
// Since every restriction group (abc | abe) refers to the same
|
// Since every restriction group (abc | abe) refers to the same
|
||||||
// artificial node, we simply have to find a single representative for
|
// artificial node, we simply have to find a single representative for
|
||||||
// the turn. Here we check whether the turn in question is the start of
|
// the turn. Here we check whether the turn in question is the start of
|
||||||
// a via way restriction. If that should be the case, we switch
|
// a via way restriction. If that should be the case, we switch the id
|
||||||
// the id of the edge-based-node for the target to the ID of the
|
// of the edge-based-node for the target to the ID of the duplicated
|
||||||
// duplicated node associated with the turn. (e.g. ab via bc switches bc
|
// node associated with the turn. (e.g. ab via bc switches bc to bc_dup)
|
||||||
// to bc_dup)
|
|
||||||
auto const target_id = way_restriction_map.RemapIfRestricted(
|
auto const target_id = way_restriction_map.RemapIfRestricted(
|
||||||
nbe_to_ebn_mapping[outgoing_edge.edge],
|
nbe_to_ebn_mapping[outgoing_edge.edge],
|
||||||
incoming_edge.node,
|
incoming_edge.node,
|
||||||
@ -817,7 +911,10 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
outgoing_edge.edge,
|
outgoing_edge.edge,
|
||||||
reversed_incoming_bearing,
|
reversed_incoming_bearing,
|
||||||
*turn,
|
*turn,
|
||||||
entry_class_id);
|
road_legs_on_the_right,
|
||||||
|
road_legs_on_the_left,
|
||||||
|
entry_class_id,
|
||||||
|
edge_geometries);
|
||||||
|
|
||||||
buffer->continuous_data.edges_list.push_back(
|
buffer->continuous_data.edges_list.push_back(
|
||||||
edge_with_data_and_condition.first.edge);
|
edge_with_data_and_condition.first.edge);
|
||||||
@ -879,7 +976,10 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
outgoing_edge.edge,
|
outgoing_edge.edge,
|
||||||
reversed_incoming_bearing,
|
reversed_incoming_bearing,
|
||||||
*turn,
|
*turn,
|
||||||
entry_class_id);
|
road_legs_on_the_right,
|
||||||
|
road_legs_on_the_left,
|
||||||
|
entry_class_id,
|
||||||
|
edge_geometries);
|
||||||
|
|
||||||
buffer->delayed_data.push_back(
|
buffer->delayed_data.push_back(
|
||||||
std::move(edge_with_data_and_condition.first));
|
std::move(edge_with_data_and_condition.first));
|
||||||
@ -913,7 +1013,10 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
outgoing_edge.edge,
|
outgoing_edge.edge,
|
||||||
reversed_incoming_bearing,
|
reversed_incoming_bearing,
|
||||||
*turn,
|
*turn,
|
||||||
entry_class_id);
|
road_legs_on_the_right,
|
||||||
|
road_legs_on_the_left,
|
||||||
|
entry_class_id,
|
||||||
|
edge_geometries);
|
||||||
|
|
||||||
buffer->delayed_data.push_back(
|
buffer->delayed_data.push_back(
|
||||||
std::move(edge_with_data_and_condition.first));
|
std::move(edge_with_data_and_condition.first));
|
||||||
@ -933,11 +1036,9 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
return buffer;
|
return buffer;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Because we write TurnIndexBlock data as we go, we'll
|
// Because we write TurnIndexBlock data as we go, we'll buffer them into groups of 1000 to
|
||||||
// buffer them into groups of 1000 to reduce the syscall
|
// reduce the syscall count by 1000x. This doesn't need much memory, but greatly reduces
|
||||||
// count by 1000x. This doesn't need much memory, but
|
// the syscall overhead of writing lots of small objects
|
||||||
// greatly reduces the syscall overhead of writing lots
|
|
||||||
// of small objects
|
|
||||||
const constexpr int TURN_INDEX_WRITE_BUFFER_SIZE = 1000;
|
const constexpr int TURN_INDEX_WRITE_BUFFER_SIZE = 1000;
|
||||||
std::vector<lookup::TurnIndexBlock> turn_indexes_write_buffer;
|
std::vector<lookup::TurnIndexBlock> turn_indexes_write_buffer;
|
||||||
turn_indexes_write_buffer.reserve(TURN_INDEX_WRITE_BUFFER_SIZE);
|
turn_indexes_write_buffer.reserve(TURN_INDEX_WRITE_BUFFER_SIZE);
|
||||||
@ -983,11 +1084,11 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
delayed_data.end(), buffer->delayed_data.begin(), buffer->delayed_data.end());
|
delayed_data.end(), buffer->delayed_data.begin(), buffer->delayed_data.end());
|
||||||
});
|
});
|
||||||
|
|
||||||
// Now, execute the pipeline. The value of "5" here was chosen by experimentation
|
// Now, execute the pipeline. The value of "5" here was chosen by experimentation on a
|
||||||
// on a 16-CPU machine and seemed to give the best performance. This value needs
|
// 16-CPU machine and seemed to give the best performance. This value needs to be balanced
|
||||||
// to be balanced with the GRAINSIZE above - ideally, the pipeline puts as much work
|
// with the GRAINSIZE above - ideally, the pipeline puts as much work as possible in the
|
||||||
// as possible in the `intersection_handler` step so that those parallel workers don't
|
// `intersection_handler` step so that those parallel workers don't get blocked too much by
|
||||||
// get blocked too much by the slower (io-performing) `buffer_storage`
|
// the slower (io-performing) `buffer_storage`
|
||||||
tbb::parallel_pipeline(tbb::task_scheduler_init::default_num_threads() * 5,
|
tbb::parallel_pipeline(tbb::task_scheduler_init::default_num_threads() * 5,
|
||||||
generator_stage & processor_stage & output_stage);
|
generator_stage & processor_stage & output_stage);
|
||||||
|
|
||||||
@ -1013,8 +1114,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
}
|
}
|
||||||
|
|
||||||
util::Log() << "Reunmbering turns";
|
util::Log() << "Reunmbering turns";
|
||||||
// Now, update the turn_id property on every EdgeBasedEdge - it will equal the
|
// Now, update the turn_id property on every EdgeBasedEdge - it will equal the position in the
|
||||||
// position in the m_edge_based_edge_list array for each object.
|
// m_edge_based_edge_list array for each object.
|
||||||
tbb::parallel_for(tbb::blocked_range<NodeID>(0, m_edge_based_edge_list.size()),
|
tbb::parallel_for(tbb::blocked_range<NodeID>(0, m_edge_based_edge_list.size()),
|
||||||
[this](const tbb::blocked_range<NodeID> &range) {
|
[this](const tbb::blocked_range<NodeID> &range) {
|
||||||
for (auto x = range.begin(), end = range.end(); x != end; ++x)
|
for (auto x = range.begin(), end = range.end(); x != end; ++x)
|
||||||
@ -1023,8 +1124,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// re-hash conditionals to ocnnect to their respective edge-based edges. Due to the
|
// re-hash conditionals to ocnnect to their respective edge-based edges. Due to the ordering, we
|
||||||
// ordering, we
|
|
||||||
// do not really have a choice but to index the conditional penalties and walk over all
|
// do not really have a choice but to index the conditional penalties and walk over all
|
||||||
// edge-based-edges to find the ID of the edge
|
// edge-based-edges to find the ID of the edge
|
||||||
auto const indexed_conditionals = IndexConditionals(std::move(conditionals));
|
auto const indexed_conditionals = IndexConditionals(std::move(conditionals));
|
||||||
|
@ -423,7 +423,9 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
|
|||||||
parsed_way.circular,
|
parsed_way.circular,
|
||||||
parsed_way.is_startpoint,
|
parsed_way.is_startpoint,
|
||||||
parsed_way.forward_restricted,
|
parsed_way.forward_restricted,
|
||||||
road_classification}};
|
road_classification,
|
||||||
|
parsed_way.highway_turn_classification,
|
||||||
|
parsed_way.access_turn_classification}};
|
||||||
|
|
||||||
external_memory.all_edges_list.push_back(InternalExtractorEdge(
|
external_memory.all_edges_list.push_back(InternalExtractorEdge(
|
||||||
std::move(edge), forward_weight_data, forward_duration_data, {}));
|
std::move(edge), forward_weight_data, forward_duration_data, {}));
|
||||||
@ -456,7 +458,9 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
|
|||||||
parsed_way.circular,
|
parsed_way.circular,
|
||||||
parsed_way.is_startpoint,
|
parsed_way.is_startpoint,
|
||||||
parsed_way.backward_restricted,
|
parsed_way.backward_restricted,
|
||||||
road_classification}};
|
road_classification,
|
||||||
|
parsed_way.highway_turn_classification,
|
||||||
|
parsed_way.access_turn_classification}};
|
||||||
|
|
||||||
external_memory.all_edges_list.push_back(InternalExtractorEdge(
|
external_memory.all_edges_list.push_back(InternalExtractorEdge(
|
||||||
std::move(edge), backward_weight_data, backward_duration_data, {}));
|
std::move(edge), backward_weight_data, backward_duration_data, {}));
|
||||||
|
@ -220,17 +220,31 @@ void GraphCompressor::Compress(
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
// generate an artifical turn for the turn penalty generation
|
// generate an artifical turn for the turn penalty generation
|
||||||
ExtractionTurn extraction_turn(
|
std::vector<ExtractionTurnLeg> roads_on_the_right;
|
||||||
0,
|
std::vector<ExtractionTurnLeg> roads_on_the_left;
|
||||||
2,
|
ExtractionTurn extraction_turn(0,
|
||||||
false,
|
2,
|
||||||
true,
|
false,
|
||||||
fwd_edge_data1.flags.restricted,
|
true,
|
||||||
fwd_edge_data2.flags.restricted,
|
false,
|
||||||
node_data_container[fwd_edge_data1.annotation_data].is_left_hand_driving,
|
false,
|
||||||
TRAVEL_MODE_DRIVING,
|
TRAVEL_MODE_DRIVING,
|
||||||
TRAVEL_MODE_DRIVING);
|
false,
|
||||||
|
false,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
false,
|
||||||
|
TRAVEL_MODE_DRIVING,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
roads_on_the_right,
|
||||||
|
roads_on_the_left);
|
||||||
scripting_environment.ProcessTurn(extraction_turn);
|
scripting_environment.ProcessTurn(extraction_turn);
|
||||||
node_duration_penalty = extraction_turn.duration * 10;
|
node_duration_penalty = extraction_turn.duration * 10;
|
||||||
node_weight_penalty = extraction_turn.weight * weight_multiplier;
|
node_weight_penalty = extraction_turn.weight * weight_multiplier;
|
||||||
|
@ -346,7 +346,13 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
|||||||
[](ExtractionWay &way, bool flag) { way.backward_restricted = flag; }),
|
[](ExtractionWay &way, bool flag) { way.backward_restricted = flag; }),
|
||||||
"is_left_hand_driving",
|
"is_left_hand_driving",
|
||||||
sol::property([](const ExtractionWay &way) { return way.is_left_hand_driving; },
|
sol::property([](const ExtractionWay &way) { return way.is_left_hand_driving; },
|
||||||
[](ExtractionWay &way, bool flag) { way.is_left_hand_driving = flag; }));
|
[](ExtractionWay &way, bool flag) { way.is_left_hand_driving = flag; }),
|
||||||
|
"highway_turn_classification",
|
||||||
|
sol::property([](const ExtractionWay &way) { return way.highway_turn_classification; },
|
||||||
|
[](ExtractionWay &way, int flag) { way.highway_turn_classification = flag; }),
|
||||||
|
"access_turn_classification",
|
||||||
|
sol::property([](const ExtractionWay &way) { return way.access_turn_classification; },
|
||||||
|
[](ExtractionWay &way, int flag) { way.access_turn_classification = flag; }));
|
||||||
|
|
||||||
auto getTypedRefBySol = [](const sol::object &obj) -> ExtractionRelation::OsmIDTyped {
|
auto getTypedRefBySol = [](const sol::object &obj) -> ExtractionRelation::OsmIDTyped {
|
||||||
if (obj.is<osmium::Way>())
|
if (obj.is<osmium::Way>())
|
||||||
@ -670,29 +676,82 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
|||||||
{
|
{
|
||||||
case 4:
|
case 4:
|
||||||
{
|
{
|
||||||
context.state.new_usertype<ExtractionTurn>("ExtractionTurn",
|
context.state.new_usertype<ExtractionTurnLeg>(
|
||||||
"angle",
|
"ExtractionTurnLeg",
|
||||||
&ExtractionTurn::angle,
|
"is_restricted",
|
||||||
"number_of_roads",
|
&ExtractionTurnLeg::is_restricted,
|
||||||
&ExtractionTurn::number_of_roads,
|
"is_motorway",
|
||||||
"is_u_turn",
|
&ExtractionTurnLeg::is_motorway,
|
||||||
&ExtractionTurn::is_u_turn,
|
"is_link",
|
||||||
"has_traffic_light",
|
&ExtractionTurnLeg::is_link,
|
||||||
&ExtractionTurn::has_traffic_light,
|
"number_of_lanes",
|
||||||
"weight",
|
&ExtractionTurnLeg::number_of_lanes,
|
||||||
&ExtractionTurn::weight,
|
"highway_turn_classification",
|
||||||
"duration",
|
&ExtractionTurnLeg::highway_turn_classification,
|
||||||
&ExtractionTurn::duration,
|
"access_turn_classification",
|
||||||
"source_restricted",
|
&ExtractionTurnLeg::access_turn_classification,
|
||||||
&ExtractionTurn::source_restricted,
|
"speed",
|
||||||
"target_restricted",
|
&ExtractionTurnLeg::speed,
|
||||||
&ExtractionTurn::target_restricted,
|
"is_incoming",
|
||||||
"is_left_hand_driving",
|
&ExtractionTurnLeg::is_incoming,
|
||||||
&ExtractionTurn::is_left_hand_driving,
|
"is_outgoing",
|
||||||
"source_mode",
|
&ExtractionTurnLeg::is_outgoing);
|
||||||
&ExtractionTurn::source_mode,
|
|
||||||
"target_mode",
|
context.state.new_usertype<ExtractionTurn>(
|
||||||
&ExtractionTurn::target_mode);
|
"ExtractionTurn",
|
||||||
|
"angle",
|
||||||
|
&ExtractionTurn::angle,
|
||||||
|
"number_of_roads",
|
||||||
|
&ExtractionTurn::number_of_roads,
|
||||||
|
"is_u_turn",
|
||||||
|
&ExtractionTurn::is_u_turn,
|
||||||
|
"has_traffic_light",
|
||||||
|
&ExtractionTurn::has_traffic_light,
|
||||||
|
"is_left_hand_driving",
|
||||||
|
&ExtractionTurn::is_left_hand_driving,
|
||||||
|
|
||||||
|
"source_restricted",
|
||||||
|
&ExtractionTurn::source_restricted,
|
||||||
|
"source_mode",
|
||||||
|
&ExtractionTurn::source_mode,
|
||||||
|
"source_is_motorway",
|
||||||
|
&ExtractionTurn::source_is_motorway,
|
||||||
|
"source_is_link",
|
||||||
|
&ExtractionTurn::source_is_link,
|
||||||
|
"source_number_of_lanes",
|
||||||
|
&ExtractionTurn::source_number_of_lanes,
|
||||||
|
"source_highway_turn_classification",
|
||||||
|
&ExtractionTurn::source_highway_turn_classification,
|
||||||
|
"source_access_turn_classification",
|
||||||
|
&ExtractionTurn::source_access_turn_classification,
|
||||||
|
"source_speed",
|
||||||
|
&ExtractionTurn::source_speed,
|
||||||
|
|
||||||
|
"target_restricted",
|
||||||
|
&ExtractionTurn::target_restricted,
|
||||||
|
"target_mode",
|
||||||
|
&ExtractionTurn::target_mode,
|
||||||
|
"target_is_motorway",
|
||||||
|
&ExtractionTurn::target_is_motorway,
|
||||||
|
"target_is_link",
|
||||||
|
&ExtractionTurn::target_is_link,
|
||||||
|
"target_number_of_lanes",
|
||||||
|
&ExtractionTurn::target_number_of_lanes,
|
||||||
|
"target_highway_turn_classification",
|
||||||
|
&ExtractionTurn::target_highway_turn_classification,
|
||||||
|
"target_access_turn_classification",
|
||||||
|
&ExtractionTurn::target_access_turn_classification,
|
||||||
|
"target_speed",
|
||||||
|
&ExtractionTurn::target_speed,
|
||||||
|
|
||||||
|
"roads_on_the_right",
|
||||||
|
&ExtractionTurn::roads_on_the_right,
|
||||||
|
"roads_on_the_left",
|
||||||
|
&ExtractionTurn::roads_on_the_left,
|
||||||
|
"weight",
|
||||||
|
&ExtractionTurn::weight,
|
||||||
|
"duration",
|
||||||
|
&ExtractionTurn::duration);
|
||||||
initV2Context();
|
initV2Context();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -167,15 +167,15 @@ BOOST_AUTO_TEST_CASE(roundabout_intersection_connectivity)
|
|||||||
// ↙ ↑ ↘
|
// ↙ ↑ ↘
|
||||||
// 4 5 6
|
// 4 5 6
|
||||||
const auto unit_edge = [](const NodeID from, const NodeID to, bool allowed, bool roundabout) {
|
const auto unit_edge = [](const NodeID from, const NodeID to, bool allowed, bool roundabout) {
|
||||||
return InputEdge{
|
return InputEdge{from,
|
||||||
from,
|
to,
|
||||||
to,
|
1,
|
||||||
1,
|
1,
|
||||||
1,
|
GeometryID{0, false},
|
||||||
GeometryID{0, false},
|
!allowed,
|
||||||
!allowed,
|
NodeBasedEdgeClassification{
|
||||||
NodeBasedEdgeClassification{true, false, false, roundabout, false, false, false, {}},
|
true, false, false, roundabout, false, false, false, {}, 0, 0},
|
||||||
0};
|
0};
|
||||||
};
|
};
|
||||||
std::vector<InputEdge> edges = {unit_edge(0, 1, false, false),
|
std::vector<InputEdge> edges = {unit_edge(0, 1, false, false),
|
||||||
unit_edge(0, 2, true, true),
|
unit_edge(0, 2, true, true),
|
||||||
|
Loading…
Reference in New Issue
Block a user