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:
Huyen Chau Nguyen 2018-01-24 15:39:55 -05:00 committed by GitHub
parent 13bb997525
commit 61e06fcaba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 719 additions and 146 deletions

View File

@ -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:

View File

@ -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.

View 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/

View File

@ -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) => {

View File

@ -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;
}; };
} }
} }

View File

@ -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;
}; };
} }
} }

View File

@ -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)
{ {
} }

View File

@ -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; }

View File

@ -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)

View File

@ -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);

View File

@ -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)

View File

@ -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 =

View File

@ -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));

View File

@ -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, {}));

View File

@ -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;

View File

@ -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;
} }

View File

@ -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),