- enduro.lua: блокировка нод barrier=gate|bollard|lift_gate|chain|cycle_barrier| motorcycle_barrier|border_control|block через mode.inaccessible (ADR-001). cattle_grid и ford остаются проезжими. - enduro.lua: highway=footway|pedestrian|steps|corridor полностью исключены из графа (early return в process_way). Эти типы удалены из highway_rate и highway_speeds, чтобы профиль был самодостаточным. - scripts/rebuild-osrm.sh: пересборка графа (extract → partition → customize) и рестарт контейнера osrm-routed. - tests/integration/test_routing_barriers.py: 7 тестов (TC-001..TC-005 + статический анализ blocked_barriers/excluded_highways). Интеграционные тесты скипаются если OSRM не доступен. Refs: ET-001
179 lines
6.2 KiB
Lua
179 lines
6.2 KiB
Lua
-- enduro.lua — OSRM профиль для эндуро-роутинга "Дикий путь"
|
||
-- Логика: weight = distance / forward_rate
|
||
-- Чтобы грунтовки были ДЕШЕВЛЕ асфальта → у грунтовок forward_rate БОЛЬШЕ
|
||
-- (высокий rate → маленький weight на тот же distance)
|
||
-- У асфальта forward_rate МЕНЬШЕ → большой weight → OSRM избегает
|
||
-- Обновлён: 2026-05-15 (ET-001: блокировка шлагбаумов через mode.inaccessible,
|
||
-- исключение footway/pedestrian/steps/corridor из графа)
|
||
|
||
api_version = 4
|
||
|
||
-- forward_rate: чем ВЫШЕ — тем ПРЕДПОЧТИТЕЛЬНЕЕ маршрут
|
||
-- грунтовки = высокий rate (предпочтительны)
|
||
-- асфальт = низкий rate (избегаем, но штраф 3-5x вместо 17-200x)
|
||
-- Примечание: footway/pedestrian/steps/corridor отсутствуют — они полностью исключены
|
||
-- из графа в process_way (ET-001, F-08).
|
||
local highway_rate = {
|
||
track = 100.0, -- самый предпочтительный
|
||
bridleway = 90.0,
|
||
path = 85.0,
|
||
cycleway = 70.0,
|
||
unclassified = 45.0,
|
||
residential = 35.0,
|
||
service = 28.0,
|
||
tertiary = 28.0, -- было 6.0 → теперь ~3.5x хуже track
|
||
tertiary_link= 28.0,
|
||
secondary = 22.0, -- было 3.0 → теперь ~4.5x хуже track
|
||
secondary_link = 22.0,
|
||
primary = 18.0, -- было 1.5 → теперь ~5.5x хуже track
|
||
primary_link = 18.0,
|
||
trunk = 12.0, -- было 0.5
|
||
trunk_link = 12.0,
|
||
motorway = 5.0, -- было 0.1
|
||
motorway_link= 5.0,
|
||
}
|
||
|
||
-- Скорости (км/ч) — только для ETA (duration), не влияют на выбор маршрута
|
||
local highway_speeds = {
|
||
track = 30,
|
||
bridleway = 20,
|
||
path = 20,
|
||
cycleway = 25,
|
||
unclassified = 40,
|
||
residential = 40,
|
||
service = 30,
|
||
tertiary = 60,
|
||
tertiary_link= 60,
|
||
secondary = 70,
|
||
secondary_link = 70,
|
||
primary = 80,
|
||
primary_link = 80,
|
||
trunk = 90,
|
||
trunk_link = 90,
|
||
motorway = 110,
|
||
motorway_link= 90,
|
||
}
|
||
|
||
-- Мультипликатор по качеству грунтовки (grade1 лучше grade5)
|
||
local tracktype_multiplier = {
|
||
grade1 = 1.2,
|
||
grade2 = 1.1,
|
||
grade3 = 1.0,
|
||
grade4 = 0.9,
|
||
grade5 = 0.8,
|
||
}
|
||
|
||
-- ET-001 (F-07): полный запрет проезда через ноды-шлагбаумы.
|
||
-- cattle_grid и ford НЕ включены — мотоцикл их проходит.
|
||
local blocked_barriers = {
|
||
gate = true,
|
||
bollard = true,
|
||
lift_gate = true,
|
||
chain = true,
|
||
cycle_barrier = true,
|
||
motorcycle_barrier = true,
|
||
border_control = true,
|
||
block = true,
|
||
}
|
||
|
||
-- ET-001 (F-08): пешеходные/служебные типы дорог, полностью исключаемые из графа.
|
||
local excluded_highways = {
|
||
footway = true,
|
||
pedestrian = true,
|
||
steps = true,
|
||
corridor = true,
|
||
}
|
||
|
||
function setup()
|
||
return {
|
||
properties = {
|
||
weight_name = 'routability',
|
||
max_speed_for_map_matching = 30/3.6,
|
||
call_tagless_node_function = false,
|
||
traffic_light_penalty = 2,
|
||
u_turn_penalty = 20,
|
||
continue_straight_at_waypoint = false,
|
||
use_turn_restrictions = false,
|
||
}
|
||
}
|
||
end
|
||
|
||
-- ET-001 (F-07): шлагбаумы блокируются жёстко через mode.inaccessible.
|
||
-- Тег access не учитывается — физическое наличие шлагбаума уже причина обхода.
|
||
function process_node(profile, node, result)
|
||
local barrier = node:get_value_by_key("barrier")
|
||
if barrier and blocked_barriers[barrier] then
|
||
result.barrier = true
|
||
result.forward_mode = mode.inaccessible
|
||
result.backward_mode = mode.inaccessible
|
||
return
|
||
end
|
||
end
|
||
|
||
function process_way(profile, way, result)
|
||
local highway = way:get_value_by_key("highway")
|
||
if not highway then return end
|
||
|
||
-- ET-001 (F-08): пешеходные/служебные типы — полностью убираем из графа.
|
||
if excluded_highways[highway] then return end
|
||
|
||
local rate = highway_rate[highway]
|
||
if not rate then return end
|
||
|
||
-- path/cycleway в городской застройке — исключить
|
||
if highway == "path" or highway == "cycleway" then
|
||
local landuse = way:get_value_by_key("landuse")
|
||
local place = way:get_value_by_key("place")
|
||
-- Признаки городской застройки
|
||
if landuse == "residential" or landuse == "commercial" or landuse == "industrial" or
|
||
place == "city" or place == "town" or place == "village" then
|
||
return -- исключить из графа
|
||
end
|
||
end
|
||
|
||
local speed = highway_speeds[highway] or 30
|
||
|
||
-- Мультипликатор по tracktype для грунтовок
|
||
local tracktype = way:get_value_by_key("tracktype")
|
||
if tracktype and tracktype_multiplier[tracktype] then
|
||
rate = rate * tracktype_multiplier[tracktype]
|
||
end
|
||
|
||
result.forward_mode = mode.driving
|
||
result.backward_mode = mode.driving
|
||
|
||
-- duration = реальное время (скорость в км/ч)
|
||
result.forward_speed = speed
|
||
result.backward_speed = speed
|
||
|
||
-- weight = distance / rate
|
||
-- высокий rate → маленький weight → предпочтительный маршрут
|
||
result.forward_rate = rate
|
||
result.backward_rate = rate
|
||
|
||
-- Одностороннее движение
|
||
local oneway = way:get_value_by_key("oneway")
|
||
if oneway == "yes" or oneway == "1" or oneway == "true" then
|
||
result.backward_mode = mode.inaccessible
|
||
elseif oneway == "-1" then
|
||
result.forward_mode = mode.inaccessible
|
||
end
|
||
end
|
||
|
||
function process_turn(profile, turn)
|
||
turn.duration = 0
|
||
turn.weight = 0
|
||
|
||
if turn.is_u_turn then
|
||
turn.duration = profile.properties.u_turn_penalty
|
||
turn.weight = profile.properties.u_turn_penalty
|
||
end
|
||
end
|
||
|
||
return {
|
||
setup = setup,
|
||
process_way = process_way,
|
||
process_node = process_node,
|
||
process_turn = process_turn,
|
||
}
|