Expose driving_side as a property on RouteStep

This commit is contained in:
Daniel Patterson 2017-10-31 23:51:11 -04:00
parent 5b79640b44
commit 5b58445535
14 changed files with 1811 additions and 31 deletions

View File

@ -1,10 +1,14 @@
# UNRELEASED # UNRELEASED
- Changes from 5.13
- Changes from 5.13: - API:
- new RouteStep property `driving_side` that has either "left" or "right" for that step
- Misc:
- Bundles a rough (please improve!) driving-side GeoJSON file for use with `osrm-extract --location-dependent-data data/driving_side.geojson`
- Profile: - Profile:
- Remove dependency on turn types and turn modifier in the process_turn function in the `car.lua` profile. Guidance instruction types are not used to influence turn penalty anymore so this will break backward compatibility between profile version 3 and 4. - Remove dependency on turn types and turn modifier in the process_turn function in the `car.lua` profile. Guidance instruction types are not used to influence turn penalty anymore so this will break backward compatibility between profile version 3 and 4.
- Bugfixes: - Bugfixes:
- Fixed #4670: Fix bug where merge instructions got the wrong direction modifier - Fixed #4670: Fix bug where merge instructions got the wrong direction modifier
- Properly use the `profile.properties.left_hand_driving` property, there was a typo that meant it had no effect
# 5.13.0 # 5.13.0
- Changes from 5.12: - Changes from 5.12:

1748
data/driving_side.geojson Normal file

File diff suppressed because it is too large Load Diff

View File

@ -594,6 +594,7 @@ step.
- `intersections`: A list of `Intersection` objects that are passed along the segment, the very first belonging to the StepManeuver - `intersections`: A list of `Intersection` objects that are passed along the segment, the very first belonging to the StepManeuver
- `rotary_name`: The name for the rotary. Optionally included, if the step is a rotary and a rotary name is available. - `rotary_name`: The name for the rotary. Optionally included, if the step is a rotary and a rotary name is available.
- `rotary_pronunciation`: The pronunciation hint of the rotary name. Optionally included, if the step is a rotary and a rotary pronunciation is available. - `rotary_pronunciation`: The pronunciation hint of the rotary name. Optionally included, if the step is a rotary and a rotary pronunciation is available.
- `driving_side`: The legal driving side at the location for this step. Either `left` or `right`.
#### Example #### Example

View File

@ -4,7 +4,7 @@ Feature: Testbot - side bias
Scenario: Left-hand bias Scenario: Left-hand bias
Given the profile file "car" initialized with Given the profile file "car" initialized with
""" """
profile.left_hand_driving = true profile.properties.left_hand_driving = true
profile.turn_bias = 1.075 profile.turn_bias = 1.075
""" """
And the node map And the node map
@ -20,14 +20,14 @@ Feature: Testbot - side bias
| bd | | bd |
When I route I should get When I route I should get
| from | to | route | time | | from | to | route | time | driving_side |
| d | a | bd,ab,ab | 24s +-1 | | d | a | bd,ab,ab | 24s +-1 | left,left,left |
| d | c | bd,bc,bc | 27s +-1 | | d | c | bd,bc,bc | 27s +-1 | left,left,left |
Scenario: Right-hand bias Scenario: Right-hand bias
Given the profile file "car" initialized with Given the profile file "car" initialized with
""" """
profile.left_hand_driving = true profile.properties.left_hand_driving = true
profile.turn_bias = 1 / 1.075 profile.turn_bias = 1 / 1.075
""" """
And the node map And the node map
@ -43,14 +43,14 @@ Feature: Testbot - side bias
| bd | | bd |
When I route I should get When I route I should get
| from | to | route | time | # | | from | to | route | time | driving_side | # |
| d | a | bd,ab,ab | 27s +-1 | should be inverse of left hand bias | | d | a | bd,ab,ab | 27s +-1 | left,left,left | should be inverse of left hand bias |
| d | c | bd,bc,bc | 24s +-1 | | | d | c | bd,bc,bc | 24s +-1 | left,left,left | |
Scenario: Roundabout exit counting for left sided driving Scenario: Roundabout exit counting for left sided driving
Given the profile file "testbot" initialized with Given the profile file "car" initialized with
""" """
profile.left_hand_driving = true profile.properties.left_hand_driving = true
""" """
And a grid size of 10 meters And a grid size of 10 meters
And the node map And the node map
@ -70,10 +70,10 @@ Feature: Testbot - side bias
| bcegb | roundabout | | bcegb | roundabout |
When I route I should get When I route I should get
| waypoints | route | turns | | waypoints | route | driving_side | turns |
| a,d | ab,cd,cd | depart,roundabout turn left exit-1,arrive | | a,d | ab,cd,cd | left,left,left | depart,roundabout turn left exit-1,arrive |
| a,f | ab,ef,ef | depart,roundabout turn straight exit-2,arrive | | a,f | ab,ef,ef | left,left,left | depart,roundabout turn straight exit-2,arrive |
| a,h | ab,gh,gh | depart,roundabout turn right exit-3,arrive | | a,h | ab,gh,gh | left,left,left | depart,roundabout turn right exit-3,arrive |
Scenario: Left-hand bias via location-dependent tags Scenario: Left-hand bias via location-dependent tags
@ -92,9 +92,9 @@ Feature: Testbot - side bias
And the extract extra arguments "--location-dependent-data test/data/regions/null-island.geojson" And the extract extra arguments "--location-dependent-data test/data/regions/null-island.geojson"
When I route I should get When I route I should get
| from | to | route | time | | from | to | route | driving_side | time |
| d | a | bd,ab,ab | 24s +-1 | | d | a | bd,ab,ab | left,left,left | 24s +-1 |
| d | c | bd,bc,bc | 27s +-1 | | d | c | bd,bc,bc | left,left,left | 27s +-1 |
Scenario: Left-hand bias via OSM tags Scenario: Left-hand bias via OSM tags
@ -113,6 +113,6 @@ Feature: Testbot - side bias
And the extract extra arguments "--location-dependent-data test/data/regions/null-island.geojson" And the extract extra arguments "--location-dependent-data test/data/regions/null-island.geojson"
When I route I should get When I route I should get
| from | to | route | time | | from | to | route | driving_side | time |
| d | a | bd,ab,ab | 27s +-1 | | d | a | bd,ab,ab | right,right,right | 27s +-1 |
| d | c | bd,bc,bc | 24s +-1 | | d | c | bd,bc,bc | right,right,right | 24s +-1 |

View File

@ -5,7 +5,7 @@ Feature: Basic Roundabout
Given a grid size of 10 meters Given a grid size of 10 meters
Given the profile file "car" initialized with Given the profile file "car" initialized with
""" """
profile.left_hand_driving = true profile.properties.left_hand_driving = true
""" """
Scenario: Roundabout exit counting for left sided driving Scenario: Roundabout exit counting for left sided driving

View File

@ -267,6 +267,10 @@ module.exports = function () {
return this.extractInstructionList(instructions, s => s.mode); return this.extractInstructionList(instructions, s => s.mode);
}; };
this.drivingSideList = (instructions) => {
return this.extractInstructionList(instructions, s => s.driving_side);
};
this.classesList = (instructions) => { this.classesList = (instructions) => {
return this.extractInstructionList(instructions, s => '[' + s.intersections.map(i => '(' + (i.classes ? i.classes.join(',') : '') + ')').join(',') + ']'); return this.extractInstructionList(instructions, s => '[' + s.intersections.map(i => '(' + (i.classes ? i.classes.join(',') : '') + ')').join(',') + ']');
}; };

View File

@ -35,7 +35,8 @@ module.exports = function () {
if (err) return cb(err); if (err) return cb(err);
if (body && body.length) { if (body && body.length) {
let destinations, exits, pronunciations, instructions, refs, bearings, turns, modes, times, classes, let destinations, exits, pronunciations, instructions, refs, bearings, turns, modes, times, classes,
distances, summary, intersections, lanes, locations, annotation, weight_name, weights, approaches; distances, summary, intersections, lanes, locations, annotation, weight_name, weights, approaches,
driving_sides;
let json = JSON.parse(body); let json = JSON.parse(body);
@ -53,6 +54,7 @@ module.exports = function () {
turns = this.turnList(json.routes[0]); turns = this.turnList(json.routes[0]);
intersections = this.intersectionList(json.routes[0]); intersections = this.intersectionList(json.routes[0]);
modes = this.modeList(json.routes[0]); modes = this.modeList(json.routes[0]);
driving_sides = this.drivingSideList(json.routes[0]);
classes = this.classesList(json.routes[0]); classes = this.classesList(json.routes[0]);
times = this.timeList(json.routes[0]); times = this.timeList(json.routes[0]);
distances = this.distanceList(json.routes[0]); distances = this.distanceList(json.routes[0]);
@ -186,6 +188,10 @@ module.exports = function () {
putValue('weight', weight); putValue('weight', weight);
putValue('approach', approaches); putValue('approach', approaches);
if (driving_sides) {
putValue('driving_side', driving_sides);
}
for (var key in row) { for (var key in row) {
if (this.FuzzyMatch.match(got[key], row[key])) { if (this.FuzzyMatch.match(got[key], row[key])) {
got[key] = row[key]; got[key] = row[key];

View File

@ -141,7 +141,8 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
maneuver, maneuver,
leg_geometry.FrontIndex(segment_index), leg_geometry.FrontIndex(segment_index),
leg_geometry.BackIndex(segment_index) + 1, leg_geometry.BackIndex(segment_index) + 1,
{intersection}}); {intersection},
path_point.is_left_hand_driving});
if (leg_data_index + 1 < leg_data.size()) if (leg_data_index + 1 < leg_data.size())
{ {
@ -219,7 +220,8 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
maneuver, maneuver,
leg_geometry.FrontIndex(segment_index), leg_geometry.FrontIndex(segment_index),
leg_geometry.BackIndex(segment_index) + 1, leg_geometry.BackIndex(segment_index) + 1,
{intersection}}); {intersection},
facade.IsLeftHandDriving(target_node_id)});
} }
// In this case the source + target are on the same edge segment // In this case the source + target are on the same edge segment
else else
@ -261,7 +263,8 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
std::move(maneuver), std::move(maneuver),
leg_geometry.FrontIndex(segment_index), leg_geometry.FrontIndex(segment_index),
leg_geometry.BackIndex(segment_index) + 1, leg_geometry.BackIndex(segment_index) + 1,
{intersection}}); {intersection},
facade.IsLeftHandDriving(source_node_id)});
} }
BOOST_ASSERT(segment_index == number_of_segments - 1); BOOST_ASSERT(segment_index == number_of_segments - 1);
@ -301,7 +304,8 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
std::move(maneuver), std::move(maneuver),
leg_geometry.locations.size() - 1, leg_geometry.locations.size() - 1,
leg_geometry.locations.size(), leg_geometry.locations.size(),
{intersection}}); {intersection},
facade.IsLeftHandDriving(source_node_id)});
BOOST_ASSERT(steps.front().intersections.size() == 1); BOOST_ASSERT(steps.front().intersections.size() == 1);
BOOST_ASSERT(steps.front().intersections.front().bearings.size() == 1); BOOST_ASSERT(steps.front().intersections.front().bearings.size() == 1);

View File

@ -76,6 +76,7 @@ struct RouteStep
std::size_t geometry_begin; std::size_t geometry_begin;
std::size_t geometry_end; std::size_t geometry_end;
std::vector<IntermediateIntersection> intersections; std::vector<IntermediateIntersection> intersections;
bool is_left_hand_driving;
// remove all information from the route step, marking it as invalid (used to indicate empty // remove all information from the route step, marking it as invalid (used to indicate empty
// steps to be removed). // steps to be removed).
@ -129,6 +130,7 @@ inline void RouteStep::Invalidate()
geometry_end = 0; geometry_end = 0;
intersections.clear(); intersections.clear();
intersections.push_back(getInvalidIntersection()); intersections.push_back(getInvalidIntersection());
is_left_hand_driving = false;
} }
// Elongate by another step in front // Elongate by another step in front

View File

@ -57,6 +57,9 @@ struct PathData
util::guidance::TurnBearing pre_turn_bearing; util::guidance::TurnBearing pre_turn_bearing;
// bearing (as seen from the intersection) post-turn // bearing (as seen from the intersection) post-turn
util::guidance::TurnBearing post_turn_bearing; util::guidance::TurnBearing post_turn_bearing;
// Driving side of the turn
bool is_left_hand_driving;
}; };
struct InternalRouteResult struct InternalRouteResult

View File

@ -185,6 +185,8 @@ void annotatePath(const FacadeT &facade,
: 0); : 0);
const std::size_t end_index = weight_vector.size(); const std::size_t end_index = weight_vector.size();
bool is_left_hand_driving = facade.IsLeftHandDriving(node_id);
BOOST_ASSERT(start_index >= 0); BOOST_ASSERT(start_index >= 0);
BOOST_ASSERT(start_index < end_index); BOOST_ASSERT(start_index < end_index);
for (std::size_t segment_idx = start_index; segment_idx < end_index; ++segment_idx) for (std::size_t segment_idx = start_index; segment_idx < end_index; ++segment_idx)
@ -202,7 +204,8 @@ void annotatePath(const FacadeT &facade,
EMPTY_ENTRY_CLASS, EMPTY_ENTRY_CLASS,
datasource_vector[segment_idx], datasource_vector[segment_idx],
util::guidance::TurnBearing(0), util::guidance::TurnBearing(0),
util::guidance::TurnBearing(0)}); util::guidance::TurnBearing(0),
is_left_hand_driving});
} }
BOOST_ASSERT(unpacked_path.size() > 0); BOOST_ASSERT(unpacked_path.size() > 0);
if (facade.HasLaneData(turn_id)) if (facade.HasLaneData(turn_id))
@ -254,6 +257,7 @@ void annotatePath(const FacadeT &facade,
// t: fwd_segment 3 // t: fwd_segment 3
// -> (U, v), (v, w), (w, x) // -> (U, v), (v, w), (w, x)
// note that (x, t) is _not_ included but needs to be added later. // note that (x, t) is _not_ included but needs to be added later.
bool is_target_left_hand_driving = facade.IsLeftHandDriving(target_node_id);
for (std::size_t segment_idx = start_index; segment_idx != end_index; for (std::size_t segment_idx = start_index; segment_idx != end_index;
(start_index < end_index ? ++segment_idx : --segment_idx)) (start_index < end_index ? ++segment_idx : --segment_idx))
{ {
@ -273,7 +277,8 @@ void annotatePath(const FacadeT &facade,
EMPTY_ENTRY_CLASS, EMPTY_ENTRY_CLASS,
datasource_vector[segment_idx], datasource_vector[segment_idx],
util::guidance::TurnBearing(0), util::guidance::TurnBearing(0),
util::guidance::TurnBearing(0)}); util::guidance::TurnBearing(0),
is_target_left_hand_driving});
} }
if (unpacked_path.size() > 0) if (unpacked_path.size() > 0)

View File

@ -563,7 +563,7 @@ function WayHandlers.driving_side(profile, way, result, data)
elseif driving_side == 'right' then elseif driving_side == 'right' then
result.is_left_hand_driving = false result.is_left_hand_driving = false
else else
result.is_left_hand_driving = profile.left_hand_driving result.is_left_hand_driving = profile.properties.left_hand_driving
end end
end end

View File

@ -195,6 +195,7 @@ util::json::Object makeRouteStep(guidance::RouteStep step, util::json::Value geo
route_step.values["mode"] = extractor::travelModeToString(std::move(step.mode)); route_step.values["mode"] = extractor::travelModeToString(std::move(step.mode));
route_step.values["maneuver"] = makeStepManeuver(std::move(step.maneuver)); route_step.values["maneuver"] = makeStepManeuver(std::move(step.maneuver));
route_step.values["geometry"] = std::move(geometry); route_step.values["geometry"] = std::move(geometry);
route_step.values["driving_side"] = step.is_left_hand_driving ? "left" : "right";
util::json::Array intersections; util::json::Array intersections;
intersections.values.reserve(step.intersections.size()); intersections.values.reserve(step.intersections.size());

View File

@ -64,6 +64,7 @@ BOOST_AUTO_TEST_CASE(test_route_same_coordinates_fixture)
{"geometry", "yw_jGupkl@??"}, {"geometry", "yw_jGupkl@??"},
{"name", "Boulevard du Larvotto"}, {"name", "Boulevard du Larvotto"},
{"mode", "driving"}, {"mode", "driving"},
{"driving_side", "right"},
{"maneuver", {"maneuver",
json::Object{{ json::Object{{
{"location", location}, {"location", location},
@ -84,6 +85,7 @@ BOOST_AUTO_TEST_CASE(test_route_same_coordinates_fixture)
{"geometry", "yw_jGupkl@"}, {"geometry", "yw_jGupkl@"},
{"name", "Boulevard du Larvotto"}, {"name", "Boulevard du Larvotto"},
{"mode", "driving"}, {"mode", "driving"},
{"driving_side", "right"},
{"maneuver", {"maneuver",
json::Object{{{"location", location}, json::Object{{{"location", location},
{"bearing_before", 58}, {"bearing_before", 58},