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:
|
||||
- Profile:
|
||||
- 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
|
||||
- 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`:
|
||||
|
||||
Attribute | Read/write? | Type | Notes
|
||||
---------------------|-------------|---------|------------------------------------------------------
|
||||
angle | Read | Float | Angle of turn in degrees (`0-360`: `0`=u-turn, `180`=straight on)
|
||||
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?
|
||||
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`)
|
||||
target_restricted | Read | Boolean | Is it to a restricted access road? (See definition in `process_way`)
|
||||
is_left_hand_driving | Read | Boolean | Is left-hand traffic?
|
||||
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)
|
||||
source_mode | Read | Enum | Travel mode before the turn. Defined in `include/extractor/travel_mode.hpp`
|
||||
target_mode | Read | Enum | Travel mode after the turn. Defined in `include/extractor/travel_mode.hpp`
|
||||
Attribute | Read/write? | Type | Notes
|
||||
--------------------- | ------------- | --------- | ------------------------------------------------------
|
||||
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
|
||||
is_u_turn | Read | Boolean | Is the turn a u-turn?
|
||||
has_traffic_light | Read | Boolean | Is a traffic light present at this turn?
|
||||
is_left_hand_driving | Read | Boolean | Is left-hand traffic?
|
||||
source_restricted | Read | Boolean | Is it from a restricted access road? (See definition in `process_way`)
|
||||
source_mode | Read | Enum | Travel mode before the turn. Defined in `include/extractor/travel_mode.hpp`
|
||||
source_is_motorway | Read | Boolean | Is the source road a motorway?
|
||||
source_is_link | Read | Boolean | Is the source road a link?
|
||||
source_number_of_lanes | Read | Integer | How many lanes does the source road have? (default when not tagged: 0)
|
||||
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
|
||||
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(rimraf, this.scenarioLogFile)
|
||||
.awaitAll(callback);
|
||||
// uncomment to get path to logfile
|
||||
// console.log(" Writing logging output to " + this.scenarioLogFile)
|
||||
});
|
||||
|
||||
this.After((scenario, callback) => {
|
||||
|
@ -12,35 +12,115 @@ namespace osrm
|
||||
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
|
||||
{
|
||||
ExtractionTurn(double angle,
|
||||
int number_of_roads,
|
||||
bool is_u_turn,
|
||||
bool has_traffic_light,
|
||||
bool source_restricted,
|
||||
bool target_restricted,
|
||||
bool is_left_hand_driving,
|
||||
bool source_restricted,
|
||||
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),
|
||||
has_traffic_light(has_traffic_light), source_restricted(source_restricted),
|
||||
target_restricted(target_restricted), is_left_hand_driving(is_left_hand_driving),
|
||||
weight(0.), duration(0.), source_mode(source_mode), target_mode(target_mode)
|
||||
has_traffic_light(has_traffic_light), is_left_hand_driving(is_left_hand_driving),
|
||||
|
||||
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 int number_of_roads;
|
||||
const bool is_u_turn;
|
||||
const bool has_traffic_light;
|
||||
const bool source_restricted;
|
||||
const bool target_restricted;
|
||||
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 duration;
|
||||
const TravelMode source_mode;
|
||||
const TravelMode target_mode;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -63,6 +63,8 @@ struct ExtractionWay
|
||||
forward_restricted = false;
|
||||
backward_restricted = false;
|
||||
is_left_hand_driving = false;
|
||||
highway_turn_classification = 0;
|
||||
access_turn_classification = 0;
|
||||
}
|
||||
|
||||
// wrappers to allow assigning nil (nullptr) to string values
|
||||
@ -123,6 +125,10 @@ struct ExtractionWay
|
||||
bool backward_restricted : 1;
|
||||
bool is_left_hand_driving : 1;
|
||||
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 restricted : 1; // 1
|
||||
guidance::RoadClassification road_classification; // 16 2
|
||||
std::uint8_t highway_turn_classification : 4; // 4
|
||||
std::uint8_t access_turn_classification : 4; // 4
|
||||
|
||||
NodeBasedEdgeClassification();
|
||||
|
||||
@ -37,10 +39,14 @@ struct NodeBasedEdgeClassification
|
||||
const bool circular,
|
||||
const bool startpoint,
|
||||
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),
|
||||
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 masks = MakeLevelMasks(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; }
|
||||
|
@ -20,9 +20,7 @@
|
||||
if (!static_cast<bool>(cond)) \
|
||||
{ \
|
||||
::osrm::util::FloatCoordinate c_(loc); \
|
||||
std::cerr << "[Location] " \
|
||||
<< "http://www.openstreetmap.org/?mlat=" << c_.lat << "&mlon=" << c_.lon \
|
||||
<< "#map=19/" << c_.lat << "/" << c_.lon << '\n'; \
|
||||
std::cerr << "[Location] " << c_.toOSMLink() << '\n'; \
|
||||
} \
|
||||
BOOST_ASSERT_MSG(cond, msg); \
|
||||
} while (0)
|
||||
|
@ -34,6 +34,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <cstddef>
|
||||
#include <iosfwd> //for std::ostream
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#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 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 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);
|
||||
|
@ -298,6 +298,14 @@ function setup()
|
||||
|
||||
relation_types = Sequence {
|
||||
"route"
|
||||
},
|
||||
|
||||
-- classify highway tags when necessary for turn weights
|
||||
highway_turn_classification = {
|
||||
},
|
||||
|
||||
-- classify access tags when necessary for turn weights
|
||||
access_turn_classification = {
|
||||
}
|
||||
}
|
||||
end
|
||||
@ -413,7 +421,10 @@ function process_way(profile, way, result, relations)
|
||||
WayHandlers.names,
|
||||
|
||||
-- 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)
|
||||
|
@ -221,6 +221,23 @@ function WayHandlers.hov(profile,way,result,data)
|
||||
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
|
||||
function WayHandlers.access(profile,way,result,data)
|
||||
data.forward_access, data.backward_access =
|
||||
|
@ -267,7 +267,8 @@ void EdgeBasedGraphFactory::Run(ScriptingEnvironment &scripting_environment,
|
||||
/// Returns the number of edge-based nodes.
|
||||
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());
|
||||
nbe_to_ebn_mapping.resize(m_node_based_graph.GetEdgeCapacity(), SPECIAL_NODEID);
|
||||
|
||||
@ -295,7 +296,7 @@ unsigned EdgeBasedGraphFactory::LabelEdgeBasedNodes()
|
||||
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>
|
||||
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_u != nbg_node_v);
|
||||
|
||||
// pick only every other edge, since we have every edge as an outgoing
|
||||
// and incoming egde
|
||||
// pick only every other edge, since we have every edge as an outgoing and incoming
|
||||
// egde
|
||||
if (nbg_node_u >= nbg_node_v)
|
||||
{
|
||||
continue;
|
||||
@ -410,7 +411,6 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
const ConditionalRestrictionMap &conditional_restriction_map,
|
||||
const WayRestrictionMap &way_restriction_map)
|
||||
{
|
||||
|
||||
util::Log() << "Generating edge-expanded edges ";
|
||||
|
||||
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
|
||||
std::vector<Conditional> conditionals;
|
||||
// The following block generates the edge-based-edges using a parallel processing
|
||||
// pipeline. Sets of intersection IDs are batched in groups of GRAINSIZE (100)
|
||||
// `generator_stage`,
|
||||
// then those groups are processed in parallel `processor_stage`. Finally, results are
|
||||
// appended to the various buffer vectors by the `output_stage` in the same order
|
||||
// that the `generator_stage` created them in (tbb::filter::serial_in_order creates this
|
||||
// guarantee). The order needs to be maintained because we depend on it later in the
|
||||
// processing pipeline.
|
||||
// The following block generates the edge-based-edges using a parallel processing pipeline.
|
||||
// Sets of intersection IDs are batched in groups of GRAINSIZE (100) `generator_stage`, then
|
||||
// those groups are processed in parallel `processor_stage`. Finally, results are appended to
|
||||
// the various buffer vectors by the `output_stage` in the same order that the `generator_stage`
|
||||
// created them in (tbb::filter::serial_in_order creates this guarantee). The order needs to be
|
||||
// maintained because we depend on it later in the processing pipeline.
|
||||
{
|
||||
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
|
||||
std::uint64_t nodes_completed = 0;
|
||||
|
||||
// going over all nodes (which form the center of an intersection), we compute all
|
||||
// possible turns along these intersections.
|
||||
// going over all nodes (which form the center of an intersection), we compute all possible
|
||||
// turns along these intersections.
|
||||
|
||||
NodeID current_node = 0;
|
||||
|
||||
// Handle intersections in sets of 100. The pipeline below has a serial bottleneck
|
||||
// during the writing phase, so we want to make the parallel workers do more work
|
||||
// to give the serial final stage time to complete its tasks.
|
||||
// Handle intersections in sets of 100. The pipeline below has a serial bottleneck during
|
||||
// the writing phase, so we want to make the parallel workers do more work to give the
|
||||
// serial final stage time to complete its tasks.
|
||||
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::serial_in_order, [&](tbb::flow_control &fc) -> tbb::blocked_range<NodeID> {
|
||||
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
|
||||
// appended to the various output arrays/files by the `output_stage`.
|
||||
// This struct is the buffered output of the `processor_stage`. This data is appended to
|
||||
// the various output arrays/files by the `output_stage`.
|
||||
struct IntersectionData
|
||||
{
|
||||
std::vector<lookup::TurnIndexBlock> turn_indexes;
|
||||
@ -562,7 +561,10 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
const auto node_based_edge_to,
|
||||
const auto incoming_bearing,
|
||||
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,
|
||||
intersection_node,
|
||||
@ -598,21 +600,46 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
|
||||
// compute weight and duration penalties
|
||||
auto is_traffic_light = m_traffic_lights.count(intersection_node);
|
||||
|
||||
ExtractionTurn extracted_turn(
|
||||
// general info
|
||||
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(),
|
||||
is_traffic_light,
|
||||
edge_data1.flags.restricted,
|
||||
edge_data2.flags.restricted,
|
||||
m_edge_based_node_container.GetAnnotation(edge_data1.annotation_data)
|
||||
.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_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);
|
||||
|
||||
// turn penalties are limited to [-2^15, 2^15) which roughly
|
||||
// translates to 54 minutes and fits signed 16bit deci-seconds
|
||||
// turn penalties are limited to [-2^15, 2^15) which roughly translates to 54 minutes
|
||||
// and fits signed 16bit deci-seconds
|
||||
auto weight_penalty =
|
||||
boost::numeric_cast<TurnPenalty>(extracted_turn.weight * weight_multiplier);
|
||||
auto duration_penalty = boost::numeric_cast<TurnPenalty>(extracted_turn.duration * 10.);
|
||||
@ -634,16 +661,15 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
true,
|
||||
false};
|
||||
|
||||
// We write out the mapping between the edge-expanded edges and
|
||||
// the original nodes. Since each edge represents a possible
|
||||
// maneuver, external programs can use this to quickly perform updates to edge
|
||||
// weights in order to penalize certain turns.
|
||||
// We write out the mapping between the edge-expanded edges and the original nodes.
|
||||
// Since each edge represents a possible maneuver, external programs can use this to
|
||||
// quickly perform updates to edge weights in order to penalize certain turns.
|
||||
|
||||
// If this edge is 'trivial' -- where the compressed edge
|
||||
// corresponds exactly to an original OSM segment -- we can pull the turn's
|
||||
// preceding node ID directly with `node_along_road_entering`;
|
||||
// otherwise, we need to look up the node immediately preceding the turn
|
||||
// from the compressed edge container.
|
||||
// If this edge is 'trivial' -- where the compressed edge corresponds exactly to an
|
||||
// original OSM segment -- we can pull the turn's preceding node ID directly with
|
||||
// `node_along_road_entering`;
|
||||
// otherwise, we need to look up the node immediately preceding the turn from the
|
||||
// compressed edge container.
|
||||
const bool isTrivial = m_compressed_edge_container.IsTrivial(node_based_edge_from);
|
||||
|
||||
const auto &from_node =
|
||||
@ -660,8 +686,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
conditional);
|
||||
};
|
||||
|
||||
// Second part of the pipeline is where the intersection analysis is done for
|
||||
// each intersection
|
||||
// Second part of the pipeline is where the intersection analysis is done for each
|
||||
// intersection
|
||||
tbb::filter_t<tbb::blocked_range<NodeID>, std::shared_ptr<PipelineBuffer>> processor_stage(
|
||||
tbb::filter::parallel, [&](const tbb::blocked_range<NodeID> &intersection_node_range) {
|
||||
|
||||
@ -678,8 +704,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
intersection_node < end;
|
||||
++intersection_node)
|
||||
{
|
||||
// We capture the thread-local work in these objects, then flush
|
||||
// them in a controlled manner at the end of the parallel range
|
||||
// We capture the thread-local work in these objects, then flush them in a
|
||||
// controlled manner at the end of the parallel range
|
||||
const auto &incoming_edges =
|
||||
intersection::getIncomingEdges(m_node_based_graph, intersection_node);
|
||||
const auto &outgoing_edges =
|
||||
@ -709,9 +735,9 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
// b: a,rev=1 c,rev=0 d,rev=0
|
||||
// c: b,rev=0
|
||||
//
|
||||
// From the flags alone, we cannot determine which nodes are connected to
|
||||
// `b` by an outgoing edge. Therefore, we have to search all connected edges for
|
||||
// edges entering `b`
|
||||
// From the flags alone, we cannot determine which nodes are connected to `b` by
|
||||
// an outgoing edge. Therefore, we have to search all connected edges for edges
|
||||
// entering `b`
|
||||
|
||||
for (const auto &incoming_edge : incoming_edges)
|
||||
{
|
||||
@ -746,9 +772,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
const auto bearing_class_id =
|
||||
bearing_class_hash.ConcurrentFindOrAdd(turn_classification.second);
|
||||
|
||||
// Note - this is strictly speaking not thread safe, but we know we
|
||||
// should never be touching the same element twice, so we should
|
||||
// be fine.
|
||||
// Note - this is strictly speaking not thread safe, but we know we should
|
||||
// never be touching the same element twice, so we should be fine.
|
||||
bearing_class_by_node_based_node[intersection_node] = bearing_class_id;
|
||||
|
||||
// check if we are turning off a via way
|
||||
@ -780,6 +805,76 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
OSRM_ASSERT(turn != intersection.end(),
|
||||
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
|
||||
// every artificial node eminating here.
|
||||
//
|
||||
@ -796,10 +891,9 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
// Since every restriction group (abc | abe) refers to the same
|
||||
// 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
|
||||
// a via way restriction. If that should be the case, we switch
|
||||
// the id of the edge-based-node for the target to the ID of the
|
||||
// duplicated node associated with the turn. (e.g. ab via bc switches bc
|
||||
// to bc_dup)
|
||||
// a via way restriction. If that should be the case, we switch the id
|
||||
// of the edge-based-node for the target to the ID of the duplicated
|
||||
// node associated with the turn. (e.g. ab via bc switches bc to bc_dup)
|
||||
auto const target_id = way_restriction_map.RemapIfRestricted(
|
||||
nbe_to_ebn_mapping[outgoing_edge.edge],
|
||||
incoming_edge.node,
|
||||
@ -817,7 +911,10 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
outgoing_edge.edge,
|
||||
reversed_incoming_bearing,
|
||||
*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(
|
||||
edge_with_data_and_condition.first.edge);
|
||||
@ -879,7 +976,10 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
outgoing_edge.edge,
|
||||
reversed_incoming_bearing,
|
||||
*turn,
|
||||
entry_class_id);
|
||||
road_legs_on_the_right,
|
||||
road_legs_on_the_left,
|
||||
entry_class_id,
|
||||
edge_geometries);
|
||||
|
||||
buffer->delayed_data.push_back(
|
||||
std::move(edge_with_data_and_condition.first));
|
||||
@ -913,7 +1013,10 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
outgoing_edge.edge,
|
||||
reversed_incoming_bearing,
|
||||
*turn,
|
||||
entry_class_id);
|
||||
road_legs_on_the_right,
|
||||
road_legs_on_the_left,
|
||||
entry_class_id,
|
||||
edge_geometries);
|
||||
|
||||
buffer->delayed_data.push_back(
|
||||
std::move(edge_with_data_and_condition.first));
|
||||
@ -933,11 +1036,9 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
return buffer;
|
||||
});
|
||||
|
||||
// Because we write TurnIndexBlock data as we go, we'll
|
||||
// buffer them into groups of 1000 to reduce the syscall
|
||||
// count by 1000x. This doesn't need much memory, but
|
||||
// greatly reduces the syscall overhead of writing lots
|
||||
// of small objects
|
||||
// Because we write TurnIndexBlock data as we go, we'll buffer them into groups of 1000 to
|
||||
// reduce the syscall count by 1000x. This doesn't need much memory, but greatly reduces
|
||||
// the syscall overhead of writing lots of small objects
|
||||
const constexpr int TURN_INDEX_WRITE_BUFFER_SIZE = 1000;
|
||||
std::vector<lookup::TurnIndexBlock> turn_indexes_write_buffer;
|
||||
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());
|
||||
});
|
||||
|
||||
// Now, execute the pipeline. The value of "5" here was chosen by experimentation
|
||||
// on a 16-CPU machine and seemed to give the best performance. This value needs
|
||||
// to be balanced with the GRAINSIZE above - ideally, the pipeline puts as much work
|
||||
// as possible in the `intersection_handler` step so that those parallel workers don't
|
||||
// get blocked too much by the slower (io-performing) `buffer_storage`
|
||||
// Now, execute the pipeline. The value of "5" here was chosen by experimentation on a
|
||||
// 16-CPU machine and seemed to give the best performance. This value needs to be balanced
|
||||
// with the GRAINSIZE above - ideally, the pipeline puts as much work as possible in the
|
||||
// `intersection_handler` step so that those parallel workers don't get blocked too much by
|
||||
// the slower (io-performing) `buffer_storage`
|
||||
tbb::parallel_pipeline(tbb::task_scheduler_init::default_num_threads() * 5,
|
||||
generator_stage & processor_stage & output_stage);
|
||||
|
||||
@ -1013,8 +1114,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
}
|
||||
|
||||
util::Log() << "Reunmbering turns";
|
||||
// Now, update the turn_id property on every EdgeBasedEdge - it will equal the
|
||||
// position in the m_edge_based_edge_list array for each object.
|
||||
// Now, update the turn_id property on every EdgeBasedEdge - it will equal the position in the
|
||||
// m_edge_based_edge_list array for each object.
|
||||
tbb::parallel_for(tbb::blocked_range<NodeID>(0, m_edge_based_edge_list.size()),
|
||||
[this](const tbb::blocked_range<NodeID> &range) {
|
||||
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
|
||||
// ordering, we
|
||||
// re-hash conditionals to ocnnect to their respective edge-based edges. Due to the ordering, we
|
||||
// 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
|
||||
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.is_startpoint,
|
||||
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(
|
||||
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.is_startpoint,
|
||||
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(
|
||||
std::move(edge), backward_weight_data, backward_duration_data, {}));
|
||||
|
@ -220,17 +220,31 @@ void GraphCompressor::Compress(
|
||||
continue;
|
||||
|
||||
// generate an artifical turn for the turn penalty generation
|
||||
ExtractionTurn extraction_turn(
|
||||
0,
|
||||
2,
|
||||
false,
|
||||
true,
|
||||
fwd_edge_data1.flags.restricted,
|
||||
fwd_edge_data2.flags.restricted,
|
||||
node_data_container[fwd_edge_data1.annotation_data].is_left_hand_driving,
|
||||
TRAVEL_MODE_DRIVING,
|
||||
TRAVEL_MODE_DRIVING);
|
||||
|
||||
std::vector<ExtractionTurnLeg> roads_on_the_right;
|
||||
std::vector<ExtractionTurnLeg> roads_on_the_left;
|
||||
ExtractionTurn extraction_turn(0,
|
||||
2,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
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);
|
||||
node_duration_penalty = extraction_turn.duration * 10;
|
||||
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; }),
|
||||
"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 {
|
||||
if (obj.is<osmium::Way>())
|
||||
@ -670,29 +676,82 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
||||
{
|
||||
case 4:
|
||||
{
|
||||
context.state.new_usertype<ExtractionTurn>("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,
|
||||
"weight",
|
||||
&ExtractionTurn::weight,
|
||||
"duration",
|
||||
&ExtractionTurn::duration,
|
||||
"source_restricted",
|
||||
&ExtractionTurn::source_restricted,
|
||||
"target_restricted",
|
||||
&ExtractionTurn::target_restricted,
|
||||
"is_left_hand_driving",
|
||||
&ExtractionTurn::is_left_hand_driving,
|
||||
"source_mode",
|
||||
&ExtractionTurn::source_mode,
|
||||
"target_mode",
|
||||
&ExtractionTurn::target_mode);
|
||||
context.state.new_usertype<ExtractionTurnLeg>(
|
||||
"ExtractionTurnLeg",
|
||||
"is_restricted",
|
||||
&ExtractionTurnLeg::is_restricted,
|
||||
"is_motorway",
|
||||
&ExtractionTurnLeg::is_motorway,
|
||||
"is_link",
|
||||
&ExtractionTurnLeg::is_link,
|
||||
"number_of_lanes",
|
||||
&ExtractionTurnLeg::number_of_lanes,
|
||||
"highway_turn_classification",
|
||||
&ExtractionTurnLeg::highway_turn_classification,
|
||||
"access_turn_classification",
|
||||
&ExtractionTurnLeg::access_turn_classification,
|
||||
"speed",
|
||||
&ExtractionTurnLeg::speed,
|
||||
"is_incoming",
|
||||
&ExtractionTurnLeg::is_incoming,
|
||||
"is_outgoing",
|
||||
&ExtractionTurnLeg::is_outgoing);
|
||||
|
||||
context.state.new_usertype<ExtractionTurn>(
|
||||
"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();
|
||||
break;
|
||||
}
|
||||
|
@ -167,15 +167,15 @@ BOOST_AUTO_TEST_CASE(roundabout_intersection_connectivity)
|
||||
// ↙ ↑ ↘
|
||||
// 4 5 6
|
||||
const auto unit_edge = [](const NodeID from, const NodeID to, bool allowed, bool roundabout) {
|
||||
return InputEdge{
|
||||
from,
|
||||
to,
|
||||
1,
|
||||
1,
|
||||
GeometryID{0, false},
|
||||
!allowed,
|
||||
NodeBasedEdgeClassification{true, false, false, roundabout, false, false, false, {}},
|
||||
0};
|
||||
return InputEdge{from,
|
||||
to,
|
||||
1,
|
||||
1,
|
||||
GeometryID{0, false},
|
||||
!allowed,
|
||||
NodeBasedEdgeClassification{
|
||||
true, false, false, roundabout, false, false, false, {}, 0, 0},
|
||||
0};
|
||||
};
|
||||
std::vector<InputEdge> edges = {unit_edge(0, 1, false, false),
|
||||
unit_edge(0, 2, true, true),
|
||||
|
Loading…
Reference in New Issue
Block a user