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