Allow specifing a weight for routing that is independent of duration

This commit is contained in:
Patrick Niklaus
2016-05-12 18:50:10 +02:00
committed by Patrick Niklaus
parent e463733138
commit 279f8aabfb
85 changed files with 2100 additions and 853 deletions
+44 -16
View File
@@ -1,4 +1,4 @@
api_version = 0
api_version = 1
-- Bicycle profile
@@ -92,14 +92,16 @@ surface_speeds = {
}
-- these need to be global because they are accesed externaly
properties.traffic_signal_penalty = 2
properties.u_turn_penalty = 20
properties.max_speed_for_map_matching = 110/3.6 -- kmph -> m/s
properties.use_turn_restrictions = false
properties.continue_straight_at_waypoint = false
properties.weight_name = 'duration'
--properties.weight_name = 'cyclability'
local obey_oneway = true
local ignore_areas = true
local traffic_light_penalty = 2
local u_turn_penalty = 20
local turn_penalty = 6
local turn_bias = 1.4
-- reduce the driving speed by 30% for unsafe roads
@@ -272,10 +274,6 @@ function way_function (way, result)
-- regular ways
result.forward_speed = bicycle_speeds[highway]
result.backward_speed = bicycle_speeds[highway]
if safety_penalty < 1 and unsafe_highway_list[highway] then
result.forward_speed = result.forward_speed * safety_penalty
result.backward_speed = result.backward_speed * safety_penalty
end
elseif access and access_tag_whitelist[access] then
-- unknown way, but valid access tag
result.forward_speed = default_speed
@@ -399,15 +397,45 @@ function way_function (way, result)
-- maxspeed
limit( result, maxspeed, maxspeed_forward, maxspeed_backward )
end
function turn_function (angle)
-- compute turn penalty as angle^2, with a left/right bias
-- multiplying by 10 converts to deci-seconds see issue #1318
k = 10*turn_penalty/(90.0*90.0)
if angle>=0 then
return angle*angle*k/turn_bias
else
return angle*angle*k*turn_bias
-- convert duration into cyclability
local is_unsafe = safety_penalty < 1 and unsafe_highway_list[highway]
if result.forward_speed > 0 then
-- convert from km/h to m/s
result.forward_rate = result.forward_speed / 3.6;
if is_unsafe then
result.forward_rate = result.forward_rate * safety_penalty
end
end
if result.backward_speed > 0 then
-- convert from km/h to m/s
result.backward_rate = result.backward_speed / 3.6;
if is_unsafe then
result.backward_rate = result.backward_rate * safety_penalty
end
end
if result.duration > 0 then
result.weight = result.duration;
if is_unsafe then
result.weight = result.weight * (1+safety_penalty)
end
end
end
function turn_function(turn)
-- compute turn penalty as angle^2, with a left/right bias
local normalized_angle = turn.angle / 90.0
if normalized_angle >= 0.0 then
turn.duration = normalized_angle * normalized_angle * turn_penalty / turn_bias
else
turn.duration = normalized_angle * normalized_angle * turn_penalty * turn_bias
end
if turn.direction_modifier == direction_modifier.uturn then
turn.duration = turn.duration + u_turn_penalty
end
if turn.has_traffic_light then
turn.duration = turn.duration + traffic_light_penalty
end
end
+37 -19
View File
@@ -1,4 +1,4 @@
api_version = 0
api_version = 1
-- Car profile
local find_access_tag = require("lib/access").find_access_tag
@@ -190,16 +190,19 @@ maxspeed_table = {
}
-- set profile properties
properties.u_turn_penalty = 20
properties.traffic_signal_penalty = 2
properties.max_speed_for_map_matching = 180/3.6 -- 180kmph -> m/s
properties.use_turn_restrictions = true
properties.continue_straight_at_waypoint = true
properties.left_hand_driving = false
-- this will use the duration and {forward/backward}_speed values as weight
properties.weight_name = 'duration'
--properties.weight_name = 'distance'
local side_road_speed_multiplier = 0.8
local turn_penalty = 7.5
local traffic_light_penalty = 2
local u_turn_penalty = 20
-- Note: this biases right-side driving. Should be
-- inverted for left-driving countries.
local turn_bias = properties.left_hand_driving and 1/1.075 or 1.075
@@ -335,7 +338,7 @@ function is_way_blocked(way,result)
if ignore_areas and "yes" == area then
return false
end
-- respect user-preference for toll=yes ways
local toll = way:get_value_by_key("toll")
if ignore_toll_ways and "yes" == toll then
@@ -445,7 +448,7 @@ function handle_speed(way,result,data)
if -1 == result.forward_speed and -1 == result.backward_speed 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_maxspeed(way,data,result) == false then return false end
@@ -454,10 +457,9 @@ function handle_speed(way,result,data)
end
-- reduce speed on special side roads
function handle_side_roads(way,result)
function handle_side_roads(way,result)
local sideway = way:get_value_by_key("side_road")
if "yes" == sideway or
"rotary" == sideway then
if "yes" == sideway or "rotary" == sideway then
result.forward_speed = result.forward_speed * side_road_speed_multiplier
result.backward_speed = result.backward_speed * side_road_speed_multiplier
end
@@ -562,7 +564,7 @@ function handle_speed_scaling(way,result)
end
end
local is_bidirectional = result.forward_mode ~= mode.inaccessible and
local is_bidirectional = result.forward_mode ~= mode.inaccessible and
result.backward_mode ~= mode.inaccessible
local service = way:get_value_by_key("service")
@@ -605,7 +607,7 @@ function handle_oneway(way,result,data)
else
local junction = way:get_value_by_key("junction")
if data.highway == "motorway" or
junction == "roundabout" or
junction == "roundabout" or
junction == "circular" then
if oneway ~= "no" then
-- implied oneway
@@ -659,7 +661,7 @@ end
-- determine if this way can be used as a start/end point for routing
function handle_startpoint(way,result)
-- only allow this road as start point if it not a ferry
result.is_startpoint = result.forward_mode == mode.driving or
result.is_startpoint = result.forward_mode == mode.driving or
result.backward_mode == mode.driving
end
@@ -678,7 +680,7 @@ function way_function(way, result)
-- unnecessary work. this implies we should check things that
-- commonly forbids access early, and handle complicated edge
-- cases later.
-- perform an quick initial check and abort if way is obviously
-- not routable, e.g. because it does not have any of the key
-- tags indicating routability
@@ -728,14 +730,30 @@ function way_function(way, result)
if handle_names(way,result) == false then return end
end
function turn_function (angle)
function turn_function (turn)
-- 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.
-- multiplying by 10 converts to deci-seconds see issue #1318
if angle>=0 then
return 10 * turn_penalty / (1 + 2.718 ^ - ((13 / turn_bias) * angle/180 - 6.5*turn_bias))
else
return 10 * turn_penalty / (1 + 2.718 ^ - ((13 * turn_bias) * - angle/180 - 6.5/turn_bias))
if turn.turn_type ~= turn_type.no_turn then
if turn.angle >= 0 then
turn.duration = turn_penalty / (1 + math.exp( -((13 / turn_bias) * turn.angle/180 - 6.5*turn_bias)))
else
turn.duration = turn_penalty / (1 + math.exp( -((13 * turn_bias) * -turn.angle/180 - 6.5/turn_bias)))
end
if turn.direction_modifier == direction_modifier.u_turn then
turn.duration = turn.duration + u_turn_penalty
end
if turn.has_traffic_light then
turn.duration = turn.duration + traffic_light_penalty
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
end
end
-1
View File
@@ -36,7 +36,6 @@ obey_oneway = true
use_restrictions = true
ignore_areas = true -- future feature
traffic_signal_penalty = 7 -- seconds
u_turn_penalty = 20
-- nodes processing, called from OSRM
function node_function(node)
+34 -20
View File
@@ -1,4 +1,4 @@
api_version = 0
api_version = 1
-- Foot profile
local find_access_tag = require("lib/access").find_access_tag
@@ -21,16 +21,16 @@ barrier_whitelist = Set {
'block'
}
access_tag_whitelist = Set {
'yes',
'foot',
'permissive',
'designated'
'yes',
'foot',
'permissive',
'designated'
}
access_tag_blacklist = Set {
'no',
'private',
'agricultural',
'forestry',
'no',
'private',
'agricultural',
'forestry',
'delivery'
}
@@ -103,11 +103,13 @@ leisure_speeds = {
track = walking_speed
}
properties.traffic_signal_penalty = 2
properties.u_turn_penalty = 2
properties.max_speed_for_map_matching = 40/3.6 -- kmph -> m/s
properties.use_turn_restrictions = false
properties.continue_straight_at_waypoint = false
properties.weight_name = 'duration'
local traffic_light_penalty = 2
local u_turn_penalty = 2
@@ -193,7 +195,7 @@ function initial_routability_check(way,result,data)
data.platform = way:get_value_by_key("platform")
data.amenity = way:get_value_by_key("amenity")
data.public_transport = way:get_value_by_key("public_transport")
return data.highway ~= nil or
data.leisure ~= nil or
data.route ~= nil or
@@ -293,14 +295,14 @@ function handle_speed(way,result,data)
amenity_speeds[data.amenity] or
man_made_speeds[data.man_made] or
leisure_speeds[data.leisure]
if speed then
-- set speed by way type
result.forward_speed = highway_speed
result.backward_speed = highway_speed
result.forward_speed = speed
result.backward_speed = speed
else
else
-- Set the avg speed on ways that are marked accessible
if access_tag_whitelist[data.forward_access] then
result.forward_speed = speed_profile["default"]
@@ -315,7 +317,7 @@ function handle_speed(way,result,data)
if -1 == result.forward_speed and -1 == result.backward_speed then
return false
end
if handle_surface(way,result) == false then return false end
end
@@ -398,9 +400,9 @@ function handle_oneway(way,result,data)
elseif oneway_handling == 'specific' then
oneway = Directional.get_value_by_prefixed_sequence(way,restrictions,'oneway')
end
data.oneway = oneway
if oneway then
if oneway == "-1" then
data.is_reverse_oneway = true
@@ -413,7 +415,7 @@ function handle_oneway(way,result,data)
else
local junction = way:get_value_by_key("junction")
if data.highway == "motorway" or
junction == "roundabout" or
junction == "roundabout" or
junction == "circular" then
if oneway ~= "no" then
-- implied oneway
@@ -436,7 +438,7 @@ end
-- determine if this way can be used as a start/end point for routing
function handle_startpoint(way,result)
-- only allow this road as start point if it not a ferry
result.is_startpoint = result.forward_mode == mode.walking or
result.is_startpoint = result.forward_mode == mode.walking or
result.backward_mode == mode.walking
end
@@ -455,7 +457,7 @@ function way_function(way, result)
-- unnecessary work. this implies we should check things that
-- commonly forbids access early, and handle complicated edge
-- cases later.
-- perform an quick initial check and abort if way is obviously
-- not routable, e.g. because it does not have any of the key
-- tags indicating routability
@@ -497,3 +499,15 @@ function way_function(way, result)
-- set name, ref and pronunciation
if handle_names(way,result) == false then return end
end
function turn_function (turn)
turn.duration = 0.
if turn.direction_modifier == direction_modifier.u_turn then
turn.duration = turn.duration + u_turn_penalty
end
if turn.has_traffic_light then
turn.duration = traffic_light_penalty
end
end
+16 -9
View File
@@ -1,4 +1,4 @@
api_version = 0
api_version = 1
-- Rasterbot profile
-- Minimalist node_ and way_functions in order to test source_ and segment_functions
@@ -37,18 +37,25 @@ function source_function ()
)
end
function segment_function (source, target, distance, weight)
local sourceData = sources:query(raster_source, source.lon, source.lat)
local targetData = sources:query(raster_source, target.lon, target.lat)
function segment_function (segment)
local sourceData = sources:query(raster_source, segment.source.lon, segment.source.lat)
local targetData = sources:query(raster_source, segment.target.lon, segment.target.lat)
io.write("evaluating segment: " .. sourceData.datum .. " " .. targetData.datum .. "\n")
local invalid = sourceData.invalid_data()
local scaled_weight = segment.weight
local scaled_duration = segment.duration
if sourceData.datum ~= invalid and targetData.datum ~= invalid then
local slope = math.abs(sourceData.datum - targetData.datum) / distance
local slope = math.abs(sourceData.datum - targetData.datum) / segment.distance
scaled_weight = scaled_weight / (1.0 - (slope * 5.0))
scaled_duration = scaled_duration / (1.0 - (slope * 5.0))
io.write(" slope: " .. slope .. "\n")
io.write(" was speed: " .. weight.speed .. "\n")
weight.speed = weight.speed * (1 - (slope * 5))
io.write(" new speed: " .. weight.speed .. "\n")
io.write(" was weight: " .. segment.weight .. "\n")
io.write(" new weight: " .. scaled_weight .. "\n")
io.write(" was duration: " .. segment.duration .. "\n")
io.write(" new duration: " .. scaled_duration .. "\n")
end
segment.weight = scaled_weight
segment.duration = scaled_duration
end
+15 -8
View File
@@ -1,4 +1,4 @@
api_version = 0
api_version = 1
-- Rasterbot profile
-- Minimalist node_ and way_functions in order to test source_ and segment_functions
@@ -37,18 +37,25 @@ function source_function ()
)
end
function segment_function (source, target, distance, weight)
local sourceData = sources:interpolate(raster_source, source.lon, source.lat)
local targetData = sources:interpolate(raster_source, target.lon, target.lat)
function segment_function (segment)
local sourceData = sources:interpolate(raster_source, segment.source.lon, segment.source.lat)
local targetData = sources:interpolate(raster_source, segment.target.lon, segment.target.lat)
io.write("evaluating segment: " .. sourceData.datum .. " " .. targetData.datum .. "\n")
local invalid = sourceData.invalid_data()
local scaled_weight = segment.weight
local scaled_duration = segment.duration
if sourceData.datum ~= invalid and targetData.datum ~= invalid then
local slope = math.abs(sourceData.datum - targetData.datum) / distance
local slope = math.abs(sourceData.datum - targetData.datum) / segment.distance
io.write(" slope: " .. slope .. "\n")
io.write(" was speed: " .. weight.speed .. "\n")
io.write(" was weight: " .. segment.weight .. "\n")
io.write(" was speed: " .. segment.duration .. "\n")
weight.speed = weight.speed * (1 - (slope * 5))
io.write(" new speed: " .. weight.speed .. "\n")
scaled_weight = scaled_weight / (1 - (slope * 5))
io.write(" new weight: " .. scaled_weight .. "\n")
scaled_duration = scaled_duration / (1 - (slope * 5))
io.write(" new speed: " .. scaled_duration .. "\n")
end
segment.weight = scaled_weight
segment.duration = scaled_duration
end
+15 -3
View File
@@ -1,4 +1,4 @@
api_version = 0
api_version = 1
-- Testbot profile
-- Moves at fixed, well-known speeds, practical for testing speed and travel times:
@@ -19,9 +19,11 @@ speed_profile = {
properties.continue_straight_at_waypoint = true
properties.use_turn_restrictions = true
properties.traffic_signal_penalty = 7 -- seconds
properties.u_turn_penalty = 20
properties.max_speed_for_map_matching = 30/3.6 --km -> m/s
properties.weight_name = 'duration'
local uturn_penalty = 20
local traffic_light_penalty = 7 -- seconds
function limit_speed(speed, limits)
-- don't use ipairs(), since it stops at the first nil value
@@ -114,3 +116,13 @@ function way_function (way, result)
result.roundabout = true
end
end
function turn_function (turn)
if turn.direction_modifier == direction_modifier.uturn then
turn.duration = uturn_penalty
turn.weight = uturn_penalty
end
if turn.has_traffic_light then
turn.duration = turn.duration + traffic_light_penalty
end
end
+3 -4
View File
@@ -1,11 +1,10 @@
api_version = 0
api_version = 1
-- Testbot, with turn penalty
-- Used for testing turn penalties
require 'testbot'
function turn_function (angle)
-- multiplying by 10 converts to deci-seconds see issue #1318
return 10*20*math.abs(angle)/180
function turn_function (turn)
turn.duration = 20 * math.abs(turn.angle) / 180
end