diff --git a/features/car/weight.feature b/features/car/weight.feature new file mode 100644 index 000000000..c092f8018 --- /dev/null +++ b/features/car/weight.feature @@ -0,0 +1,56 @@ +@routing @car @weight +Feature: Car - weights + + Background: Use specific speeds + Given the profile "car" + + Scenario: Only routes down service road when that's the destination + Given the node map + """ + a--b--c + | + d + | + e--f--g + """ + And the ways + | nodes | highway | + | abc | residential | + | efg | residential | + | cg | tertiary | + | bdf | service | + When I route I should get + | from | to | route | speed | + | a | e | abc,cg,efg,efg | 23 km/h | + | a | d | abc,bdf,bdf | 14 km/h | + + Scenario: Does not jump off the highway to go down service road + Given the node map + """ + a + | + b + |\ + | e + |/ + c + | + d + """ + And the ways + | nodes | highway | + | ab | primary | + | bc | primary | + | cd | primary | + | be | service | + | ec | service | + And the extract extra arguments "--generate-edge-lookup" + And the contract extra arguments "--segment-speed-file {speeds_file}" + And the speed file + """ + 2,4,8 + """ + When I route I should get + | from | to | route | speed | + | a | d | ab,bc,cd,cd | 14 km/h | + | a | e | ab,be,be | 19 km/h | diff --git a/profiles/car.lua b/profiles/car.lua index ab7b61253..14439b48f 100644 --- a/profiles/car.lua +++ b/profiles/car.lua @@ -8,13 +8,20 @@ local Sequence = require('lib/sequence') local Handlers = require("lib/handlers") local next = next -- bind to local for speed +penalty_table = { + ["service"] = 0.5, +} + -- set profile properties 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' +-- For routing based on duration, but weighted for prefering certain roads +properties.weight_name = 'routability' +-- For shortest duration without penalties for accessibility +--properties.weight_name = 'duration' +-- For shortest distance without penalties for accessibility --properties.weight_name = 'distance' local profile = { @@ -22,7 +29,7 @@ local profile = { default_speed = 10, oneway_handling = true, - side_road_speed_multiplier = 0.8, + side_road_multiplier = 0.8, turn_penalty = 7.5, speed_reduction = 0.8, traffic_light_penalty = 2, @@ -114,12 +121,12 @@ local profile = { } }, - service_speeds = { - alley = 5, - parking = 5, - parking_aisle = 5, - driveway = 5, - ["drive-through"] = 5 + service_penalties = { + alley = 0.5, + parking = 0.5, + parking_aisle = 0.5, + driveway = 0.5, + ["drive-through"] = 0.5 }, route_speeds = { @@ -267,7 +274,6 @@ function node_function (node, result) end end - function way_function(way, result) -- the intial filtering of ways based on presence of tags -- affects processing times significantly, because all ways @@ -331,7 +337,7 @@ function way_function(way, result) 'handle_side_roads', 'handle_surface', 'handle_maxspeed', - 'handle_speed_scaling', + 'handle_penalties', 'handle_alternating_speed', -- handle turn lanes and road classification, used for guidance diff --git a/profiles/lib/handlers.lua b/profiles/lib/handlers.lua index 6a5573d78..607880a89 100644 --- a/profiles/lib/handlers.lua +++ b/profiles/lib/handlers.lua @@ -247,16 +247,6 @@ function Handlers.handle_speed(way,result,data,profile) end end --- reduce speed on special side roads -function Handlers.handle_side_roads(way,result,data,profile) - local sideway = way:get_value_by_key("side_road") - if "yes" == sideway or - "rotary" == sideway then - result.forward_speed = result.forward_speed * profile.side_road_speed_multiplier - result.backward_speed = result.backward_speed * profile.side_road_speed_multiplier - end -end - -- reduce speed on bad surfaces function Handlers.handle_surface(way,result,data,profile) local surface = way:get_value_by_key("surface") @@ -278,45 +268,58 @@ function Handlers.handle_surface(way,result,data,profile) end -- scale speeds to get better average driving times -function Handlers.handle_speed_scaling(way,result,data,profile) +function Handlers.handle_penalties(way,result,data,profile) + local service_penalty = 1.0 + local service = way:get_value_by_key("service") + if service and service_penalties[service] then + service_penalty = service_penalties[service] + end + + local width_penalty = 1.0 local width = math.huge local lanes = math.huge - if result.forward_speed > 0 or result.backward_speed > 0 then - local width_string = way:get_value_by_key("width") - if width_string and tonumber(width_string:match("%d*")) then - width = tonumber(width_string:match("%d*")) - end + local width_string = way:get_value_by_key("width") + if width_string and tonumber(width_string:match("%d*")) then + width = tonumber(width_string:match("%d*")) + end - local lanes_string = way:get_value_by_key("lanes") - if lanes_string and tonumber(lanes_string:match("%d*")) then - lanes = tonumber(lanes_string:match("%d*")) - end + local lanes_string = way:get_value_by_key("lanes") + if lanes_string and tonumber(lanes_string:match("%d*")) then + lanes = tonumber(lanes_string:match("%d*")) end local is_bidirectional = result.forward_mode ~= mode.inaccessible and result.backward_mode ~= mode.inaccessible - local service = way:get_value_by_key("service") - if result.forward_speed > 0 then - local scaled_speed = result.forward_speed * profile.speed_reduction - local penalized_speed = math.huge - if service and profile.service_speeds[service] then - penalized_speed = profile.service_speeds[service] - elseif width <= 3 or (lanes <= 1 and is_bidirectional) then - penalized_speed = result.forward_speed / 2 - end - result.forward_speed = math.min(penalized_speed, scaled_speed) + if width <= 3 or (lanes <= 1 and is_bidirectional) then + width_penalty = 0.5 end - if result.backward_speed > 0 then - local scaled_speed = result.backward_speed * profile.speed_reduction - local penalized_speed = math.huge - if service and profile.service_speeds[service]then - penalized_speed = profile.service_speeds[service] - elseif width <= 3 or (lanes <= 1 and is_bidirectional) then - penalized_speed = result.backward_speed / 2 + -- Handle high frequency reversible oneways (think traffic signal controlled, changing direction every 15 minutes). + -- Scaling speed to take average waiting time into account plus some more for start / stop. + local alternating_penalty = 1.0 + if data.oneway == "alternating" then + alternating_penalty = 0.4 + end + + local sideroad_penalty = 1.0 + data.sideroad = way:get_value_by_key("side_road") + if "yes" == data.sideroad or "rotary" == data.sideroad then + sideroad_penalty = side_road_multipler; + end + + local penalty = service_penalty * width_penalty * alternating_penalty * sideroad_penalty + + if properties.weight_name == 'routability' then + if result.forward_speed > 0 then + result.forward_rate = result.forward_speed * penalty + end + if result.backward_speed > 0 then + result.backward_rate = result.backward_speed * penalty + end + if result.duration > 0 then + result.weight = result.duration / penalty end - result.backward_speed = math.min(penalized_speed, scaled_speed) end end @@ -328,25 +331,11 @@ function Handlers.handle_maxspeed(way,result,data,profile) backward = Handlers.parse_maxspeed(backward,profile) if forward and forward > 0 then - result.forward_speed = forward + result.forward_speed = forward * speed_scaling end if backward and backward > 0 then - result.backward_speed = backward - end -end - --- Handle high frequency reversible oneways (think traffic signal controlled, changing direction every 15 minutes). --- Scaling speed to take average waiting time into account plus some more for start / stop. -function Handlers.handle_alternating_speed(way,result,data,profile) - if "alternating" == data.oneway then - local scaling_factor = 0.4 - if result.forward_speed ~= math.huge then - result.forward_speed = result.forward_speed * scaling_factor - end - if result.backward_speed ~= math.huge then - result.backward_speed = result.backward_speed * scaling_factor - end + result.backward_speed = backward * speed_scaling end end