Files
enduro-trails/infra/osrm/enduro.lua
claude-bot e263f8425c
All checks were successful
CI / lint (push) Successful in 7s
CI / test (push) Successful in 6s
CI / build (push) Successful in 2s
feat(ET-001): implement barrier blocking and footway exclusion in OSRM profile
- 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
2026-05-15 22:11:32 +03:00

179 lines
6.2 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- 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,
}