profiles: Directional helper, some car refactoring

This commit is contained in:
Emil Tin 2016-11-18 20:49:51 +01:00 committed by Daniel J. H
parent 0fbd18b0dd
commit 532cbfce13
6 changed files with 334 additions and 274 deletions

View File

@ -149,6 +149,7 @@ Feature: Car - Restricted access
| runway | | | | yes | | | runway | | | | yes | |
| primary | | | | no | x | | primary | | | | no | x |
@hov
Scenario: Car - only designated HOV ways are ignored by default Scenario: Car - only designated HOV ways are ignored by default
Then routability should be Then routability should be
| highway | hov | bothw | | highway | hov | bothw |
@ -156,6 +157,7 @@ Feature: Car - Restricted access
| primary | yes | x | | primary | yes | x |
| primary | no | x | | primary | no | x |
@hov
Scenario: Car - a way with all lanes HOV-designated is inaccessible by default (similar to hov=designated) Scenario: Car - a way with all lanes HOV-designated is inaccessible by default (similar to hov=designated)
Then routability should be Then routability should be
| highway | hov:lanes:forward | hov:lanes:backward | hov:lanes | oneway | forw | backw | | highway | hov:lanes:forward | hov:lanes:backward | hov:lanes | oneway | forw | backw |
@ -166,8 +168,8 @@ Feature: Car - Restricted access
| primary | designated\|no | designated\|no | | | x | x | | primary | designated\|no | designated\|no | | | x | x |
| primary | yes\|no | yes\|no | | | x | x | | primary | yes\|no | yes\|no | | | x | x |
| primary | | | | | x | x | | primary | | | | | x | x |
| primary | designated | | | -1 | | | | primary | designated | | | -1 | | x |
| primary | | designated | | -1 | | x | | primary | | designated | | -1 | | |
| primary | | | designated | yes | | | | primary | | | designated | yes | | |
| primary | | | designated | -1 | | | | primary | | | designated | -1 | | |
| primary | | | designated\| | yes | x | | | primary | | | designated\| | yes | x | |

View File

@ -123,3 +123,14 @@ OSRM will use 4/5 of the projected free-flow speed.
| primary | 30 | 1 | -1 | | 23 km/h | | primary | 30 | 1 | -1 | | 23 km/h |
| primary | 30 | 1 | | 15 km/h | 15 km/h | | primary | 30 | 1 | | 15 km/h | 15 km/h |
| primary | 30 | 2 | | 23 km/h | 23 km/h | | primary | 30 | 2 | | 23 km/h | 23 km/h |
Scenario: Car - Forwward/backward maxspeed on reverse oneways
Then routability should be
| highway | maxspeed | maxspeed:forward | maxspeed:backward | oneway | forw | backw |
| primary | | | | -1 | | 52 km/h |
| primary | 30 | | | -1 | | 23 km/h |
| primary | | 30 | | -1 | | 52 km/h |
| primary | | | 30 | -1 | | 23 km/h |
| primary | 20 | 30 | | -1 | | 16 km/h |
| primary | 20 | | 30 | -1 | | 23 km/h |

View File

@ -5,6 +5,7 @@ local set_classification = require("lib/guidance").set_classification
local get_turn_lanes = require("lib/guidance").get_turn_lanes local get_turn_lanes = require("lib/guidance").get_turn_lanes
local Set = require('lib/set') local Set = require('lib/set')
local Sequence = require('lib/sequence') local Sequence = require('lib/sequence')
local Directional = require('lib/directional')
-- Begin of globals -- Begin of globals
barrier_whitelist = Set { barrier_whitelist = Set {
@ -287,69 +288,51 @@ end
-- abort early if this way is obviouslt not routable -- abort early if this way is obviouslt not routable
function initial_routability_check(way,result,data) function initial_routability_check(way,result,data)
data.speed_type = way:get_value_by_key('highway') data.highway = way:get_value_by_key('highway')
return data.speed_type ~= nil or return data.highway ~= nil or
way:get_value_by_key('route') ~= nil or way:get_value_by_key('route') ~= nil or
way:get_value_by_key('bridge') ~= nil way:get_value_by_key('bridge') ~= nil
end end
-- handle high occupancy vehicle tags -- all lanes restricted to hov vehicles?
function handle_hov(way,result) local function has_all_designated_hov_lanes(lanes)
-- respect user-preference for HOV-only ways if not lanes then
if ignore_hov_ways then return false
local hov = way:get_value_by_key("hov") end
if "designated" == hov then -- This gmatch call effectively splits the string on | chars.
-- we append an extra | to the end so that we can match the final part
for lane in (lanes .. '|'):gmatch("([^|]*)|") do
if lane and lane ~= "designated" then
return false return false
end end
end
return true
end
-- also respect user-preference for HOV-only ways when all lanes are HOV-designated -- handle high occupancy vehicle tags
local function has_all_designated_hov_lanes(lanes) function handle_hov(way,result,data)
local all = true -- respect user-preference for HOV
-- This gmatch call effectively splits the string on | chars. if not ignore_hov_ways then
-- we append an extra | to the end so that we can match the final part return
for lane in (lanes .. '|'):gmatch("([^|]*)|") do end
if lane and lane ~= "designated" then
all = false
break
end
end
return all
end
local hov_lanes = way:get_value_by_key("hov:lanes") -- check if way is hov only
local hov_lanes_forward = way:get_value_by_key("hov:lanes:forward") local hov = way:get_value_by_key("hov")
local hov_lanes_backward = way:get_value_by_key("hov:lanes:backward") if "designated" == hov then
return false
end
local hov_all_designated = hov_lanes and -- check if all lanes are hov only
has_all_designated_hov_lanes(hov_lanes) local hov_lanes_forward, hov_lanes_backward = Directional.get_values_by_key(way,data,'hov:lanes')
local inaccessible_forward = has_all_designated_hov_lanes(hov_lanes_forward)
local hov_all_designated_forward = hov_lanes_forward and local inaccessible_backward = has_all_designated_hov_lanes(hov_lanes_backward)
has_all_designated_hov_lanes(hov_lanes_forward)
local hov_all_designated_backward = hov_lanes_backward and
has_all_designated_hov_lanes(hov_lanes_backward)
-- forward/backward lane depend on a way's direction
local oneway = way:get_value_by_key("oneway")
local reverse = oneway == "-1"
if hov_all_designated or hov_all_designated_forward then
if reverse then
result.backward_mode = mode.inaccessible
else
result.forward_mode = mode.inaccessible
end
end
if hov_all_designated_backward then
if reverse then
result.forward_mode = mode.inaccessible
else
result.backward_mode = mode.inaccessible
end
end
if inaccessible_forward then
result.forward_mode = mode.inaccessible
end
if inaccessible_backward then
result.backward_mode = mode.inaccessible
end end
end end
@ -440,18 +423,11 @@ end
-- handle speed (excluding maxspeed) -- handle speed (excluding maxspeed)
function handle_speed(way,result,data) function handle_speed(way,result,data)
if result.forward_speed == -1 then if result.forward_speed == -1 then
local highway_speed = speed_profile[way:get_value_by_key("highway")] local highway_speed = speed_profile[data.highway]
local max_speed = parse_maxspeed( way:get_value_by_key("maxspeed") )
-- Set the avg speed on the way if it is accessible by road class -- Set the avg speed on the way if it is accessible by road class
if highway_speed then if highway_speed then
if max_speed and max_speed > highway_speed then result.forward_speed = highway_speed
result.forward_speed = max_speed result.backward_speed = highway_speed
result.backward_speed = max_speed
-- max_speed = math.huge
else
result.forward_speed = highway_speed
result.backward_speed = highway_speed
end
else else
-- Set the avg speed on ways that are marked accessible -- Set the avg speed on ways that are marked accessible
if access_tag_whitelist[data.access] then if access_tag_whitelist[data.access] then
@ -459,11 +435,6 @@ function handle_speed(way,result,data)
result.backward_speed = speed_profile["default"] result.backward_speed = speed_profile["default"]
end end
end end
if 0 == max_speed then
max_speed = math.huge
end
result.forward_speed = min(result.forward_speed, max_speed)
result.backward_speed = min(result.backward_speed, max_speed)
end end
if -1 == result.forward_speed and -1 == result.backward_speed then if -1 == result.forward_speed and -1 == result.backward_speed then
@ -472,7 +443,7 @@ function handle_speed(way,result,data)
if handle_side_roads(way,result) == false then return false end if handle_side_roads(way,result) == false then return false end
if handle_surface(way,result) == false then return false end if handle_surface(way,result) == false then return false end
if handle_maxspeed(way,result) == false then return false end if handle_maxspeed(way,data,result) == false then return false end
if handle_speed_scaling(way,result) == false then return false end if handle_speed_scaling(way,result) == false then return false end
if handle_alternating_speed(way,result) == false then return false end if handle_alternating_speed(way,result) == false then return false end
end end
@ -529,23 +500,15 @@ function handle_names(way,result)
end end
-- handle turn lanes -- handle turn lanes
function handle_turn_lanes(way,result) function handle_turn_lanes(way,result,data)
local turn_lanes = '' local forward, backward = get_turn_lanes(way,data)
local turn_lanes_forward = ''
local turn_lanes_backward = ''
turn_lanes, turn_lanes_forward, turn_lanes_backward = get_turn_lanes(way) if forward then
if turn_lanes and turn_lanes ~= '' then result.turn_lanes_forward = forward
result.turn_lanes_forward = turn_lanes; end
result.turn_lanes_backward = turn_lanes;
else
if turn_lanes_forward and turn_lanes_forward ~= '' then
result.turn_lanes_forward = turn_lanes_forward;
end
if turn_lanes_backward and turn_lanes_backward ~= '' then if backward then
result.turn_lanes_backward = turn_lanes_backward; result.turn_lanes_backward = backward
end
end end
end end
@ -633,69 +596,55 @@ function handle_speed_scaling(way,result)
end end
end end
-- oneways -- handle oneways tags
function handle_oneway(way,result) function handle_oneway(way,result,data)
local oneway = way:get_value_by_key("oneway") local oneway = way:get_value_by_key("oneway")
data.oneway = oneway
if obey_oneway then if obey_oneway then
if oneway == "-1" then if oneway == "-1" then
data.is_reverse_oneway = true
result.forward_mode = mode.inaccessible result.forward_mode = mode.inaccessible
local is_forward = false
local destination = get_destination(way, is_forward)
result.destinations = canonicalizeStringList(destination, ",")
elseif oneway == "yes" or elseif oneway == "yes" or
oneway == "1" or oneway == "1" or
oneway == "true" or oneway == "true" then
way:get_value_by_key("junction") == "roundabout" or data.is_forward_oneway = true
way:get_value_by_key("junction") == "circular" or
(way:get_value_by_key("highway") == "motorway" and oneway ~= "no") then
result.backward_mode = mode.inaccessible result.backward_mode = mode.inaccessible
else
local is_forward = true local junction = way:get_value_by_key("junction")
local destination = get_destination(way, is_forward) if data.highway == "motorway" or
result.destinations = canonicalizeStringList(destination, ",") junction == "roundabout" or
junction == "circular" then
if oneway ~= "no" then
-- implied oneway
data.is_forward_oneway = true
result.backward_mode = mode.inaccessible
end
end
end end
end end
end end
-- maxspeed and advisory maxspeed -- handle destination tags
function handle_maxspeed(way,result) function handle_destinations(way,result,data)
-- Override speed settings if explicit forward/backward maxspeeds are given if data.is_forward_oneway or data.is_reverse_oneway then
local maxspeed_forward = parse_maxspeed(way:get_value_by_key("maxspeed:forward")) local destination = get_destination(way, data.is_forward_oneway)
local maxspeed_backward = parse_maxspeed(way:get_value_by_key("maxspeed:backward")) result.destinations = canonicalizeStringList(destination, ",")
if maxspeed_forward and maxspeed_forward > 0 then
if mode.inaccessible ~= result.forward_mode and
mode.inaccessible ~= result.backward_mode then
result.backward_speed = result.forward_speed
end
result.forward_speed = maxspeed_forward
end end
if maxspeed_backward and maxspeed_backward > 0 then end
result.backward_speed = maxspeed_backward
-- maxspeed and advisory maxspeed
function handle_maxspeed(way,data,result)
local keys = Sequence { 'maxspeed:advisory', 'maxspeed' }
local forward, backward = Directional.get_values_by_set(way,data,keys)
forward = parse_maxspeed(forward)
backward = parse_maxspeed(backward)
if forward and forward > 0 then
result.forward_speed = forward
end end
-- Override speed settings if advisory forward/backward maxspeeds are given if backward and backward > 0 then
local advisory_speed = parse_maxspeed(way:get_value_by_key("maxspeed:advisory")) result.backward_speed = backward
local advisory_forward = parse_maxspeed(way:get_value_by_key("maxspeed:advisory:forward"))
local advisory_backward = parse_maxspeed(way:get_value_by_key("maxspeed:advisory:backward"))
-- apply bi-directional advisory speed first
if advisory_speed and advisory_speed > 0 then
if mode.inaccessible ~= result.forward_mode then
result.forward_speed = advisory_speed
end
if mode.inaccessible ~= result.backward_mode then
result.backward_speed = advisory_speed
end
end
if advisory_forward and advisory_forward > 0 then
if mode.inaccessible ~= result.forward_mode and mode.inaccessible ~= result.backward_mode then
result.backward_speed = result.forward_speed
end
result.forward_speed = advisory_forward
end
if advisory_backward and advisory_backward > 0 then
result.backward_speed = advisory_backward
end end
end end
@ -713,6 +662,7 @@ function handle_alternating_speed(way,result)
end end
end end
-- determine if this way can be used as a start/end point for routing -- determine if this way can be used as a start/end point for routing
function handle_startpoint(way,result) function handle_startpoint(way,result)
-- only allow this road as start point if it not a ferry -- only allow this road as start point if it not a ferry
@ -721,8 +671,8 @@ function handle_startpoint(way,result)
end end
-- set the road classification based on guidance globals configuration -- set the road classification based on guidance globals configuration
function handle_classification(way,result) function handle_classification(way,result,data)
set_classification(way:get_value_by_key("highway"),result,way) set_classification(data.highway,result,way)
end end
-- main entry point for processsing a way -- main entry point for processsing a way
@ -754,8 +704,11 @@ function way_function(way, result)
-- access tags, e.g: motorcar, motor_vehicle, vehicle -- access tags, e.g: motorcar, motor_vehicle, vehicle
if handle_access(way,result,data) == false then return end if handle_access(way,result,data) == false then return end
-- check high occupancy vehicle restrictions -- check whether forward/backward directons are routable
if handle_hov(way,result) == false then return end if handle_oneway(way,result,data) == false then return end
-- check whether forward/backward directons are routable
if handle_destinations(way,result,data) == false then return end
-- check whether we're using a special transport mode -- check whether we're using a special transport mode
if handle_ferries(way,result) == false then return end if handle_ferries(way,result) == false then return end
@ -764,24 +717,21 @@ function way_function(way, result)
-- handle service road restrictions -- handle service road restrictions
if handle_service(way,result) == false then return end if handle_service(way,result) == false then return end
-- check whether forward/backward directons are routable -- check high occupancy vehicle restrictions
if handle_oneway(way,result) == false then return end if handle_hov(way,result,data) == false then return end
-- compute speed taking into account way type, maxspeed tags, etc. -- compute speed taking into account way type, maxspeed tags, etc.
if handle_speed(way,result,data) == false then return end if handle_speed(way,result,data) == false then return end
-- handle turn lanes and road classification, used for guidance -- handle turn lanes and road classification, used for guidance
if handle_turn_lanes(way,result) == false then return end if handle_turn_lanes(way,result,data) == false then return end
if handle_classification(way,result) == false then return end if handle_classification(way,result,data) == false then return end
-- handle various other flags -- handle various other flags
if handle_roundabouts(way,result) == false then return end if handle_roundabouts(way,result) == false then return end
if handle_startpoint(way,result) == false then return end if handle_startpoint(way,result) == false then return end
if handle_restricted(way,result,data) == false then return end if handle_restricted(way,result,data) == false then return end
-- handle roundabout flags
if handle_roundabouts(way,result) == false then return end
-- check if this way can be routed through, but not used as -- check if this way can be routed through, but not used as
-- origin or destination -- origin or destination
if handle_restricted(way,result,data) == false then return end if handle_restricted(way,result,data) == false then return end

View File

@ -56,13 +56,32 @@ local way = {
--route = 'ferry', --route = 'ferry',
--duration = '00:01:00', --duration = '00:01:00',
--hov = 'designated', --hov = 'designated',
["hov:lanes:forward"] = 'designated',
--access = 'no' --access = 'no'
--destination = 'Berlin', --destination = 'Berlin',
["destination:ref"] = 'Nuremberg', --["destination:ref"] = 'Nuremberg',
--["destination:ref:forward"] = 'Hamburg;Dresden', --["destination:ref:forward"] = 'Hamburg;Dresden',
} }
-- tag function normally provided via C++ -- tag function normally provided via C++
function way:get_value_by_key(k) function way:get_value_by_key(k)
if not self['_debug'] then
self['_debug'] = {
_counts = {}
}
end
if self['_debug']['_total'] then
self['_debug']['_total'] = self['_debug']['_total'] + 1
else
self['_debug']['_total'] = 1
end
if self['_debug']['_counts'][k] then
self['_debug']['_counts'][k] = self['_debug']['_counts'][k] + 1
else
self['_debug']['_counts'][k] = 1
end
return self[k] return self[k]
end end
@ -83,6 +102,27 @@ function canonicalizeStringList(str)
return str return str
end end
-- helpers for sorting associative array
function get_keys_sorted_by_value(tbl, sortFunction)
local keys = {}
for key in pairs(tbl) do
table.insert(keys, key)
end
table.sort(keys, function(a, b)
return sortFunction(tbl[a], tbl[b])
end)
return keys
end
-- helper for printing sorted array
function print_sorted(sorted,associative)
for _, key in ipairs(sorted) do
print(associative[key], key)
end
end
-- start state of result table, normally set form C++ -- start state of result table, normally set form C++
local result = { local result = {
road_classification = {}, road_classification = {},
@ -100,3 +140,9 @@ way_function(way,result)
pprint(way) pprint(way)
print("=>") print("=>")
pprint(result) pprint(result)
print("\n")
print("Tag fetches:")
sorted_counts = get_keys_sorted_by_value(way._debug._counts, function(a, b) return a > b end)
print_sorted(sorted_counts, way._debug._counts)
print(way._debug._total, 'total')

View File

@ -0,0 +1,59 @@
local Directional = {}
-- return [forward,backward] values for a specific tag.
-- e.g. for maxspeed search forward:
-- maxspeed:forward
-- maxspeed
-- and backward:
-- maxspeed:backward
-- maxspeed
function Directional.get_values_by_key(way,data,key)
local forward = way:get_value_by_key(key .. ':forward')
local backward = way:get_value_by_key(key .. ':backward')
if forward and backward then
return forward, backward
end
local common = way:get_value_by_key(key)
return forward or common,
backward or common
end
-- return [forward,backward] values, searching a
-- prioritized sequence of tags
-- e.g. for the sequence [maxspeed,advisory] search forward:
-- maxspeed:forward
-- maxspeed
-- advisory:forward
-- advisory
-- and for backward:
-- maxspeed:backward
-- maxspeed
-- advisory:backward
-- advisory
function Directional.get_values_by_set(way,data,keys)
local forward, backward
for i,key in ipairs(keys) do
if not forward then
forward = way:get_value_by_key(key .. ':forward')
end
if not backward then
backward = way:get_value_by_key(key .. ':backward')
end
if not forward or not backward then
local common = way:get_value_by_key(key)
forward = forward or common
backward = backward or common
end
if forward and backward then
break
end
end
return forward, backward
end
return Directional

View File

@ -1,154 +1,146 @@
local Directional = require('lib/directional')
local Set = require('lib/set')
local Guidance = {} local Guidance = {}
-- Guidance: Default Mapping from roads to types/priorities -- Guidance: Default Mapping from roads to types/priorities
highway_classes = { ["motorway"] = road_priority_class.motorway, highway_classes = {
["motorway_link"] = road_priority_class.link_road, motorway = road_priority_class.motorway,
["trunk"] = road_priority_class.trunk, motorway_link = road_priority_class.link_road,
["trunk_link"] = road_priority_class.link_road, trunk = road_priority_class.trunk,
["primary"] = road_priority_class.primary, trunk_link = road_priority_class.link_road,
["primary_link"] = road_priority_class.link_road, primary = road_priority_class.primary,
["secondary"] = road_priority_class.secondary, primary_link = road_priority_class.link_road,
["secondary_link"] = road_priority_class.link_road, secondary = road_priority_class.secondary,
["tertiary"] = road_priority_class.tertiary, secondary_link = road_priority_class.link_road,
["tertiary_link"] = road_priority_class.link_road, tertiary = road_priority_class.tertiary,
["unclassified"] = road_priority_class.side_residential, tertiary_link = road_priority_class.link_road,
["residential"] = road_priority_class.side_residential, unclassified = road_priority_class.side_residential,
["service"] = road_priority_class.connectivity, residential = road_priority_class.side_residential,
["living_street"] = road_priority_class.main_residential, service = road_priority_class.connectivity,
["track"] = road_priority_class.bike_path, living_street = road_priority_class.main_residential,
["path"] = road_priority_class.bike_path, track = road_priority_class.bike_path,
["footway"] = road_priority_class.foot_path, path = road_priority_class.bike_path,
["pedestrian"] = road_priority_class.foot_path, footway = road_priority_class.foot_path,
["steps"] = road_priority_class.foot_path} pedestrian = road_priority_class.foot_path,
steps = road_priority_class.foot_path
}
default_highway_class = road_priority_class.connectivity; default_highway_class = road_priority_class.connectivity;
motorway_types = { ["motorway"] = true, ["motorway_link"] = true, ["trunk"] = true, ["trunk_link"] = true } motorway_types = Set {
'motorway',
'motorway_link',
'trunk',
'trunk_link'
}
-- these road types are set with a car in mind. For bicycle/walk we probably need different ones -- these road types are set with a car in mind. For bicycle/walk we probably need different ones
road_types = { ["motorway"] = true, road_types = Set {
["motorway_link"] = true, 'motorway',
["trunk"] = true, 'motorway_link',
["trunk_link"] = true, 'trunk',
["primary"] = true, 'trunk_link',
["primary_link"] = true, 'primary',
["secondary"] = true, 'primary_link',
["secondary_link"] = true, 'secondary',
["tertiary"] = true, 'secondary_link',
["tertiary_link"] = true, 'tertiary',
["unclassified"] = true, 'tertiary_link',
["residential"] = true, 'unclassified',
["living_street"] = true } 'residential',
'living_street'
}
link_types = { ["motorway_link"] = true, ["trunk_link"] = true, ["primary_link"] = true, ["secondary_link"] = true, ["tertiary_link"] = true } link_types = Set {
'motorway_link',
'trunk_link',
'primary_link',
'secondary_link',
'tertiary_link'
}
function Guidance.set_classification (highway, result, input_way) function Guidance.set_classification (highway, result, input_way)
if motorway_types[highway] then if motorway_types[highway] then
result.road_classification.motorway_class = true; result.road_classification.motorway_class = true;
end end
if link_types[highway] then if link_types[highway] then
result.road_classification.link_class = true; result.road_classification.link_class = true;
end end
if highway_classes[highway] ~= nil then if highway_classes[highway] ~= nil then
result.road_classification.road_priority_class = highway_classes[highway] result.road_classification.road_priority_class = highway_classes[highway]
else else
result.road_classification.road_priority_class = default_highway_class result.road_classification.road_priority_class = default_highway_class
end end
if road_types[highway] then if road_types[highway] then
result.road_classification.may_be_ignored = false; result.road_classification.may_be_ignored = false;
else else
result.road_classification.may_be_ignored = true; result.road_classification.may_be_ignored = true;
end end
local lane_count = input_way:get_value_by_key("lanes") local lane_count = input_way:get_value_by_key("lanes")
if lane_count then if lane_count then
local lc = tonumber(lane_count) local lc = tonumber(lane_count)
if lc ~= nil then if lc ~= nil then
result.road_classification.num_lanes = lc result.road_classification.num_lanes = lc
end
else
local total_count = 0
local forward_count = input_way:get_value_by_key("lanes:forward")
if forward_count then
local fc = tonumber(forward_count)
if fc ~= nil then
total_count = fc
end
end
local backward_count = input_way:get_value_by_key("lanes:backward")
if backward_count then
local bc = tonumber(backward_count)
if bc ~= nil then
total_count = total_count + bc
end
end
if total_count ~= 0 then
result.road_classification.num_lanes = total_count
end
end end
else
local total_count = 0
local forward_count = input_way:get_value_by_key("lanes:forward")
if forward_count then
local fc = tonumber(forward_count)
if fc ~= nil then
total_count = fc
end
end
local backward_count = input_way:get_value_by_key("lanes:backward")
if backward_count then
local bc = tonumber(backward_count)
if bc ~= nil then
total_count = total_count + bc
end
end
if total_count ~= 0 then
result.road_classification.num_lanes = total_count
end
end
end end
-- returns forward,backward psv lane count -- returns forward,backward psv lane count
local function get_psv_counts(way) local function get_psv_counts(way,data)
local psv = way:get_value_by_key("lanes:psv") local psv_forward, psv_backward = Directional.get_values_by_key(way,data,'lanes:psv')
local psv_forward = way:get_value_by_key("lanes:psv:forward"); if psv_forward then
local psv_backward = way:get_value_by_key("lanes:psv:backward"); psv_forward = tonumber(psv_forward)
end
local fw = 0; if psv_backward then
local bw = 0; psv_backward = tonumber(psv_backward)
if psv then end
fw = tonumber(psv) return psv_forward or 0,
if( fw == nil ) then psv_backward or 0
fw = 0
end
end
if psv_forward then
fw = tonumber(psv_forward)
if( fw == nil ) then
fw = 0
end
end
if psv_backward then
bw = tonumber(psv_backward);
if( bw == nil ) then
bw = 0
end
end
return fw, bw
end end
-- trims lane string with regard to supported lanes -- trims lane string with regard to supported lanes
local function process_lanes(turn_lane,vehicle_lane,first_count,second_count) local function process_lanes(turn_lanes,vehicle_lanes,first_count,second_count)
if turn_lane then if turn_lanes then
if vehicle_lane then if vehicle_lanes then
turn_lane = applyAccessTokens(turn_lane,vehicle_lane) return applyAccessTokens(turn_lanes,vehicle_lanes)
elseif first_count ~= 0 or second_count ~= 0 then elseif first_count ~= 0 or second_count ~= 0 then
turn_lane = trimLaneString(turn_lane, first_count, second_count) return trimLaneString(turn_lanes, first_count, second_count)
end else
return turn_lanes
end end
return turn_lane; end
end end
-- this is broken for left-sided driving. It needs to switch left and right in case of left-sided driving -- this is broken for left-sided driving. It needs to switch left and right in case of left-sided driving
function Guidance.get_turn_lanes(way) function Guidance.get_turn_lanes(way,data)
local fw_psv = 0 local psv_fw, psv_bw = get_psv_counts(way,data)
local bw_psv = 0 local turn_lanes_fw, turn_lanes_bw = Directional.get_values_by_key(way,data,'turn:lanes')
fw_psv, bw_psv = get_psv_counts(way) local vehicle_lanes_fw, vehicle_lanes_bw = Directional.get_values_by_key(way,data,'vehicle:lanes')
local turn_lanes = way:get_value_by_key("turn:lanes") --note: backward lanes swap psv_bw and psv_fw
local turn_lanes_fw = way:get_value_by_key("turn:lanes:forward") return process_lanes(turn_lanes_fw,vehicle_lanes_fw,psv_bw,psv_fw) or turn_lanes,
local turn_lanes_bw = way:get_value_by_key("turn:lanes:backward") process_lanes(turn_lanes_bw,vehicle_lanes_bw,psv_fw,psv_bw) or turn_lanes
local vehicle_lanes = way:get_value_by_key("vehicle:lanes");
local vehicle_lanes_fw = way:get_value_by_key("vehicle:lanes:forward");
local vehicle_lanes_bw = way:get_value_by_key("vehicle:lanes:backward");
turn_lanes = process_lanes(turn_lanes,vehicle_lanes,bw_psv,fw_psv)
turn_lanes_fw = process_lanes(turn_lanes_fw,vehicle_lanes_fw,bw_psv,fw_psv)
--backwards turn lanes need to treat bw_psv as fw_psv and vice versa
turn_lanes_bw = process_lanes(turn_lanes_bw,vehicle_lanes_bw,fw_psv,bw_psv)
return turn_lanes, turn_lanes_fw, turn_lanes_bw
end end
return Guidance return Guidance