2017-01-23 15:23:33 -05:00
|
|
|
-- Car profile
|
|
|
|
|
2016-05-12 12:50:10 -04:00
|
|
|
api_version = 1
|
2016-12-01 17:10:56 -05:00
|
|
|
|
2015-05-01 14:06:45 -04:00
|
|
|
local find_access_tag = require("lib/access").find_access_tag
|
2016-11-15 07:36:39 -05:00
|
|
|
local Set = require('lib/set')
|
|
|
|
local Sequence = require('lib/sequence')
|
2017-01-23 15:23:33 -05:00
|
|
|
local Handlers = require("lib/handlers")
|
|
|
|
local next = next -- bind to local for speed
|
2014-10-04 08:12:14 -04:00
|
|
|
|
2017-02-03 04:37:05 -05:00
|
|
|
penalty_table = {
|
|
|
|
["service"] = 0.5,
|
|
|
|
}
|
|
|
|
|
2016-03-21 17:42:47 -04:00
|
|
|
-- set profile properties
|
2016-11-01 17:13:10 -04:00
|
|
|
properties.max_speed_for_map_matching = 180/3.6 -- 180kmph -> m/s
|
2016-03-21 17:42:47 -04:00
|
|
|
properties.use_turn_restrictions = true
|
2016-04-12 12:47:00 -04:00
|
|
|
properties.continue_straight_at_waypoint = true
|
2016-07-18 09:34:12 -04:00
|
|
|
properties.left_hand_driving = false
|
2017-02-03 07:46:28 -05:00
|
|
|
-- For routing based on duration, but weighted for preferring certain roads
|
2017-02-03 04:37:05 -05:00
|
|
|
properties.weight_name = 'routability'
|
|
|
|
-- For shortest duration without penalties for accessibility
|
|
|
|
--properties.weight_name = 'duration'
|
|
|
|
-- For shortest distance without penalties for accessibility
|
2016-05-12 12:50:10 -04:00
|
|
|
--properties.weight_name = 'distance'
|
2014-04-28 11:26:31 -04:00
|
|
|
|
2017-01-23 15:23:33 -05:00
|
|
|
local profile = {
|
|
|
|
default_mode = mode.driving,
|
|
|
|
default_speed = 10,
|
|
|
|
oneway_handling = true,
|
2017-02-01 14:35:29 -05:00
|
|
|
|
2017-02-03 04:37:05 -05:00
|
|
|
side_road_multiplier = 0.8,
|
2017-01-23 15:23:33 -05:00
|
|
|
turn_penalty = 7.5,
|
|
|
|
speed_reduction = 0.8,
|
|
|
|
traffic_light_penalty = 2,
|
|
|
|
u_turn_penalty = 20,
|
2017-02-14 06:59:16 -05:00
|
|
|
restricted_penalty = 3000,
|
|
|
|
-- Note^: abstract value but in seconds correlates approximately to 50 min
|
|
|
|
-- meaning that a route through a local access way is > 50 min faster than around
|
2017-02-01 14:35:29 -05:00
|
|
|
|
2017-01-23 15:23:33 -05:00
|
|
|
-- Note: this biases right-side driving.
|
|
|
|
-- Should be inverted for left-driving countries.
|
|
|
|
turn_bias = properties.left_hand_driving and 1/1.075 or 1.075,
|
|
|
|
|
|
|
|
-- a list of suffixes to suppress in name change instructions
|
|
|
|
suffix_list = {
|
|
|
|
'N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW', 'North', 'South', 'West', 'East'
|
|
|
|
},
|
2017-02-01 14:35:29 -05:00
|
|
|
|
2017-01-23 15:23:33 -05:00
|
|
|
barrier_whitelist = Set {
|
|
|
|
'cattle_grid',
|
|
|
|
'border_control',
|
|
|
|
'checkpoint',
|
|
|
|
'toll_booth',
|
|
|
|
'sally_port',
|
|
|
|
'gate',
|
|
|
|
'lift_gate',
|
|
|
|
'no',
|
|
|
|
'entrance'
|
|
|
|
},
|
|
|
|
|
|
|
|
access_tag_whitelist = Set {
|
|
|
|
'yes',
|
|
|
|
'motorcar',
|
|
|
|
'motor_vehicle',
|
|
|
|
'vehicle',
|
|
|
|
'permissive',
|
|
|
|
'designated',
|
2017-02-14 06:59:16 -05:00
|
|
|
'hov'
|
2017-01-23 15:23:33 -05:00
|
|
|
},
|
|
|
|
|
|
|
|
access_tag_blacklist = Set {
|
|
|
|
'no',
|
|
|
|
'agricultural',
|
|
|
|
'forestry',
|
|
|
|
'emergency',
|
2017-03-03 07:38:11 -05:00
|
|
|
'psv',
|
2017-03-04 06:25:13 -05:00
|
|
|
'customers',
|
2017-03-03 07:38:11 -05:00
|
|
|
'private',
|
|
|
|
'delivery',
|
|
|
|
'destination'
|
2017-02-14 06:59:16 -05:00
|
|
|
},
|
|
|
|
|
|
|
|
restricted_access_tag_list = Set {
|
|
|
|
'private',
|
|
|
|
'delivery',
|
2017-03-04 06:25:13 -05:00
|
|
|
'destination',
|
|
|
|
'customers',
|
2017-01-23 15:23:33 -05:00
|
|
|
},
|
|
|
|
|
|
|
|
access_tags_hierarchy = Sequence {
|
|
|
|
'motorcar',
|
|
|
|
'motor_vehicle',
|
|
|
|
'vehicle',
|
|
|
|
'access'
|
|
|
|
},
|
|
|
|
|
|
|
|
service_tag_forbidden = Set {
|
|
|
|
'emergency_access'
|
|
|
|
},
|
|
|
|
|
|
|
|
restrictions = Sequence {
|
|
|
|
'motorcar',
|
|
|
|
'motor_vehicle',
|
|
|
|
'vehicle'
|
|
|
|
},
|
2017-02-01 14:35:29 -05:00
|
|
|
|
2017-01-23 15:23:33 -05:00
|
|
|
avoid = Set {
|
|
|
|
'area',
|
2017-02-14 18:20:10 -05:00
|
|
|
-- 'toll', -- uncomment this to avoid tolls
|
2017-01-23 15:23:33 -05:00
|
|
|
'reversible',
|
|
|
|
'impassable',
|
2017-02-07 06:03:48 -05:00
|
|
|
'hov_lanes',
|
|
|
|
'steps'
|
2017-01-23 15:23:33 -05:00
|
|
|
},
|
2017-02-01 14:35:29 -05:00
|
|
|
|
2017-01-23 15:23:33 -05:00
|
|
|
speeds = Sequence {
|
|
|
|
highway = {
|
|
|
|
motorway = 90,
|
|
|
|
motorway_link = 45,
|
|
|
|
trunk = 85,
|
|
|
|
trunk_link = 40,
|
|
|
|
primary = 65,
|
|
|
|
primary_link = 30,
|
|
|
|
secondary = 55,
|
|
|
|
secondary_link = 25,
|
|
|
|
tertiary = 40,
|
|
|
|
tertiary_link = 20,
|
|
|
|
unclassified = 25,
|
|
|
|
residential = 25,
|
|
|
|
living_street = 10,
|
2017-02-06 13:18:00 -05:00
|
|
|
service = 15
|
2017-01-23 15:23:33 -05:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2017-02-03 04:37:05 -05:00
|
|
|
service_penalties = {
|
|
|
|
alley = 0.5,
|
|
|
|
parking = 0.5,
|
|
|
|
parking_aisle = 0.5,
|
|
|
|
driveway = 0.5,
|
2017-02-06 13:18:00 -05:00
|
|
|
["drive-through"] = 0.5,
|
|
|
|
["drive-thru"] = 0.5
|
2017-01-23 15:23:33 -05:00
|
|
|
},
|
2017-02-01 14:35:29 -05:00
|
|
|
|
2017-03-03 07:38:11 -05:00
|
|
|
restricted_highway_whitelist = Set {
|
|
|
|
'motorway',
|
|
|
|
'motorway_link',
|
|
|
|
'trunk',
|
|
|
|
'trunk_link',
|
|
|
|
'primary',
|
|
|
|
'primary_link',
|
|
|
|
'secondary',
|
|
|
|
'secondary_link',
|
|
|
|
'tertiary',
|
|
|
|
'tertiary_link',
|
|
|
|
'residential',
|
|
|
|
'living_street',
|
|
|
|
},
|
|
|
|
|
2017-01-23 15:23:33 -05:00
|
|
|
route_speeds = {
|
|
|
|
ferry = 5,
|
|
|
|
shuttle_train = 10
|
|
|
|
},
|
|
|
|
|
|
|
|
bridge_speeds = {
|
|
|
|
movable = 5
|
|
|
|
},
|
2017-02-01 14:35:29 -05:00
|
|
|
|
2017-01-23 15:23:33 -05:00
|
|
|
-- surface/trackype/smoothness
|
|
|
|
-- values were estimated from looking at the photos at the relevant wiki pages
|
|
|
|
|
|
|
|
-- max speed for surfaces
|
|
|
|
surface_speeds = {
|
|
|
|
asphalt = nil, -- nil mean no limit. removing the line has the same effect
|
|
|
|
concrete = nil,
|
|
|
|
["concrete:plates"] = nil,
|
|
|
|
["concrete:lanes"] = nil,
|
|
|
|
paved = nil,
|
|
|
|
|
|
|
|
cement = 80,
|
|
|
|
compacted = 80,
|
|
|
|
fine_gravel = 80,
|
|
|
|
|
|
|
|
paving_stones = 60,
|
|
|
|
metal = 60,
|
|
|
|
bricks = 60,
|
|
|
|
|
|
|
|
grass = 40,
|
|
|
|
wood = 40,
|
|
|
|
sett = 40,
|
|
|
|
grass_paver = 40,
|
|
|
|
gravel = 40,
|
|
|
|
unpaved = 40,
|
|
|
|
ground = 40,
|
|
|
|
dirt = 40,
|
|
|
|
pebblestone = 40,
|
|
|
|
tartan = 40,
|
|
|
|
|
|
|
|
cobblestone = 30,
|
|
|
|
clay = 30,
|
|
|
|
|
|
|
|
earth = 20,
|
|
|
|
stone = 20,
|
|
|
|
rocky = 20,
|
|
|
|
sand = 20,
|
|
|
|
|
|
|
|
mud = 10
|
|
|
|
},
|
|
|
|
|
|
|
|
-- max speed for tracktypes
|
|
|
|
tracktype_speeds = {
|
|
|
|
grade1 = 60,
|
|
|
|
grade2 = 40,
|
|
|
|
grade3 = 30,
|
|
|
|
grade4 = 25,
|
|
|
|
grade5 = 20
|
|
|
|
},
|
|
|
|
|
|
|
|
-- max speed for smoothnesses
|
|
|
|
smoothness_speeds = {
|
|
|
|
intermediate = 80,
|
|
|
|
bad = 40,
|
|
|
|
very_bad = 20,
|
|
|
|
horrible = 10,
|
|
|
|
very_horrible = 5,
|
|
|
|
impassable = 0
|
|
|
|
},
|
|
|
|
|
|
|
|
-- http://wiki.openstreetmap.org/wiki/Speed_limits
|
|
|
|
maxspeed_table_default = {
|
|
|
|
urban = 50,
|
|
|
|
rural = 90,
|
|
|
|
trunk = 110,
|
|
|
|
motorway = 130
|
|
|
|
},
|
|
|
|
|
|
|
|
-- List only exceptions
|
|
|
|
maxspeed_table = {
|
|
|
|
["ch:rural"] = 80,
|
|
|
|
["ch:trunk"] = 100,
|
|
|
|
["ch:motorway"] = 120,
|
|
|
|
["de:living_street"] = 7,
|
|
|
|
["ru:living_street"] = 20,
|
|
|
|
["ru:urban"] = 60,
|
|
|
|
["ua:urban"] = 60,
|
|
|
|
["at:rural"] = 100,
|
|
|
|
["de:rural"] = 100,
|
|
|
|
["at:trunk"] = 100,
|
|
|
|
["cz:trunk"] = 0,
|
|
|
|
["ro:trunk"] = 100,
|
|
|
|
["cz:motorway"] = 0,
|
|
|
|
["de:motorway"] = 0,
|
|
|
|
["ru:motorway"] = 110,
|
|
|
|
["gb:nsl_single"] = (60*1609)/1000,
|
|
|
|
["gb:nsl_dual"] = (70*1609)/1000,
|
|
|
|
["gb:motorway"] = (70*1609)/1000,
|
|
|
|
["uk:nsl_single"] = (60*1609)/1000,
|
|
|
|
["uk:nsl_dual"] = (70*1609)/1000,
|
|
|
|
["uk:motorway"] = (70*1609)/1000,
|
|
|
|
["nl:rural"] = 80,
|
|
|
|
["nl:trunk"] = 100,
|
|
|
|
["none"] = 140
|
|
|
|
}
|
|
|
|
}
|
2014-03-27 13:22:04 -04:00
|
|
|
|
2016-04-22 05:31:46 -04:00
|
|
|
function get_name_suffix_list(vector)
|
2017-01-23 15:23:33 -05:00
|
|
|
for index,suffix in ipairs(profile.suffix_list) do
|
2016-04-22 05:31:46 -04:00
|
|
|
vector:Add(suffix)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-09-09 06:34:04 -04:00
|
|
|
function get_restrictions(vector)
|
2017-01-23 15:23:33 -05:00
|
|
|
for i,v in ipairs(profile.restrictions) do
|
2014-03-27 16:19:26 -04:00
|
|
|
vector:Add(v)
|
|
|
|
end
|
2012-11-12 11:00:36 -05:00
|
|
|
end
|
|
|
|
|
2014-08-27 10:44:40 -04:00
|
|
|
function node_function (node, result)
|
2014-03-27 16:19:26 -04:00
|
|
|
-- parse access and barrier tags
|
2017-01-23 15:23:33 -05:00
|
|
|
local access = find_access_tag(node, profile.access_tags_hierarchy)
|
2016-11-13 17:05:01 -05:00
|
|
|
if access then
|
2017-03-03 07:38:11 -05:00
|
|
|
if profile.access_tag_blacklist[access] and not profile.restricted_access_tag_list[access] then
|
2014-08-27 10:44:40 -04:00
|
|
|
result.barrier = true
|
2014-03-27 16:19:26 -04:00
|
|
|
end
|
2014-08-27 10:44:40 -04:00
|
|
|
else
|
|
|
|
local barrier = node:get_value_by_key("barrier")
|
2016-11-13 17:05:01 -05:00
|
|
|
if barrier then
|
2015-08-25 08:46:05 -04:00
|
|
|
-- make an exception for rising bollard barriers
|
|
|
|
local bollard = node:get_value_by_key("bollard")
|
|
|
|
local rising_bollard = bollard and "rising" == bollard
|
|
|
|
|
2017-01-23 15:23:33 -05:00
|
|
|
if not profile.barrier_whitelist[barrier] and not rising_bollard then
|
2014-08-27 10:44:40 -04:00
|
|
|
result.barrier = true
|
|
|
|
end
|
2014-03-27 16:19:26 -04:00
|
|
|
end
|
|
|
|
end
|
2012-09-19 12:35:45 -04:00
|
|
|
|
2014-08-27 10:44:40 -04:00
|
|
|
-- check if node is a traffic light
|
|
|
|
local tag = node:get_value_by_key("highway")
|
2016-11-13 17:05:01 -05:00
|
|
|
if "traffic_signals" == tag then
|
2015-09-02 06:23:26 -04:00
|
|
|
result.traffic_lights = true
|
2014-08-27 10:44:40 -04:00
|
|
|
end
|
|
|
|
end
|
2014-07-24 12:00:37 -04:00
|
|
|
|
2016-11-08 13:20:14 -05:00
|
|
|
function way_function(way, result)
|
2017-01-23 15:23:33 -05:00
|
|
|
-- the intial filtering of ways based on presence of tags
|
|
|
|
-- affects processing times significantly, because all ways
|
|
|
|
-- have to be checked.
|
|
|
|
-- to increase performance, prefetching and intial tag check
|
|
|
|
-- is done in directly instead of via a handler.
|
2016-11-17 07:56:17 -05:00
|
|
|
|
2017-01-23 15:23:33 -05:00
|
|
|
-- in general we should try to abort as soon as
|
2016-11-17 07:56:17 -05:00
|
|
|
-- possible if the way is not routable, to avoid doing
|
|
|
|
-- unnecessary work. this implies we should check things that
|
2017-02-01 14:35:29 -05:00
|
|
|
-- commonly forbids access early, and handle edge cases later.
|
2017-01-23 15:23:33 -05:00
|
|
|
|
|
|
|
-- data table for storing intermediate values during processing
|
|
|
|
local data = {
|
|
|
|
-- prefetch tags
|
|
|
|
highway = way:get_value_by_key('highway'),
|
2017-02-21 16:13:25 -05:00
|
|
|
bridge = way:get_value_by_key('bridge'),
|
2017-01-23 15:23:33 -05:00
|
|
|
route = way:get_value_by_key('route')
|
|
|
|
}
|
|
|
|
|
|
|
|
-- perform an quick initial check and abort if the way is
|
2017-02-21 16:13:25 -05:00
|
|
|
-- obviously not routable.
|
|
|
|
-- highway or route tags must be in data table, bridge is optional
|
|
|
|
if (not data.highway or data.highway == '') and
|
|
|
|
(not data.route or data.route == '')
|
|
|
|
then
|
2017-01-23 15:23:33 -05:00
|
|
|
return
|
|
|
|
end
|
2016-11-17 07:56:17 -05:00
|
|
|
|
2017-01-23 15:23:33 -05:00
|
|
|
handlers = Sequence {
|
|
|
|
-- set the default mode for this profile. if can be changed later
|
|
|
|
-- in case it turns we're e.g. on a ferry
|
|
|
|
'handle_default_mode',
|
2016-11-17 07:56:17 -05:00
|
|
|
|
2017-01-23 15:23:33 -05:00
|
|
|
-- check various tags that could indicate that the way is not
|
|
|
|
-- routable. this includes things like status=impassable,
|
|
|
|
-- toll=yes and oneway=reversible
|
|
|
|
'handle_blocked_ways',
|
2016-11-17 07:56:17 -05:00
|
|
|
|
2017-01-23 15:23:33 -05:00
|
|
|
-- determine access status by checking our hierarchy of
|
|
|
|
-- access tags, e.g: motorcar, motor_vehicle, vehicle
|
|
|
|
'handle_access',
|
2016-11-17 07:56:17 -05:00
|
|
|
|
2017-02-03 07:46:28 -05:00
|
|
|
-- check whether forward/backward directions are routable
|
2017-01-23 15:23:33 -05:00
|
|
|
'handle_oneway',
|
2016-11-18 14:49:51 -05:00
|
|
|
|
2017-02-03 07:46:28 -05:00
|
|
|
-- check whether forward/backward directions are routable
|
2017-01-23 15:23:33 -05:00
|
|
|
'handle_destinations',
|
2016-11-17 07:56:17 -05:00
|
|
|
|
2017-01-23 15:23:33 -05:00
|
|
|
-- check whether we're using a special transport mode
|
|
|
|
'handle_ferries',
|
|
|
|
'handle_movables',
|
2016-11-17 07:56:17 -05:00
|
|
|
|
2017-01-23 15:23:33 -05:00
|
|
|
-- handle service road restrictions
|
|
|
|
'handle_service',
|
2016-11-17 07:56:17 -05:00
|
|
|
|
2017-02-14 06:59:16 -05:00
|
|
|
-- handle hov
|
2017-01-23 15:23:33 -05:00
|
|
|
'handle_hov',
|
2016-11-17 07:56:17 -05:00
|
|
|
|
2017-01-23 15:23:33 -05:00
|
|
|
-- compute speed taking into account way type, maxspeed tags, etc.
|
|
|
|
'handle_speed',
|
|
|
|
'handle_surface',
|
|
|
|
'handle_maxspeed',
|
2017-02-03 04:37:05 -05:00
|
|
|
'handle_penalties',
|
2016-11-17 07:56:17 -05:00
|
|
|
|
2017-01-23 15:23:33 -05:00
|
|
|
-- handle turn lanes and road classification, used for guidance
|
|
|
|
'handle_turn_lanes',
|
|
|
|
'handle_classification',
|
2016-11-17 07:56:17 -05:00
|
|
|
|
2017-01-23 15:23:33 -05:00
|
|
|
-- handle various other flags
|
|
|
|
'handle_roundabouts',
|
|
|
|
'handle_startpoint',
|
2016-11-17 07:56:17 -05:00
|
|
|
|
2017-01-23 15:23:33 -05:00
|
|
|
-- set name, ref and pronunciation
|
2017-02-01 14:35:29 -05:00
|
|
|
'handle_names',
|
|
|
|
|
|
|
|
-- set weight properties of the way
|
|
|
|
'handle_weights'
|
2017-01-23 15:23:33 -05:00
|
|
|
}
|
2017-02-01 14:35:29 -05:00
|
|
|
|
2017-01-23 15:23:33 -05:00
|
|
|
Handlers.run(handlers,way,result,data,profile)
|
2012-09-27 05:35:56 -04:00
|
|
|
end
|
2012-11-03 03:19:01 -04:00
|
|
|
|
2016-05-12 12:50:10 -04:00
|
|
|
function turn_function (turn)
|
2016-09-06 12:07:00 -04:00
|
|
|
-- Use a sigmoid function to return a penalty that maxes out at turn_penalty
|
|
|
|
-- over the space of 0-180 degrees. Values here were chosen by fitting
|
|
|
|
-- the function to some turn penalty samples from real driving.
|
2017-01-23 15:23:33 -05:00
|
|
|
local turn_penalty = profile.turn_penalty
|
|
|
|
local turn_bias = profile.turn_bias
|
2017-02-01 14:35:29 -05:00
|
|
|
|
2017-04-19 10:47:35 -04:00
|
|
|
if turn.has_traffic_light then
|
|
|
|
turn.duration = profile.traffic_light_penalty
|
|
|
|
end
|
|
|
|
|
2016-05-12 12:50:10 -04:00
|
|
|
if turn.turn_type ~= turn_type.no_turn then
|
|
|
|
if turn.angle >= 0 then
|
2017-04-19 10:47:35 -04:00
|
|
|
turn.duration = turn.duration + turn_penalty / (1 + math.exp( -((13 / turn_bias) * turn.angle/180 - 6.5*turn_bias)))
|
2016-05-12 12:50:10 -04:00
|
|
|
else
|
2017-04-19 10:47:35 -04:00
|
|
|
turn.duration = turn.duration + turn_penalty / (1 + math.exp( -((13 * turn_bias) * -turn.angle/180 - 6.5/turn_bias)))
|
2016-05-12 12:50:10 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
if turn.direction_modifier == direction_modifier.u_turn then
|
2017-01-23 15:23:33 -05:00
|
|
|
turn.duration = turn.duration + profile.u_turn_penalty
|
2016-05-12 12:50:10 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
-- for distance based routing we don't want to have penalties based on turn angle
|
|
|
|
if properties.weight_name == 'distance' then
|
|
|
|
turn.weight = 0
|
|
|
|
else
|
|
|
|
turn.weight = turn.duration
|
|
|
|
end
|
2017-03-01 13:50:53 -05:00
|
|
|
end
|
|
|
|
if properties.weight_name == 'routability' then
|
|
|
|
-- penalize turns from non-local access only segments onto local access only tags
|
|
|
|
if not turn.source_restricted and turn.target_restricted then
|
|
|
|
turn.weight = turn.weight + profile.restricted_penalty
|
|
|
|
end
|
2015-08-30 13:17:19 -04:00
|
|
|
end
|
|
|
|
end
|