Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/profiles.md
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,7 @@ angle | Read | Float |
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?
has_turning_facility | Read | Boolean | Is a turning facility (turning_circle, turning_loop, or mini_roundabout) present at this intersection?
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`
Expand Down
190 changes: 190 additions & 0 deletions features/car/turning_circle_uturn.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
@routing @car @turning_circle @uturn
Feature: Car - Use turning circles for u-turns

Background:
Given the profile "car"

Scenario: Car - Should use turning_circle for u-turn when direct u-turn is restricted
Given the node map
"""
a---b---c---e
|
d
"""

And the ways
| nodes | highway |
| abce | primary |
| bd | primary |

And the nodes
| node | highway |
| d | turning_circle |

And the relations
| type | way:from | node:via | way:to | restriction |
| restriction | abce | b | abce | no_u_turn |

When I route I should get
| waypoints | bearings | route | turns |
| a,a | 90,10 270,10 | abce,bd,bd,abce,abce | depart,turn right,continue uturn,turn left,arrive |

Scenario: Car - Should use turning_loop for u-turn when direct u-turn is restricted
Given the node map
"""
a---b---c---d
|
e
"""

And the ways
| nodes | highway |
| abcd | primary |
| be | primary |

And the nodes
| node | highway |
| e | turning_loop |

And the relations
| type | way:from | node:via | way:to | restriction |
| restriction | abcd | b | abcd | no_u_turn |

When I route I should get
| waypoints | bearings | route | turns |
| a,a | 90,10 270,10 | abcd,be,be,abcd,abcd | depart,turn right,continue uturn,turn left,arrive |

Scenario: Car - Should use mini_roundabout for u-turn when direct u-turn is restricted
Given the node map
"""
a---b---c---d
|
e
"""

And the ways
| nodes | highway |
| abcd | primary |
| be | primary |

And the nodes
| node | highway |
| e | mini_roundabout |

And the relations
| type | way:from | node:via | way:to | restriction |
| restriction | abcd | b | abcd | no_u_turn |

When I route I should get
| waypoints | bearings | route | turns |
| a,a | 90,10 270,10 | abcd,be,be,abcd,abcd | depart,turn right,continue uturn,turn left,arrive |

Scenario: Car - Prefer turning_circle over plain dead end for u-turn
Given the node map
"""
c
|
a---b
|
d
"""

And the ways
| nodes | highway |
| ab | primary |
| bc | primary |
| bd | primary |

And the nodes
| node | highway |
| d | turning_circle |

And the relations
| type | way:from | node:via | way:to | restriction |
| restriction | ab | b | ab | no_u_turn |

When I route I should get
| waypoints | bearings | route | turns |
| a,a | 90,10 270,10 | ab,bd,bd,ab,ab | depart,turn right,continue uturn,turn left,arrive |

Scenario: Car - Multiple turning facilities, use closest
Given the node map
"""
a---b---c---d---e
| |
f g
"""

And the ways
| nodes | highway |
| abcde | primary |
| bf | primary |
| dg | primary |

And the nodes
| node | highway |
| f | turning_circle |
| g | turning_loop |

When I route I should get
| waypoints | bearings | route | turns |
| a,a | 90,10 270,10 | abcde,bf,bf,abcde,abcde | depart,turn right,continue uturn,turn left,arrive |

Scenario: Car - Dead end with turning_circle
Given the node map
"""
a---b---c
|
d
"""

And the ways
| nodes | highway |
| abc | primary |
| cd | primary |

And the nodes
| node | highway |
| d | turning_circle |

When I route I should get
| waypoints | route | turns |
| a,d | abc,cd,cd | depart,new name right,arrive |
| d,a | cd,abc,abc | depart,new name left,arrive |

Scenario: Car - Regular u-turn without turning facility still penalized
Given the node map
"""
a---b---c---d
"""

And the ways
| nodes | highway |
| abcd | primary |

# Note: No turning facility nodes defined

When I route I should get
| waypoints | bearings | route | turns |
| a,a | 90,10 270,10 | abcd,abcd,abcd | depart,continue uturn,arrive |

Scenario: Car - Turning circle on one-way should respect direction
Given the node map
"""
a---b---c
|
d
"""

And the ways
| nodes | highway | oneway |
| abc | primary | no |
| bd | primary | yes |

And the nodes
| node | highway |
| d | turning_circle |

When I route I should get
| waypoints | bearings | route | turns |
| a,a | 90,10 270,10 | abc,abc,abc | depart,continue uturn,arrive |
4 changes: 2 additions & 2 deletions features/step_definitions/distance_matrix.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ async function tableCodeOnlyParse(table, annotation, format) {
let got;

await this.reprocessAndLoadData();
const testRow = function (row, ri) {
const testRow = function (row, _ri) {
return new Promise((resolve, reject) => {
const afterRequest = function (err, res, body) {
if (err) return reject(err);
Expand Down Expand Up @@ -174,7 +174,7 @@ async function tableParse(table, noRoute, annotation, format) {
await this.reprocessAndLoadData();
// compute matrix

const { response, body } = await new Promise((resolve, reject) => {
const { body } = await new Promise((resolve, reject) => {
this.requestTable(waypoints, params, (err, response, body) => {
if (err) return reject(err);
resolve({ response, body });
Expand Down
2 changes: 1 addition & 1 deletion features/step_definitions/matching.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ When(/^I match I should get$/, async function (table) {
let got;

await this.reprocessAndLoadData();
const testRow = function (row, ri) {
const testRow = function (row, _ri) {
return new Promise((resolve, reject) => {
const afterRequest = function (err, res, body) {
if (err) return reject(err);
Expand Down
4 changes: 2 additions & 2 deletions features/step_definitions/nearest.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { When } from '@cucumber/cucumber';

When(/^I request nearest I should get$/, async function (table) {
await this.reprocessAndLoadData();
const testRow = function (row, ri) {
const testRow = function (row, _ri) {
return new Promise((resolve, reject) => {
const inNode = this.findNodeByName(row.in);
if (!inNode) return reject(new Error(util.format('*** unknown in-node "%s"', row.in)));
Expand Down Expand Up @@ -79,7 +79,7 @@ When(/^I request nearest I should get$/, async function (table) {

When(/^I request nearest with flatbuffers I should get$/, async function (table) {
await this.reprocessAndLoadData();
const testRow = function (row, ri) {
const testRow = function (row, _ri) {
return new Promise((resolve, reject) => {
const inNode = this.findNodeByName(row.in);
if (!inNode) return reject(new Error(util.format('*** unknown in-node "%s"', row.in)));
Expand Down
2 changes: 1 addition & 1 deletion features/step_definitions/trip.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ When(/^I plan a trip I should get$/, async function (table) {
let got;

await this.reprocessAndLoadData();
const testRow = function (row, ri) {
const testRow = function (row, _ri) {
return new Promise((resolve, reject) => {
const afterRequest = function (err, res, body) {
if (err) return reject(err);
Expand Down
9 changes: 7 additions & 2 deletions include/extractor/extraction_turn.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ struct ExtractionTurn
int number_of_roads,
bool is_u_turn,
bool has_traffic_light,
bool has_turning_facility,
bool is_left_hand_driving,

bool source_restricted,
Expand Down Expand Up @@ -112,7 +113,8 @@ struct ExtractionTurn
const NodeID via,
const NodeID to)
: angle(180. - angle), number_of_roads(number_of_roads), is_u_turn(is_u_turn),
has_traffic_light(has_traffic_light), is_left_hand_driving(is_left_hand_driving),
has_traffic_light(has_traffic_light), has_turning_facility(has_turning_facility),
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),
Expand Down Expand Up @@ -146,11 +148,13 @@ struct ExtractionTurn
const ExtractionTurnLeg::EdgeData &target_edge,
const std::vector<ExtractionTurnLeg> &roads_on_the_right,
const std::vector<ExtractionTurnLeg> &roads_on_the_left,
const bool has_traffic_light)
const bool has_traffic_light,
const bool has_turning_facility)
: ExtractionTurn{0,
2,
false,
has_traffic_light,
has_turning_facility,
false,
// source
false,
Expand Down Expand Up @@ -187,6 +191,7 @@ struct ExtractionTurn
const int number_of_roads;
const bool is_u_turn;
const bool has_traffic_light;
const bool has_turning_facility;
const bool is_left_hand_driving;

// source info
Expand Down
7 changes: 7 additions & 0 deletions include/extractor/obstacles.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,13 @@ class ObstacleMap
// inexpensive general test
bool any(NodeID to) const { return obstacles.contains(to); }

// is there any obstacle of type 'type' at node 'to' (from any direction)?
// 'type' can be a bitwise-or combination of Obstacle::Type
bool any(NodeID to, Obstacle::Type type) const
{
return any(to) && !get(SPECIAL_NODEID, to, type).empty();
}

// is there any obstacle of type 'type' at node 'to' when coming from node 'from'?
// pass SPECIAL_NODEID as 'from' to query all obstacles at 'to'
// 'type' can be a bitwise-or combination of Obstacle::Type
Expand Down
11 changes: 10 additions & 1 deletion profiles/car.lua
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ function setup()
speed_reduction = 0.8,
turn_bias = 1.075,
cardinal_directions = false,
-- Penalty in seconds for u-turns at designated turning facilities
-- (highway=turning_circle, turning_loop, mini_roundabout).
-- Lower than u_turn_penalty because these nodes are specifically designed for turning around.
turning_circle_penalty = 5,

-- Penalty multiplier for roads with no lane markings (lane_markings=no)
-- Applied to bidirectional roads to prefer roads with clear lane markings
Expand Down Expand Up @@ -538,7 +542,12 @@ function process_turn(profile, turn)
end

if turn.is_u_turn then
turn.duration = turn.duration + profile.properties.u_turn_penalty
if turn.has_turning_facility then
-- No regular u-turn penalty at designated turning facilities (turning_circle, turning_loop, mini_roundabout)
turn.duration = turn.duration + profile.turning_circle_penalty
else
turn.duration = turn.duration + profile.properties.u_turn_penalty
end
end
end

Expand Down
14 changes: 13 additions & 1 deletion profiles/lib/obstacles.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,24 @@

local Obstacles = {}

-- Mapping from highway tag values to obstacle types
local highway_to_obstacle_type = {
["traffic_signals"] = obstacle_type.traffic_signals,
["stop"] = obstacle_type.stop,
["give_way"] = obstacle_type.give_way,
["crossing"] = obstacle_type.crossing,
["traffic_calming"] = obstacle_type.traffic_calming,
["mini_roundabout"] = obstacle_type.mini_roundabout,
["turning_loop"] = obstacle_type.turning_loop,
["turning_circle"] = obstacle_type.turning_circle
}

-- process the obstacles at the given node
-- note: does not process barriers
function Obstacles.process_node(profile, node)
local highway = node:get_value_by_key("highway")
if highway then
local type = obstacle_type[highway]
local type = highway_to_obstacle_type[highway]
-- barriers already handled in car.lua
if type and type ~= obstacle_type.barrier then
local direction = node:get_value_by_key("direction")
Expand Down
3 changes: 3 additions & 0 deletions src/extractor/edge_based_graph_factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
// node. But we'll check anyway.
const bool is_traffic_light = scripting_environment.m_obstacle_map.any(
node_along_road_entering, intersection_node, Obstacle::Type::TrafficSignals);
const bool has_turning_facility = scripting_environment.m_obstacle_map.any(
intersection_node, Obstacle::Type::Turning);
const bool is_uturn =
guidance::getTurnDirection(turn_angle) == guidance::DirectionModifier::UTurn;

Expand All @@ -631,6 +633,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
is_uturn),
is_uturn,
is_traffic_light,
has_turning_facility,
m_edge_based_node_container.GetAnnotation(edge_data1.annotation_data)
.is_left_hand_driving,
// source info
Expand Down
Loading
Loading