1257 lines
No EOL
40 KiB
Lua
1257 lines
No EOL
40 KiB
Lua
-- Itinero 1.0-profile, generated by AspectedRouting. Last source file change is 2021-01-27T15:51:22
|
|
name = "bicycle"
|
|
normalize = false
|
|
vehicle_type = {"vehicle", "bicycle"}
|
|
meta_whitelist = {
|
|
"name"
|
|
, "bridge"
|
|
, "tunnel"
|
|
, "colour"
|
|
, "cycle_network_colour"
|
|
, "cycle_network_ref"
|
|
, "ref"
|
|
, "status"
|
|
, "network" }
|
|
profile_whitelist = {
|
|
"access"
|
|
, "highway"
|
|
, "service"
|
|
, "bicycle"
|
|
, "anyways:bicycle"
|
|
, "anyways:access"
|
|
, "anyways:construction"
|
|
, "oneway"
|
|
, "oneway:bicycle"
|
|
, "junction"
|
|
, "cycleway"
|
|
, "cycleway:left"
|
|
, "maxspeed"
|
|
, "designation"
|
|
, "railway"
|
|
, "towpath"
|
|
, "cyclestreet"
|
|
, "bicycle:class"
|
|
, "surface"
|
|
, "route"
|
|
}
|
|
|
|
|
|
|
|
profiles = {
|
|
{
|
|
name = "fastest",
|
|
function_name = "behaviour_bicycle_fastest",
|
|
metric = "custom"
|
|
},
|
|
{
|
|
name = "shortest",
|
|
function_name = "behaviour_bicycle_shortest",
|
|
metric = "custom"
|
|
},
|
|
{
|
|
name = "comfort",
|
|
function_name = "behaviour_bicycle_comfort",
|
|
metric = "custom"
|
|
},
|
|
{
|
|
name = "electric",
|
|
function_name = "behaviour_bicycle_electric",
|
|
metric = "custom"
|
|
}
|
|
}
|
|
|
|
function default_parameters()
|
|
local parameters = {}
|
|
parameters.defaultSpeed = 15
|
|
parameters.timeNeeded = 0
|
|
parameters.distance = 0
|
|
parameters.comfort = 0
|
|
|
|
return parameters
|
|
end
|
|
|
|
|
|
|
|
--[[
|
|
"The fastest route to your destination"
|
|
]]
|
|
function behaviour_bicycle_fastest(tags, result)
|
|
tags = remove_relation_prefix(tags, "fastest")
|
|
local parameters = default_parameters()
|
|
parameters.name = "bicycle_fastest"
|
|
parameters.timeNeeded = 1
|
|
bicycle(parameters, tags, result)
|
|
end
|
|
|
|
|
|
--[[
|
|
"The shortest route, independent of of speed"
|
|
]]
|
|
function behaviour_bicycle_shortest(tags, result)
|
|
tags = remove_relation_prefix(tags, "shortest")
|
|
local parameters = default_parameters()
|
|
parameters.name = "bicycle_shortest"
|
|
parameters.distance = 1
|
|
bicycle(parameters, tags, result)
|
|
end
|
|
|
|
|
|
--[[
|
|
"A comfortable route preferring well-paved roads, smaller roads and a bit of scenery at the cost of speed"
|
|
]]
|
|
function behaviour_bicycle_comfort(tags, result)
|
|
tags = remove_relation_prefix(tags, "comfort")
|
|
local parameters = default_parameters()
|
|
parameters.name = "bicycle_comfort"
|
|
parameters.comfort = 1
|
|
bicycle(parameters, tags, result)
|
|
end
|
|
|
|
|
|
--[[
|
|
"An electrical bicycle"
|
|
]]
|
|
function behaviour_bicycle_electric(tags, result)
|
|
tags = remove_relation_prefix(tags, "electric")
|
|
local parameters = default_parameters()
|
|
parameters.name = "bicycle_electric"
|
|
parameters.defaultSpeed = 25
|
|
parameters.comfort = 1
|
|
parameters.timeNeeded = 5
|
|
bicycle(parameters, tags, result)
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
--[[
|
|
bicycle
|
|
This is the main function called to calculate the access, oneway and speed.
|
|
Comfort is calculated as well, based on the parameters which are padded in
|
|
|
|
Created by
|
|
Originally defined in /home/pietervdvn/git/AspectedRouting/Examples/bicycle
|
|
]]
|
|
function bicycle(parameters, tags, result)
|
|
|
|
-- initialize the result table on the default values
|
|
result.access = 0
|
|
result.speed = 0
|
|
result.factor = 1
|
|
result.direction = 0
|
|
result.canstop = true
|
|
result.attributes_to_keep = {}
|
|
|
|
local access = bicycle_legal_access(parameters, tags, result)
|
|
if (access == nil or access == "no") then
|
|
return
|
|
end
|
|
tags.access = access
|
|
local oneway = bicycle_oneway(parameters, tags, result)
|
|
tags.oneway = oneway
|
|
local speed =
|
|
min({
|
|
legal_maxspeed_be(parameters, tags, result),
|
|
parameters["defaultSpeed"]
|
|
})
|
|
tags.speed = speed
|
|
local distance = 1 -- the weight per meter for distance travelled is, well, 1m/m
|
|
|
|
local priority = 0
|
|
|
|
if(parameters["comfort"] ~= 0) then
|
|
priority = priority + parameters["comfort"] * bicycle_comfort(parameters, tags, result)
|
|
end
|
|
if(parameters["timeNeeded"] ~= 0) then
|
|
priority = priority + parameters["timeNeeded"] * speed
|
|
end
|
|
if(parameters["distance"] ~= 0) then
|
|
priority = priority + parameters["distance"] * distance
|
|
end
|
|
|
|
if (priority <= 0) then
|
|
result.access = 0
|
|
return
|
|
end
|
|
|
|
result.access = 1
|
|
result.speed = speed
|
|
result.factor = 1 / priority
|
|
|
|
result.direction = 0
|
|
if (oneway == "with" or oneway == "yes") then
|
|
result.direction = 1
|
|
elseif (oneway == "against" or oneway == "-1") then
|
|
result.direction = 2
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- Processes the relation. All tags which are added to result.attributes_to_keep will be copied to 'attributes' of each individual way
|
|
function relation_tag_processor(relation_tags, result)
|
|
local parameters = {}
|
|
local subresult = {}
|
|
local matched = false
|
|
result.attributes_to_keep = {}
|
|
|
|
-- Legacy to add colours to the bike networks
|
|
legacy_relation_preprocessor(relation_tags, result)
|
|
end
|
|
|
|
|
|
---------------------- ASPECTS ----------------------
|
|
|
|
|
|
--[[
|
|
Gives, for each type of highway, whether or not a normal bicycle can enter legally.
|
|
Note that legal access is a bit 'grey' in the case of roads marked private and permissive, in which case these values are returned
|
|
|
|
Unit: 'designated': Access is allowed and even specifically for bicycles
|
|
'yes': bicycles are allowed here
|
|
'permissive': bicycles are allowed here, but this might be a private road or service where usage is allowed, but could be retracted one day by the owner
|
|
'dismount': cycling here is not allowed, but walking with the bicycle is
|
|
'destination': cycling is allowed here, but only if truly necessary to reach the destination
|
|
'private': this is a private road, only go here if the destination is here
|
|
'no': do not cycle here
|
|
Created by
|
|
Originally defined in bicycle.legal_access.json
|
|
Uses tags: access, highway, service, bicycle, anyways:bicycle, anyways:access, anyways:construction
|
|
Used parameters:
|
|
Number of combintations: 54
|
|
Returns values:
|
|
]]
|
|
function bicycle_legal_access(parameters, tags, result)
|
|
local result
|
|
if (tags["highway"] ~= nil) then
|
|
local v
|
|
v = tags["highway"]
|
|
if (v == "cycleway") then
|
|
result = "designated"
|
|
elseif (v == "residential") then
|
|
result = "yes"
|
|
elseif (v == "living_street") then
|
|
result = "yes"
|
|
elseif (v == "service") then
|
|
result = "yes"
|
|
elseif (v == "services") then
|
|
result = "yes"
|
|
elseif (v == "track") then
|
|
result = "yes"
|
|
elseif (v == "crossing") then
|
|
result = "dismount"
|
|
elseif (v == "footway") then
|
|
result = "dismount"
|
|
elseif (v == "pedestrian") then
|
|
result = "dismount"
|
|
elseif (v == "corridor") then
|
|
result = "dismount"
|
|
elseif (v == "construction") then
|
|
result = "dismount"
|
|
elseif (v == "steps") then
|
|
result = "dismount"
|
|
elseif (v == "path") then
|
|
result = "yes"
|
|
elseif (v == "primary") then
|
|
result = "yes"
|
|
elseif (v == "primary_link") then
|
|
result = "yes"
|
|
elseif (v == "secondary") then
|
|
result = "yes"
|
|
elseif (v == "secondary_link") then
|
|
result = "yes"
|
|
elseif (v == "tertiary") then
|
|
result = "yes"
|
|
elseif (v == "tertiary_link") then
|
|
result = "yes"
|
|
elseif (v == "unclassified") then
|
|
result = "yes"
|
|
elseif (v == "road") then
|
|
result = "yes"
|
|
end
|
|
end
|
|
if (tags["service"] ~= nil) then
|
|
local v0
|
|
v0 = tags["service"]
|
|
if (v0 == "parking_aisle") then
|
|
result = "permissive"
|
|
elseif (v0 == "driveway") then
|
|
result = "private"
|
|
elseif (v0 == "alley") then
|
|
result = "yes"
|
|
elseif (v0 == "bus") then
|
|
result = "no"
|
|
end
|
|
end
|
|
if (tags["access"] ~= nil) then
|
|
local v1
|
|
v1 = tags["access"]
|
|
if (v1 == "no") then
|
|
result = "no"
|
|
elseif (v1 == "customers") then
|
|
result = "private"
|
|
elseif (v1 == "private") then
|
|
result = "private"
|
|
elseif (v1 == "permissive") then
|
|
result = "permissive"
|
|
elseif (v1 == "destination") then
|
|
result = "destination"
|
|
elseif (v1 == "delivery") then
|
|
result = "destination"
|
|
elseif (v1 == "service") then
|
|
result = "destination"
|
|
elseif (v1 == "permit") then
|
|
result = "destination"
|
|
end
|
|
end
|
|
if (tags["bicycle"] ~= nil) then
|
|
local v2
|
|
v2 = tags["bicycle"]
|
|
if (v2 == "yes") then
|
|
result = "yes"
|
|
elseif (v2 == "no") then
|
|
result = "no"
|
|
elseif (v2 == "use_sidepath") then
|
|
result = "no"
|
|
elseif (v2 == "designated") then
|
|
result = "designated"
|
|
elseif (v2 == "permissive") then
|
|
result = "permissive"
|
|
elseif (v2 == "private") then
|
|
result = "private"
|
|
elseif (v2 == "official") then
|
|
result = "designated"
|
|
elseif (v2 == "dismount") then
|
|
result = "dismount"
|
|
elseif (v2 == "permit") then
|
|
result = "destination"
|
|
end
|
|
end
|
|
if (tags["anyways:construction"] ~= nil) then
|
|
local v3
|
|
v3 = tags["anyways:construction"]
|
|
if (v3 == "yes") then
|
|
result = "no"
|
|
end
|
|
end
|
|
if (tags["anyways:access"] ~= nil) then
|
|
local v4
|
|
v4 = tags["anyways:access"]
|
|
if (v4 == "no") then
|
|
result = "no"
|
|
elseif (v4 == "destination") then
|
|
result = "destination"
|
|
elseif (v4 == "yes") then
|
|
result = "yes"
|
|
end
|
|
end
|
|
if (tags["anyways:bicycle"] ~= nil) then
|
|
result = tags["anyways:bicycle"]
|
|
end
|
|
|
|
if (result == nil) then
|
|
result = "no"
|
|
end
|
|
return result
|
|
end
|
|
--[[
|
|
Determines wether or not a bicycle can go in both ways in this street, and if it is oneway, in what direction
|
|
|
|
Unit: both: direction is allowed in both direction
|
|
with: this is a oneway street with direction allowed with the grain of the way
|
|
against: oneway street with direction against the way
|
|
Created by
|
|
Originally defined in bicycle.oneway.json
|
|
Uses tags: oneway, oneway:bicycle, junction, cycleway, cycleway:left
|
|
Used parameters:
|
|
Number of combintations: 32
|
|
Returns values:
|
|
]]
|
|
function bicycle_oneway(parameters, tags, result)
|
|
local result
|
|
if (tags["oneway"] ~= nil) then
|
|
local v5
|
|
v5 = tags["oneway"]
|
|
if (v5 == "yes") then
|
|
result = "with"
|
|
elseif (v5 == "no") then
|
|
result = "both"
|
|
elseif (v5 == "1") then
|
|
result = "with"
|
|
elseif (v5 == "-1") then
|
|
result = "against"
|
|
end
|
|
end
|
|
if (tags["cycleway:left"] ~= nil) then
|
|
local v6
|
|
v6 = tags["cycleway:left"]
|
|
if (v6 == "no") then
|
|
result = "with"
|
|
elseif (v6 == "none") then
|
|
result = "with"
|
|
elseif (v6 == "yes") then
|
|
result = "both"
|
|
elseif (v6 == "lane") then
|
|
result = "both"
|
|
elseif (v6 == "track") then
|
|
result = "both"
|
|
elseif (v6 == "shared_lane") then
|
|
result = "both"
|
|
elseif (v6 == "share_busway") then
|
|
result = "both"
|
|
elseif (v6 == "opposite_lane") then
|
|
result = "both"
|
|
elseif (v6 == "opposite_track") then
|
|
result = "both"
|
|
elseif (v6 == "opposite") then
|
|
result = "both"
|
|
end
|
|
end
|
|
if (tags["cycleway"] ~= nil) then
|
|
local v7
|
|
v7 = tags["cycleway"]
|
|
if (v7 == "right") then
|
|
result = "against"
|
|
elseif (v7 == "opposite_lane") then
|
|
result = "both"
|
|
elseif (v7 == "track") then
|
|
result = "both"
|
|
elseif (v7 == "lane") then
|
|
result = "both"
|
|
elseif (v7 == "opposite") then
|
|
result = "both"
|
|
elseif (v7 == "opposite_share_busway") then
|
|
result = "both"
|
|
elseif (v7 == "opposite_track") then
|
|
result = "both"
|
|
end
|
|
end
|
|
if (tags["junction"] ~= nil) then
|
|
local v8
|
|
v8 = tags["junction"]
|
|
if (v8 == "roundabout") then
|
|
result = "with"
|
|
end
|
|
end
|
|
if (tags["oneway:bicycle"] ~= nil) then
|
|
local v9
|
|
v9 = tags["oneway:bicycle"]
|
|
if (v9 == "yes") then
|
|
result = "with"
|
|
elseif (v9 == "no") then
|
|
result = "both"
|
|
elseif (v9 == "1") then
|
|
result = "with"
|
|
elseif (v9 == "-1") then
|
|
result = "against"
|
|
end
|
|
end
|
|
|
|
if (result == nil) then
|
|
result = "both"
|
|
end
|
|
return result
|
|
end
|
|
--[[
|
|
Gives, for each type of highway, which the default legal maxspeed is in Belgium. This file is intended to be reused for in all vehicles, from pedestrian to car. In some cases, a legal maxspeed is not really defined (e.g. on footways). In that case, a socially acceptable speed should be taken (e.g.: a bicycle on a pedestrian path will go say around 12km/h)
|
|
|
|
Unit: km/h
|
|
Created by
|
|
Originally defined in legal_maxspeed_be.json
|
|
Uses tags: maxspeed, highway, designation
|
|
Used parameters:
|
|
Number of combintations: 26
|
|
Returns values:
|
|
]]
|
|
function legal_maxspeed_be(parameters, tags, result)
|
|
local result
|
|
if (tags["highway"] ~= nil) then
|
|
local v10
|
|
v10 = tags["highway"]
|
|
if (v10 == "cycleway") then
|
|
result = 30
|
|
elseif (v10 == "footway") then
|
|
result = 20
|
|
elseif (v10 == "crossing") then
|
|
result = 20
|
|
elseif (v10 == "pedestrian") then
|
|
result = 15
|
|
elseif (v10 == "path") then
|
|
result = 15
|
|
elseif (v10 == "corridor") then
|
|
result = 5
|
|
elseif (v10 == "residential") then
|
|
result = 30
|
|
elseif (v10 == "living_street") then
|
|
result = 20
|
|
elseif (v10 == "service") then
|
|
result = 30
|
|
elseif (v10 == "services") then
|
|
result = 30
|
|
elseif (v10 == "track") then
|
|
result = 50
|
|
elseif (v10 == "unclassified") then
|
|
result = 50
|
|
elseif (v10 == "road") then
|
|
result = 50
|
|
elseif (v10 == "motorway") then
|
|
result = 120
|
|
elseif (v10 == "motorway_link") then
|
|
result = 120
|
|
elseif (v10 == "primary") then
|
|
result = 90
|
|
elseif (v10 == "primary_link") then
|
|
result = 90
|
|
elseif (v10 == "secondary") then
|
|
result = 50
|
|
elseif (v10 == "secondary_link") then
|
|
result = 50
|
|
elseif (v10 == "tertiary") then
|
|
result = 50
|
|
elseif (v10 == "tertiary_link") then
|
|
result = 50
|
|
end
|
|
end
|
|
if (tags["designation"] ~= nil) then
|
|
local v11
|
|
v11 = tags["designation"]
|
|
if (v11 == "towpath") then
|
|
result = 30
|
|
end
|
|
end
|
|
if (tags["maxspeed"] ~= nil) then
|
|
result = parse(tags["maxspeed"])
|
|
end
|
|
|
|
if (result == nil) then
|
|
result = 30
|
|
end
|
|
return result
|
|
end
|
|
--[[
|
|
Gives a comfort factor for a road, purely based on physical aspects of the road, which is a bit subjective; this takes a bit of scnery into account with a preference for `railway=abandoned` and `towpath=yes`
|
|
|
|
Unit: [0, 2]
|
|
Created by
|
|
Originally defined in bicycle.comfort.json
|
|
Uses tags: highway, railway, towpath, cycleway, cyclestreet, access, bicycle:class, surface, route
|
|
Used parameters:
|
|
Number of combintations: 55
|
|
Returns values:
|
|
]]
|
|
function bicycle_comfort(parameters, tags, result)
|
|
local result
|
|
result = 1
|
|
if (tags["highway"] ~= nil) then
|
|
local m = nil
|
|
local v12
|
|
v12 = tags["highway"]
|
|
if (v12 == "cycleway") then
|
|
m = 1.2
|
|
elseif (v12 == "primary") then
|
|
m = 0.3
|
|
elseif (v12 == "secondary") then
|
|
m = 0.4
|
|
elseif (v12 == "tertiary") then
|
|
m = 0.5
|
|
elseif (v12 == "unclassified") then
|
|
m = 0.8
|
|
elseif (v12 == "track") then
|
|
m = 0.95
|
|
elseif (v12 == "residential") then
|
|
m = 1
|
|
elseif (v12 == "living_street") then
|
|
m = 1.1
|
|
elseif (v12 == "footway") then
|
|
m = 0.95
|
|
elseif (v12 == "path") then
|
|
m = 0.5
|
|
elseif (v12 == "construction") then
|
|
m = 0.5
|
|
end
|
|
|
|
|
|
if (m ~= nil) then
|
|
result = result * m
|
|
end
|
|
end
|
|
if (tags["railway"] ~= nil) then
|
|
local m = nil
|
|
local v13
|
|
v13 = tags["railway"]
|
|
if (v13 == "abandoned") then
|
|
m = 2
|
|
end
|
|
|
|
|
|
if (m ~= nil) then
|
|
result = result * m
|
|
end
|
|
end
|
|
if (tags["towpath"] ~= nil) then
|
|
local m = nil
|
|
local v14
|
|
v14 = tags["towpath"]
|
|
if (v14 == "yes") then
|
|
m = 2
|
|
end
|
|
|
|
|
|
if (m ~= nil) then
|
|
result = result * m
|
|
end
|
|
end
|
|
if (tags["cycleway"] ~= nil) then
|
|
local m = nil
|
|
local v15
|
|
v15 = tags["cycleway"]
|
|
if (v15 == "track") then
|
|
m = 1.2
|
|
end
|
|
|
|
|
|
if (m ~= nil) then
|
|
result = result * m
|
|
end
|
|
end
|
|
if (tags["cyclestreet"] ~= nil) then
|
|
local m = nil
|
|
local v16
|
|
v16 = tags["cyclestreet"]
|
|
if (v16 == "yes") then
|
|
m = 1.1
|
|
end
|
|
|
|
|
|
if (m ~= nil) then
|
|
result = result * m
|
|
end
|
|
end
|
|
if (tags["access"] ~= nil) then
|
|
local m = nil
|
|
local v17
|
|
v17 = tags["access"]
|
|
if (v17 == "designated") then
|
|
m = 1.2
|
|
elseif (v17 == "dismount") then
|
|
m = 0.01
|
|
end
|
|
|
|
|
|
if (m ~= nil) then
|
|
result = result * m
|
|
end
|
|
end
|
|
if (tags["bicycle:class"] ~= nil) then
|
|
local m = nil
|
|
local v18
|
|
v18 = tags["bicycle:class"]
|
|
if (v18 == "-3") then
|
|
m = 0.5
|
|
elseif (v18 == "-2") then
|
|
m = 0.7
|
|
elseif (v18 == "-1") then
|
|
m = 0.9
|
|
elseif (v18 == "0") then
|
|
m = 1
|
|
elseif (v18 == "1") then
|
|
m = 1.1
|
|
elseif (v18 == "2") then
|
|
m = 1.3
|
|
elseif (v18 == "3") then
|
|
m = 1.5
|
|
end
|
|
|
|
|
|
if (m ~= nil) then
|
|
result = result * m
|
|
end
|
|
end
|
|
if (tags["surface"] ~= nil) then
|
|
local m = nil
|
|
local v19
|
|
v19 = tags["surface"]
|
|
if (v19 == "paved") then
|
|
m = 0.99
|
|
elseif (v19 == "concrete:lanes") then
|
|
m = 0.8
|
|
elseif (v19 == "concrete:plates") then
|
|
m = 1
|
|
elseif (v19 == "sett") then
|
|
m = 0.9
|
|
elseif (v19 == "unhewn_cobblestone") then
|
|
m = 0.75
|
|
elseif (v19 == "cobblestone") then
|
|
m = 0.8
|
|
elseif (v19 == "unpaved") then
|
|
m = 0.75
|
|
elseif (v19 == "compacted") then
|
|
m = 0.95
|
|
elseif (v19 == "fine_gravel") then
|
|
m = 0.7
|
|
elseif (v19 == "gravel") then
|
|
m = 0.9
|
|
elseif (v19 == "dirt") then
|
|
m = 0.6
|
|
elseif (v19 == "earth") then
|
|
m = 0.6
|
|
elseif (v19 == "grass") then
|
|
m = 0.6
|
|
elseif (v19 == "grass_paver") then
|
|
m = 0.9
|
|
elseif (v19 == "ground") then
|
|
m = 0.7
|
|
elseif (v19 == "sand") then
|
|
m = 0.5
|
|
elseif (v19 == "woodchips") then
|
|
m = 0.5
|
|
elseif (v19 == "snow") then
|
|
m = 0.5
|
|
elseif (v19 == "pebblestone") then
|
|
m = 0.5
|
|
elseif (v19 == "mud") then
|
|
m = 0.4
|
|
end
|
|
|
|
|
|
if (m ~= nil) then
|
|
result = result * m
|
|
end
|
|
end
|
|
if (tags["route"] ~= nil) then
|
|
local m = nil
|
|
local v20
|
|
v20 = tags["route"]
|
|
if (v20 == "ferry") then
|
|
m = 0.01
|
|
end
|
|
|
|
|
|
if (m ~= nil) then
|
|
result = result * m
|
|
end
|
|
end
|
|
|
|
if (result == nil) then
|
|
result = 1
|
|
end
|
|
return result
|
|
end
|
|
--[[
|
|
Actual speed of this function
|
|
|
|
Unit: NA
|
|
Created by NA
|
|
Originally defined in NA
|
|
Uses tags:
|
|
Used parameters:
|
|
Number of combintations: 1
|
|
Returns values:
|
|
]]
|
|
function speed(parameters, tags, result)
|
|
local result
|
|
result = 15
|
|
return result
|
|
end
|
|
--[[
|
|
The distance travelled of this profile
|
|
|
|
Unit:
|
|
Created by
|
|
Originally defined in bicycle.json
|
|
Uses tags:
|
|
Used parameters:
|
|
Number of combintations: 1
|
|
Returns values:
|
|
]]
|
|
function distance(parameters, tags, result)
|
|
local result
|
|
result = 1
|
|
return result
|
|
end
|
|
|
|
|
|
---------------------- UTILS ------------------------
|
|
|
|
|
|
-- instruction generators
|
|
instruction_generators = {
|
|
{
|
|
applies_to = "", -- applies to all profiles when empty
|
|
generators = {
|
|
{
|
|
name = "start",
|
|
function_name = "get_start"
|
|
},
|
|
{
|
|
name = "stop",
|
|
function_name = "get_stop"
|
|
},
|
|
{
|
|
name = "roundabout",
|
|
function_name = "get_roundabout"
|
|
},
|
|
{
|
|
name = "turn",
|
|
function_name = "get_turn"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
-- gets the first instruction
|
|
function get_start(route_position, language_reference, instruction)
|
|
if route_position.is_first() then
|
|
local direction = route_position.direction()
|
|
instruction.text = itinero.format(language_reference.get("Start {0}."), language_reference.get(direction));
|
|
instruction.shape = route_position.shape
|
|
return 1
|
|
end
|
|
return 0
|
|
end
|
|
|
|
-- gets the last instruction
|
|
function get_stop(route_position, language_reference, instruction)
|
|
if route_position.is_last() then
|
|
instruction.text = language_reference.get("Arrived at destination.");
|
|
instruction.shape = route_position.shape
|
|
return 1
|
|
end
|
|
return 0
|
|
end
|
|
|
|
|
|
-- gets a roundabout instruction
|
|
function get_roundabout(route_position, language_reference, instruction)
|
|
if route_position.attributes.junction == "roundabout" and
|
|
(not route_position.is_last()) then
|
|
local attributes = route_position.next().attributes
|
|
if attributes.junction then
|
|
else
|
|
local exit = 1
|
|
local count = 1
|
|
local previous = route_position.previous()
|
|
while previous and previous.attributes.junction == "roundabout" do
|
|
local branches = previous.branches
|
|
if branches then
|
|
branches = branches.get_traversable()
|
|
if branches.count > 0 then
|
|
exit = exit + 1
|
|
end
|
|
end
|
|
count = count + 1
|
|
previous = previous.previous()
|
|
end
|
|
|
|
instruction.text = itinero.format(language_reference.get("Take the {0}th exit at the next roundabout."), "" .. exit)
|
|
if exit == 1 then
|
|
instruction.text = itinero.format(language_reference.get("Take the first exit at the next roundabout."))
|
|
elseif exit == 2 then
|
|
instruction.text = itinero.format(language_reference.get("Take the second exit at the next roundabout."))
|
|
elseif exit == 3 then
|
|
instruction.text = itinero.format(language_reference.get("Take the third exit at the next roundabout."))
|
|
end
|
|
instruction.type = "roundabout"
|
|
instruction.shape = route_position.shape
|
|
return count
|
|
end
|
|
end
|
|
return 0
|
|
end
|
|
|
|
-- gets a turn
|
|
function get_turn(route_position, language_reference, instruction)
|
|
local relative_direction = route_position.relative_direction().direction
|
|
|
|
local turn_relevant = false
|
|
local branches = route_position.branches
|
|
if branches then
|
|
branches = branches.get_traversable()
|
|
if relative_direction == "straighton" and
|
|
branches.count >= 2 then
|
|
turn_relevant = true -- straight on at cross road
|
|
end
|
|
if relative_direction ~= "straighton" and
|
|
branches.count > 0 then
|
|
turn_relevant = true -- an actual normal turn
|
|
end
|
|
end
|
|
|
|
if relative_direction == "unknown" then
|
|
turn_relevant = false -- turn could not be calculated.
|
|
end
|
|
|
|
if turn_relevant then
|
|
local next = route_position.next()
|
|
local name = nil
|
|
if next then
|
|
name = next.attributes.name
|
|
end
|
|
if name then
|
|
instruction.text = itinero.format(language_reference.get("Go {0} on {1}."),
|
|
language_reference.get(relative_direction), name)
|
|
instruction.shape = route_position.shape
|
|
else
|
|
instruction.text = itinero.format(language_reference.get("Go {0}."),
|
|
language_reference.get(relative_direction))
|
|
instruction.shape = route_position.shape
|
|
end
|
|
|
|
return 1
|
|
end
|
|
return 0
|
|
end
|
|
|
|
--[[
|
|
Legacy function to add cycle_colour
|
|
]]
|
|
|
|
function legacy_relation_preprocessor(attributes, result)
|
|
if (attributes.route == "bicycle") then
|
|
-- This is a cycling network, the colour is copied
|
|
if (attributes.colour ~= nil) then
|
|
result.attributes_to_keep.cycle_network_colour = attributes.colour
|
|
end
|
|
|
|
if (attributes.color ~= nil) then
|
|
-- for the americans!
|
|
result.attributes_to_keep.cycle_network_colour = attributes.color
|
|
end
|
|
|
|
if (attributes.ref ~= nil and attributes.operator == "Stad Genk") then
|
|
-- This is pure legacy: we need the ref number only of stad Genk
|
|
result.attributes_to_keep.cycle_network_ref = attributes.ref
|
|
end
|
|
end
|
|
end
|
|
|
|
function string_start(strt, s)
|
|
return string.sub(s, 1, string.len(strt)) == strt
|
|
end
|
|
|
|
|
|
-- every key starting with "_relation:<name>:XXX" is rewritten to "_relation:XXX"
|
|
function remove_relation_prefix(tags, name)
|
|
|
|
local new_tags = {}
|
|
for k, v in pairs(tags) do
|
|
local prefix = "_relation:" .. name .. ":";
|
|
if (string_start(prefix, k)) then
|
|
local new_key = "_relation:" .. string.sub(k, string.len(prefix) + 1) -- plus 1: sub uses one-based indexing to select the start
|
|
new_tags[new_key] = v
|
|
else
|
|
new_tags[k] = v
|
|
end
|
|
end
|
|
return new_tags
|
|
end
|
|
function min(list)
|
|
local min
|
|
for _, value in pairs(list) do
|
|
if(value ~= nil) then
|
|
if (min == nil) then
|
|
min = value
|
|
elseif (value < min) then
|
|
min = value
|
|
end
|
|
end
|
|
end
|
|
|
|
return min;
|
|
end
|
|
function parse(string)
|
|
if (string == nil) then
|
|
return 0
|
|
end
|
|
if (type(string) == "number") then
|
|
return string
|
|
end
|
|
|
|
if (string == "yes" or string == "true") then
|
|
return 1
|
|
end
|
|
|
|
if (string == "no" or string == "false") then
|
|
return 0
|
|
end
|
|
|
|
if (type(string) == "boolean") then
|
|
if (string) then
|
|
return 1
|
|
else
|
|
return 0
|
|
end
|
|
end
|
|
|
|
if(string:match("%d+:%d+")) then
|
|
-- duration in minute
|
|
local duration = 0
|
|
for part in string:gmatch "%d+" do
|
|
duration = duration * 60 + tonumber(part)
|
|
end
|
|
return duration
|
|
end
|
|
|
|
|
|
return tonumber(string)
|
|
end
|
|
failed_tests = false
|
|
function unit_test(f, fname, index, expected, parameters, tags)
|
|
if (f == nil) then
|
|
print("Trying to unit test " .. fname .. " but this function is not defined")
|
|
failed_tests = true
|
|
return
|
|
end
|
|
local result = {attributes_to_keep = {}}
|
|
local actual = f(parameters, tags, result)
|
|
if(expected == "null" and actual == nil) then
|
|
-- OK!
|
|
elseif(tonumber(actual) and tonumber(expected) and math.abs(tonumber(actual) - tonumber(expected)) < 0.1) then
|
|
-- OK!
|
|
elseif (tostring(actual) ~= expected) then
|
|
print("[" .. fname .. "] " .. index .. " failed: expected " .. expected .. " but got " .. tostring(actual))
|
|
failed_tests = true
|
|
end
|
|
end
|
|
failed_profile_tests = false
|
|
--[[
|
|
expected should be a table containing 'access', 'speed' and 'priority'
|
|
]]
|
|
function unit_test_profile(profile_function, profile_name, index, expected, tags)
|
|
local result = { attributes_to_keep = {} }
|
|
local profile_failed = false
|
|
profile_function(tags, result)
|
|
|
|
local accessCorrect = (result.access == 0 and (expected.access == "no" or expected.priority <= 0)) or result.access == 1
|
|
if (not accessCorrect) then
|
|
print("Test " .. tostring(index) .. " failed for " .. profile_name .. ".access: expected " .. expected.access .. " but got " .. result.access)
|
|
profile_failed = true
|
|
failed_profile_tests = true
|
|
end
|
|
|
|
if (expected.access == "no" or expected.priority <= 0) then
|
|
-- we cannot access this road, the other results are irrelevant
|
|
if (profile_failed) then
|
|
print("The used tags for test " .. tostring(index) .. " are:")
|
|
debug_table(tags)
|
|
end
|
|
return
|
|
end
|
|
|
|
if (not double_compare(result.speed, expected.speed)) then
|
|
print("Test " .. tostring(index) .. " failed for " .. profile_name .. ".speed: expected " .. expected.speed .. " but got " .. result.speed)
|
|
failed_profile_tests = true
|
|
profile_failed = true
|
|
end
|
|
|
|
|
|
local actualOneway = result.direction
|
|
|
|
if(actualOneway == nil) then
|
|
print("Fail: result.direction is nil")
|
|
profile_failed = true;
|
|
end
|
|
|
|
if (result.direction == 0) then
|
|
actualOneway = "both"
|
|
elseif (result.direction == 1) then
|
|
actualOneway = "with"
|
|
elseif (result.direction == 2) then
|
|
actualOneway = "against"
|
|
end
|
|
|
|
if (expected.oneway ~= actualOneway) then
|
|
print("Test " .. tostring(index) .. " failed for " .. profile_name .. ".oneway: expected " .. expected.oneway .. " but got " .. actualOneway)
|
|
failed_profile_tests = true
|
|
profile_failed = true
|
|
end
|
|
|
|
|
|
if (not double_compare(result.factor, 1/expected.priority)) then
|
|
print("Test " .. tostring(index) .. " failed for " .. profile_name .. ".factor: expected " .. expected.priority .. " but got " .. 1/result.factor)
|
|
failed_profile_tests = true
|
|
profile_failed = true
|
|
end
|
|
|
|
if (profile_failed == true) then
|
|
print("The used tags for test " .. tostring(index) .. " are:")
|
|
debug_table(tags)
|
|
end
|
|
end
|
|
function inv(n)
|
|
return 1/n
|
|
end
|
|
function double_compare(a, b)
|
|
if (b == nil) then
|
|
return false
|
|
end
|
|
|
|
if (type(a) ~= "number") then
|
|
a = parse(a)
|
|
end
|
|
|
|
if(type(b) ~= "number") then
|
|
b = parse(b)
|
|
end
|
|
if (a == b) then
|
|
return true
|
|
end
|
|
|
|
return math.abs(a - b) < 0.0001
|
|
end
|
|
function debug_table(table, prefix)
|
|
if (prefix == nil) then
|
|
prefix = ""
|
|
end
|
|
for k, v in pairs(table) do
|
|
|
|
if (type(v) == "table") then
|
|
debug_table(v, " ")
|
|
else
|
|
print(prefix .. tostring(k) .. " = " .. tostring(v))
|
|
end
|
|
end
|
|
print("")
|
|
end
|
|
|
|
function debug_table_str(table, prefix)
|
|
if (prefix == nil) then
|
|
prefix = ""
|
|
end
|
|
local str = "";
|
|
for k, v in pairs(table) do
|
|
|
|
if (type(v) == "table") then
|
|
str = str .. "," .. debug_table_str(v, " ")
|
|
else
|
|
str = str .. "," .. (prefix .. tostring(k) .. " = " .. tostring(v))
|
|
end
|
|
end
|
|
return str
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
----------------------- TESTS ------------------------
|
|
|
|
|
|
function test_all()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
unit_test(legal_maxspeed_be, "legal_maxspeed_be", 0, "30", {}, {})
|
|
unit_test(legal_maxspeed_be, "legal_maxspeed_be", 1, "30", {}, {highway = "residential"})
|
|
unit_test(legal_maxspeed_be, "legal_maxspeed_be", 2, "50", {}, {highway = "secondary"})
|
|
unit_test(legal_maxspeed_be, "legal_maxspeed_be", 3, "70", {}, {highway = "secondary", maxspeed = "70"})
|
|
|
|
|
|
|
|
unit_test(bicycle_comfort, "bicycle.comfort", 0, "1", {}, {})
|
|
unit_test(bicycle_comfort, "bicycle.comfort", 1, "1", {}, {highway = "residential"})
|
|
unit_test(bicycle_comfort, "bicycle.comfort", 2, "1.1", {}, {highway = "residential", cyclestreet = "yes"})
|
|
unit_test(bicycle_comfort, "bicycle.comfort", 3, "1.2", {}, {highway = "cycleway"})
|
|
unit_test(bicycle_comfort, "bicycle.comfort", 4, "1.2", {}, {highway = "cycleway", foot = "designated"})
|
|
unit_test(bicycle_comfort, "bicycle.comfort", 5, "0.5", {}, {highway = "path", foot = "designated", bicycle = "designated"})
|
|
unit_test(bicycle_comfort, "bicycle.comfort", 6, "0.5", {}, {highway = "path", bicycle = "designated"})
|
|
unit_test(bicycle_comfort, "bicycle.comfort", 7, "0.95", {}, {highway = "footway", foot = "designated"})
|
|
unit_test(bicycle_comfort, "bicycle.comfort", 8, "0.3", {}, {highway = "primary", cycleway = "no"})
|
|
unit_test(bicycle_comfort, "bicycle.comfort", 9, "0.3", {}, {highway = "primary", cycleway = "yes"})
|
|
unit_test(bicycle_comfort, "bicycle.comfort", 10, "0.36", {}, {highway = "primary", cycleway = "track"})
|
|
unit_test(bicycle_comfort, "bicycle.comfort", 11, "0.4", {}, {highway = "secondary", cycleway = "lane"})
|
|
unit_test(bicycle_comfort, "bicycle.comfort", 12, "0.4", {}, {highway = "secondary", ["cycleway:right"] = "lane", surface = "asphalt"})
|
|
unit_test(bicycle_comfort, "bicycle.comfort", 13, "1.1", {}, {highway = "residential", cyclestreet = "yes", surface = "asphalt"})
|
|
unit_test(bicycle_comfort, "bicycle.comfort", 14, "2", {}, {railway = "abandoned"})
|
|
unit_test(bicycle_comfort, "bicycle.comfort", 15, "2", {}, {towpath = "yes"})
|
|
unit_test(bicycle_comfort, "bicycle.comfort", 16, "4", {}, {railway = "abandoned", towpath = "yes"})
|
|
|
|
|
|
|
|
unit_test(bicycle_legal_access, "bicycle.legal_access", 0, "no", {}, {})
|
|
unit_test(bicycle_legal_access, "bicycle.legal_access", 1, "no", {}, {access = "no"})
|
|
unit_test(bicycle_legal_access, "bicycle.legal_access", 2, "yes", {}, {bicycle = "yes", access = "no"})
|
|
unit_test(bicycle_legal_access, "bicycle.legal_access", 3, "yes", {}, {highway = "path"})
|
|
unit_test(bicycle_legal_access, "bicycle.legal_access", 4, "yes", {}, {highway = "pedestrian", bicycle = "yes"})
|
|
unit_test(bicycle_legal_access, "bicycle.legal_access", 5, "dismount", {}, {highway = "pedestrian"})
|
|
unit_test(bicycle_legal_access, "bicycle.legal_access", 6, "designated", {}, {highway = "cycleway"})
|
|
unit_test(bicycle_legal_access, "bicycle.legal_access", 7, "destination", {}, {highway = "residential", access = "destination"})
|
|
unit_test(bicycle_legal_access, "bicycle.legal_access", 8, "private", {}, {highway = "residential", access = "private"})
|
|
unit_test(bicycle_legal_access, "bicycle.legal_access", 9, "designated", {}, {highway = "residential", bicycle = "designated"})
|
|
unit_test(bicycle_legal_access, "bicycle.legal_access", 10, "designated", {}, {highway = "motorway", bicycle = "designated"})
|
|
unit_test(bicycle_legal_access, "bicycle.legal_access", 11, "no", {}, {highway = "residential", bicycle = "use_sidepath"})
|
|
unit_test(bicycle_legal_access, "bicycle.legal_access", 12, "yes", {}, {highway = "residential", access = "no", ["anyways:access"] = "yes"})
|
|
unit_test(bicycle_legal_access, "bicycle.legal_access", 13, "yes", {}, {highway = "primary"})
|
|
unit_test(bicycle_legal_access, "bicycle.legal_access", 14, "yes", {}, {highway = "primary", ["cycleway:right"] = "yes"})
|
|
unit_test(bicycle_legal_access, "bicycle.legal_access", 15, "yes", {}, {highway = "primary", cycleway = "yes"})
|
|
unit_test(bicycle_legal_access, "bicycle.legal_access", 16, "yes", {}, {highway = "secondary", ["cycleway:right"] = "track"})
|
|
unit_test(bicycle_legal_access, "bicycle.legal_access", 17, "destination", {}, {highway = "service", access = "destination"})
|
|
unit_test(bicycle_legal_access, "bicycle.legal_access", 18, "no", {}, {highway = "residential", bicycle = "use_sidepath"})
|
|
unit_test(bicycle_legal_access, "bicycle.legal_access", 19, "yes", {}, {highway = "tertiary", cycleway = "no"})
|
|
unit_test(bicycle_legal_access, "bicycle.legal_access", 20, "dismount", {}, {highway = "construction"})
|
|
|
|
unit_test(bicycle_oneway, "bicycle.oneway", 0, "both", {}, {})
|
|
unit_test(bicycle_oneway, "bicycle.oneway", 1, "both", {}, {oneway = "no"})
|
|
unit_test(bicycle_oneway, "bicycle.oneway", 2, "with", {}, {oneway = "no", ["oneway:bicycle"] = "yes"})
|
|
unit_test(bicycle_oneway, "bicycle.oneway", 3, "with", {}, {junction = "roundabout"})
|
|
unit_test(bicycle_oneway, "bicycle.oneway", 4, "both", {}, {oneway = "yes", cycleway = "opposite"})
|
|
unit_test(bicycle_oneway, "bicycle.oneway", 5, "against", {}, {oneway = "yes", ["oneway:bicycle"] = "-1"})
|
|
unit_test(bicycle_oneway, "bicycle.oneway", 6, "with", {}, {highway = "residential", oneway = "yes"})
|
|
unit_test(bicycle_oneway, "bicycle.oneway", 7, "both", {}, {highway = "residential", oneway = "no"})
|
|
unit_test(bicycle_oneway, "bicycle.oneway", 8, "both", {}, {highway = "residential", oneway = "yes", ["oneway:bicycle"] = "no"})
|
|
unit_test(bicycle_oneway, "bicycle.oneway", 9, "with", {}, {highway = "residential", junction = "roundabout"})
|
|
unit_test(bicycle_oneway, "bicycle.oneway", 10, "both", {}, {highway = "residential", ["oneway:bicycle"] = "no", junction = "roundabout"})
|
|
unit_test(bicycle_oneway, "bicycle.oneway", 11, "against", {}, {highway = "residential", ["oneway:bicycle"] = "-1"})
|
|
unit_test(bicycle_oneway, "bicycle.oneway", 12, "both", {}, {highway = "residential", oneway = "invalidKey", ["oneway:bicycle"] = "no"})
|
|
unit_test(bicycle_oneway, "bicycle.oneway", 13, "with", {}, {highway = "secondary", oneway = "yes", ["cycleway:right"] = "track"})
|
|
unit_test(bicycle_oneway, "bicycle.oneway", 14, "both", {}, {highway = "secondary", oneway = "yes", ["cycleway:left"] = "track"})
|
|
unit_test(bicycle_oneway, "bicycle.oneway", 15, "both", {}, {highway = "secondary", oneway = "yes", cycleway = "track"})
|
|
unit_test(bicycle_oneway, "bicycle.oneway", 16, "with", {}, {oneway = "yes", ["cycleway:left"] = "no"})
|
|
unit_test(bicycle_oneway, "bicycle.oneway", 17, "both", {}, {highway = "residential", oneway = "yes", ["cycleway:left"] = "lane"})
|
|
|
|
|
|
|
|
|
|
-- Behaviour tests --
|
|
|
|
|
|
unit_test_profile(behaviour_bicycle_fastest, "fastest", 0, {access = "no", speed = 0, oneway = "both", priority = 0 }, {})
|
|
unit_test_profile(behaviour_bicycle_fastest, "fastest", 1, {access = "designated", speed = 15, oneway = "both", priority = 15 }, {highway = "cycleway"})
|
|
unit_test_profile(behaviour_bicycle_fastest, "fastest", 2, {access = "yes", speed = 15, oneway = "both", priority = 15 }, {highway = "residential"})
|
|
unit_test_profile(behaviour_bicycle_fastest, "fastest", 3, {access = "yes", speed = 15, oneway = "both", priority = 15 }, {highway = "pedestrian", bicycle = "yes"})
|
|
unit_test_profile(behaviour_bicycle_fastest, "fastest", 4, {access = "yes", speed = 15, oneway = "both", priority = 15 }, {highway = "unclassified", ["cycleway:left"] = "track", oneway = "yes", ["oneway:bicycle"] = "no"})
|
|
unit_test_profile(behaviour_bicycle_fastest, "fastest", 5, {access = "yes", speed = 15, oneway = "both", priority = 15 }, {highway = "service"})
|
|
unit_test_profile(behaviour_bicycle_fastest, "fastest", 6, {access = "yes", speed = 15, oneway = "both", priority = 15 }, {highway = "tertiary", access = "yes", maxspeed = "50"})
|
|
unit_test_profile(behaviour_bicycle_fastest, "fastest", 7, {access = "yes", speed = 15, oneway = "with", priority = 15 }, {highway = "residential", junction = "roundabout"})
|
|
|
|
unit_test_profile(behaviour_bicycle_shortest, "shortest", 0, {access = "no", speed = 0, oneway = "both", priority = 0 }, {})
|
|
unit_test_profile(behaviour_bicycle_shortest, "shortest", 1, {access = "designated", speed = 15, oneway = "both", priority = 1 }, {highway = "cycleway"})
|
|
unit_test_profile(behaviour_bicycle_shortest, "shortest", 2, {access = "yes", speed = 15, oneway = "both", priority = 1 }, {highway = "path", surface = "ground"})
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
if (itinero == nil) then
|
|
itinero = {}
|
|
itinero.log = print
|
|
|
|
-- Itinero is not defined -> we are running from a lua interpreter -> the tests are intended
|
|
runTests = true
|
|
|
|
|
|
else
|
|
print = itinero.log
|
|
end
|
|
|
|
test_all()
|
|
if (not failed_tests and not failed_profile_tests) then
|
|
print("Tests OK")
|
|
end |