BRouter Stage 1: verified on device; ship v11 lookups/profiles to match segments

End-to-end offline routing confirmed on the phone: shortest ~5.4 km in Rostov
(3.2s cold), trekking cross-tile Rostov->region 44.8 km / 316 m ascend
(1.2s), 617 ms on the apk-shipped data. JS -> Rust brouter_route -> Kotlin
engine -> GPX works through the whole chain.

The 1.6.3 distribution ships lookups.dat v10, but the live brouter.de/segments4
tiles are v11 ("lookup version mismatch"). Replaced the vendored lookups.dat +
trekking/shortest profiles with the v11 set from abrensch/brouter master
(misc/profiles2); the 1.6.3 engine accepts them. Profiles and lookups MUST match
the segments' version.
This commit is contained in:
4aiman 2026-09-09 01:07:24 +03:00
commit bc63b34cb9
6 changed files with 668 additions and 390 deletions

View file

@ -26,7 +26,12 @@ app data dir; профиль trekking (идея 2) и shortest (идея 1); л
**Success:** на телефоне с вручную положенным тайлом региона (adb push для спайка) вызов
`BRouter.route([[lon,lat],[lon,lat]], "shortest")` возвращает дорожный GPX/GeoJSON, а не ошибку.
**Tests:** ручной вызов из DevTools (CDP) + лог движка; сверить, что трек идёт по дорогам.
**Status:** not started
**Status:** DONE (проверено на устройстве 2026-09-09). `shortest` Ростов 5.4км за 3.2с;
`trekking` кросс-тайл Ростов→город 44.8км/набор 316м за 1.2с; GPX с track-length/ascend/cost.
ВАЖНО: bundled `lookups.dat` из 1.6.3 — версии 10, а живые сегменты brouter.de/segments4 — v11
(«lookup version mismatch»). Ассеты заменены на v11 из репозитория (abrensch/brouter master:
misc/profiles2/{lookups.dat,trekking.brf,shortest.brf}); движок 1.6.3 их принимает. Профили/lookups
ОБЯЗАНЫ совпадать по версии с сегментами.
## Stage 2 — Экран загрузки сегментов по проводу
**Goal:** пользователь скачивает тайлы `.rd5` региона внутри BalDav в app data dir.

View file

@ -39,9 +39,13 @@ BRouter — **маршрутизатор без карты**: на вход оп
рельефа, по которому он считает набор высоты (см. §4). Без SRTM сегменты соберутся, но без
высот — маршруты «с малым набором» не получатся.
- Для нашего региона (Ростовская обл., ~47N/40E) нужны тайлы, чьи SW-углы кратны 5:
вероятно **`E35_N45.rd5`** (35–40E, 45–50N) и **`E40_N45.rd5`** (40–45E) — город ~40.1E
попадает во второй. Точные имена и размер (обычно десятки МБ на тайл) — **проверить при
загрузке**. Загрузка одноразовая по проводу — тот же паттерн «скачать дома», что для DEM/прогноза.
**`E35_N45.rd5`** (35–40E, 45–50N, ~23.8 МБ) и **`E40_N45.rd5`** (40–45E, ~14.1 МБ) —
город ~40.1E попадает во второй (проверено загрузкой). Одноразовая загрузка по проводу —
тот же паттерн «скачать дома», что для DEM/прогноза.
- **ВЕРСИЯ ДАННЫХ (важно, проверено на устройстве).** `lookups.dat` и профили ОБЯЗАНЫ совпадать
по версии с сегментами, иначе «lookup version mismatch». Дистрибутив 1.6.3 несёт `lookups.dat`
версии 10, а живые сегменты brouter.de/segments4 — версии 11. Взяли v11 lookups.dat + профили из
репозитория (abrensch/brouter master, `misc/profiles2/`); движок 1.6.3 их принимает и роутит.
## 3. Как строится маршрут (движок)

View file

@ -37,3 +37,14 @@ README не трогал: пользовательской фичи пока н
## Следующие шаги
- Ответы пользователя на открытые вопросы §9 разбора → планировать идею 1 и/или идею 2.
- Опционально PoC: RouteServer на компе + сегменты региона (нужен JRE + загрузка, по согласию).
## Дополнение 2026-09-09: Этап 1 проверен на устройстве
Поставил сборку с мостом, залил тайлы E35_N45/E40_N45 в files/brouter/segments4 (adb push →
run-as cp), запустил через CDP. Первый вызов упал: «lookup version mismatch lookups.dat=10 rd5=11»
— дистрибутив 1.6.3 несёт lookups.dat v10, а сегменты brouter.de/segments4 — v11. Взял v11
lookups.dat + trekking.brf + shortest.brf из abrensch/brouter master (misc/profiles2), заменил
вложенные ассеты; движок 1.6.3 их принял. Результаты: shortest Ростов ~5.4км за 3.2с (холодный),
trekking Ростов→город 44.8км/набор 316м за 1.2с (кросс-тайл), на зашитых в apk v11-данных
617мс. Мост JS→Rust→Kotlin(движок)→GPX работает целиком. Этап 1 = DONE.
Урок: профили и lookups.dat ОБЯЗАНЫ совпадать по версии с сегментами (сейчас v11).

View file

@ -7,12 +7,18 @@ assign downhillcutoff 1.5
assign uphillcost 0
assign uphillcutoff 1.5
assign turnInstructionMode = 1 # 0=none, 1=auto-choose, 2=locus-style, 3=osmand-style, 4=comment-style, 5=gpsies-style, 6=orux-style
assign turnInstructionMode = 1 # %turnInstructionMode% | Mode for the generated turn instructions | [0=none, 1=auto-choose, 2=locus-style, 3=osmand-style, 4=comment-style, 5=gpsies-style, 6=orux-style, 7=locus-old-style]
assign validForFoot 1
assign use_proposed_cycleroutes = false # %use_proposed_cycleroutes% | Set to true to consider proposed and regular cycleroutes as equals | boolean
---context:way # following code refers to way-tags
assign any_cycleroute or route_bicycle_icn=yes or route_bicycle_ncn=yes or route_bicycle_rcn=yes route_bicycle_lcn=yes
assign any_cycleroute
switch not use_proposed_cycleroutes
or route_bicycle_icn=yes or route_bicycle_ncn=yes or route_bicycle_rcn=yes route_bicycle_lcn=yes
or route_bicycle_icn=yes|proposed or route_bicycle_ncn=yes|proposed or route_bicycle_rcn=yes|proposed route_bicycle_lcn=yes|proposed
assign nodeaccessgranted or any_cycleroute lcn=yes
assign turncost 0
@ -29,35 +35,35 @@ assign initialcost switch route=ferry 10000 0
#
assign defaultaccess
switch access=
not motorroad=yes
(
if motorroad=yes then false
else if highway=motorway|motorway_link then false
else true
)
switch or access=private access=no
0
1
false
true
#
# calculate logical bike access
#
assign bikeaccess
or any_cycleroute
switch bicycle=
switch bicycle_road=yes
1
switch vehicle=
defaultaccess
switch or vehicle=private vehicle=no
0
1
not or bicycle=private or bicycle=no bicycle=dismount
switch bicycle=
switch bicycle_road=yes
true
switch vehicle=
( if highway=footway then false else defaultaccess )
not vehicle=private|no
not or bicycle=private or bicycle=no or bicycle=dismount bicycle=use_sidepath
#
# calculate logical foot access
#
assign footaccess
or bikeaccess
or bicycle=dismount
switch foot=
defaultaccess
not or foot=private foot=no
or bicycle=dismount
switch foot=
defaultaccess
not or foot=private or foot=no foot=use_sidepath
assign accesspenalty switch or bikeaccess footaccess 0 100000

View file

@ -9,16 +9,26 @@
assign validForBikes = true
# Use the following switches to change behaviour
assign allow_steps = true # %allow_steps% | Set to false to disallow steps | boolean
assign allow_ferries = true # %allow_ferries% | set to false to disallow ferries | boolean
assign ignore_cycleroutes = false # %ignore_cycleroutes% | Set to true for better elevation results | boolean
assign stick_to_cycleroutes = false # %stick_to_cycleroutes% | Set to true to just follow cycleroutes | boolean
assign avoid_unsafe = false # %avoid_unsafe% | Set to true to avoid standard highways | boolean
assign considerTurnRestrictions = true # %considerTurnRestrictions% | Set to true to take turn restrictions into account | boolean
assign processUnusedTags = false # %processUnusedTags% | Set to true to output unused tags in data tab | boolean
assign allow_steps = true # %allow_steps% | Set false to disallow steps | boolean
assign allow_ferries = true # %allow_ferries% | Set false to disallow ferries | boolean
assign ignore_cycleroutes = false # %ignore_cycleroutes% | Set true for better elevation results | boolean
assign stick_to_cycleroutes = false # %stick_to_cycleroutes% | Set true to just follow cycleroutes | boolean
assign use_proposed_cycleroutes = false # %use_proposed_cycleroutes% | Set to true to consider proposed and regular cycleroutes as equals | boolean
assign avoid_unsafe = false # %avoid_unsafe% | Set true to avoid standard highways | boolean
assign add_beeline = false # %add_beeline% | Enable beeline on distant start/end points | boolean
assign consider_noise = false # %consider_noise% | Activate to prefer a low-noise route | boolean
assign consider_river = false # %consider_river% | Activate to prefer a route along rivers, lakes, etc. | boolean
assign consider_forest = false # %consider_forest% | Activate to prefer a route in forest or parks | boolean
assign consider_town = false # %consider_town% | Activate to bypass cities / big towns as far as possible | boolean
assign consider_traffic = false # %consider_traffic% | Activate to consider traffic estimates | boolean
# Change elevation parameters
assign consider_elevation = true # %consider_elevation% | Set to false to ignore elevation in routing | boolean
assign consider_elevation = true # %consider_elevation% | Set true to favor a route with few elevation meters | boolean
assign downhillcost = 60 # %downhillcost% | Cost for going downhill | number
assign downhillcutoff = 1.5 # %downhillcutoff% | Gradients below this value in percents are not counted. | number
assign uphillcost = 0 # %uphillcost% | Cost for going uphill | number
@ -35,10 +45,18 @@ assign C_r = 0.01 # %C_r% | Rolling resistance coefficient (dimensionle
assign bikerPower = 100 # %bikerPower% | Average power (in W) provided by the biker, for travel time computation | number
# Turn instructions settings
assign turnInstructionMode = 1 # %turnInstructionMode% | Mode for the generated turn instructions | [0=none, 1=auto-choose, 2=locus-style, 3=osmand-style, 4=comment-style, 5=gpsies-style, 6=orux-style]
assign turnInstructionMode = 1 # %turnInstructionMode% | Mode for the generated turn instructions | [0=none, 1=auto-choose, 2=locus-style, 3=osmand-style, 4=comment-style, 5=gpsies-style, 6=orux-style, 7=locus-old-style]
assign turnInstructionCatchingRange = 40 # %turnInstructionCatchingRange% | Within this distance (in m) several turning instructions are combined into one and the turning angles are better approximated to the general direction | number
assign turnInstructionRoundabouts = true # %turnInstructionRoundabouts% | Set to "false" to avoid generating special turning instructions for roundabouts | boolean
assign turnInstructionRoundabouts = true # %turnInstructionRoundabouts% | Set "false" to avoid generating special turning instructions for roundabouts | boolean
assign considerTurnRestrictions = true # %considerTurnRestrictions% | Set true to take turn restrictions into account | boolean
# with engine defaults, long parts of routing to via points may be removed
assign correctMisplacedViaPoints = false # %correctMisplacedViaPoints% | Set to true to remove detours due to via points (going back and forth on the same route) | boolean
assign correctMisplacedViaPointsDistance = 400 # %correctMisplacedViaPointsDistance% | Only remove detours shorter than this (one-way) distance (in m) (engine defaults to 0 which removes detours whatever their length) | number
assign processUnusedTags = false # %processUnusedTags% | Set true to output unused tags in data tab | boolean
assign unpavedPenalty = 1.0 # %unpavedPenalty% | Extra penalty multiplier applied to the non-probablyGood cost of track/road/path/footway ways depending on tracktype grade | number
---context:way # following code refers to way-tags
@ -51,11 +69,18 @@ assign classifier_ferry = 2
#
assign any_cycleroute =
if not use_proposed_cycleroutes then
if route_bicycle_icn=yes then true
else if route_bicycle_ncn=yes then true
else if route_bicycle_rcn=yes then true
else if route_bicycle_lcn=yes then true
else false
else
if route_bicycle_icn=yes|proposed then true
else if route_bicycle_ncn=yes|proposed then true
else if route_bicycle_rcn=yes|proposed then true
else if route_bicycle_lcn=yes|proposed then true
else false
assign nodeaccessgranted =
if any_cycleroute then true
@ -65,9 +90,17 @@ assign is_ldcr =
if ignore_cycleroutes then false
else any_cycleroute
assign isbike = or bicycle_road=yes or bicycle=yes or or bicycle=permissive bicycle=designated lcn=yes
assign ispaved = surface=paved|asphalt|concrete|paving_stones|sett
assign isunpaved = not or surface= or ispaved surface=fine_gravel|cobblestone
# set isbike considering access, local cycle route or the presence of a cycleway on the highway
assign hasbikerouteoraccess =
or bicycle_road=yes or cyclestreet=yes or bicycle=yes|permissive|designated lcn=yes
assign hascycleway = not
and ( or cycleway= cycleway=no|none ) and ( or cycleway:left= cycleway:left=no ) and ( or cycleway:right= cycleway:right=no ) ( or cycleway:both= cycleway:both=no )
assign isbike = or hasbikerouteoraccess hascycleway
assign ispaved = or surface=paved|asphalt|concrete|paving_stones|sett smoothness=excellent|good
assign isunpaved = not or ispaved or ( and surface= smoothness= ) or surface=fine_gravel|cobblestone smoothness=intermediate|bad
assign probablyGood = or ispaved and ( or isbike highway=footway ) not isunpaved
@ -112,8 +145,7 @@ assign defaultaccess =
# calculate logical bike access
#
assign bikeaccess =
if any_cycleroute then true
else if bicycle= then
if bicycle= then
(
if bicycle_road=yes then true
else if vehicle= then ( if highway=footway then false else defaultaccess )
@ -125,18 +157,19 @@ assign bikeaccess =
# calculate logical foot access
#
assign footaccess =
if bikeaccess then true
else if bicycle=dismount then true
if bicycle=dismount then true
else if foot= then defaultaccess
else not foot=private|no
else not foot=private|no|use_sidepath
#
# if not bike-, but foot-acess, just a moderate penalty,
# if not bike-, but foot-access, just a moderate penalty,
# otherwise access is forbidden
#
assign accesspenalty =
if bikeaccess then 0
else if footaccess then 4
else if any_cycleroute then 15
else if bicycle=use_sidepath then 25
else 10000
#
@ -144,7 +177,8 @@ assign accesspenalty =
# be close to forbidden, while on other ways we just add
# 4 to the costfactor (making it at least 5 - you are allowed
# to push your bike)
#
# are we against legal direction on a oneway?
assign badoneway =
if reversedirection=yes then
if oneway:bicycle=yes then true
@ -155,8 +189,23 @@ assign badoneway =
assign onewaypenalty =
if ( badoneway ) then
(
if ( cycleway=opposite|opposite_lane|opposite_track ) then 0
if (
and hascycleway
or and cycleway:left=lane|track|shared_lane|share_busway
cycleway:left:oneway=no|-1
or and cycleway:right=lane|track|shared_lane|share_busway
cycleway:right:oneway=no|-1
or and cycleway:both=lane|track|shared_lane|share_busway
#or cycleway:both:oneway=no|-1
or cycleway:left:oneway=no|-1
cycleway:right:oneway=no|-1
or cycleway=opposite|opposite_lane|opposite_track
or cycleway:left=opposite|opposite_lane|opposite_track
cycleway:right=opposite|opposite_lane|opposite_track
) then 0
else if ( oneway:bicycle=no ) then 0
else if ( not footaccess ) then 100
else if ( junction=roundabout|circular ) then 60
else if ( highway=primary|primary_link ) then 50
else if ( highway=secondary|secondary_link ) then 30
else if ( highway=tertiary|tertiary_link ) then 20
@ -164,6 +213,57 @@ assign onewaypenalty =
)
else 0.0
# add estimate tags
assign traffic_penalty
switch consider_traffic
switch estimated_traffic_class= 0
switch estimated_traffic_class=1|2 0.2
switch estimated_traffic_class=3 0.4
switch estimated_traffic_class=4 0.6
switch estimated_traffic_class=5 0.8
switch estimated_traffic_class=6|7 1 99 0
assign noise_penalty
switch consider_noise
switch estimated_noise_class= 0
switch estimated_noise_class=1 0.3
switch estimated_noise_class=2 0.5
switch estimated_noise_class=3 0.8
switch estimated_noise_class=4 1.4
switch estimated_noise_class=5 1.7
switch estimated_noise_class=6 2 0 0
assign no_river_penalty
switch consider_river
switch estimated_river_class= 2
switch estimated_river_class=1 1.3
switch estimated_river_class=2 1
switch estimated_river_class=3 0.7
switch estimated_river_class=4 0.4
switch estimated_river_class=5 0.1
switch estimated_river_class=6 0 99 0
assign no_forest_penalty
switch consider_forest
switch estimated_forest_class= 1
switch estimated_forest_class=1 0.5
switch estimated_forest_class=2 0.4
switch estimated_forest_class=3 0.25
switch estimated_forest_class=4 0.15
switch estimated_forest_class=5 0.1
switch estimated_forest_class=6 0 99 0
assign town_penalty
switch consider_town
switch estimated_town_class= 0
switch estimated_town_class=1 0.5
switch estimated_town_class=2 0.9
switch estimated_town_class=3 1.2
switch estimated_town_class=4 1.3
switch estimated_town_class=5 1.4
switch estimated_town_class=6 1.6 99 0
#
# calculate the cost-factor, which is the factor
# by which the distance of a way-segment is multiplied
@ -180,10 +280,10 @@ assign costfactor
if ( and highway= not route=ferry ) then 10000
#
# exclude motorways and proposed roads
# exclude motorways and proposed, abandoned under construction roads
#
else if ( highway=motorway|motorway_link ) then 10000
else if ( highway=proposed|abandoned ) then 10000
else if ( highway=motorway|motorway_link ) then 10000
else if ( highway=proposed|abandoned|construction ) then 10000
#
# all other exclusions below (access, steps, ferries,..)
@ -192,6 +292,12 @@ assign costfactor
#
else min 9999
add town_penalty
add no_forest_penalty
add no_river_penalty
add noise_penalty
add traffic_penalty
#
# apply oneway-and access-penalties
#
@ -200,7 +306,7 @@ assign costfactor
#
# steps and ferries are special. Note this is handled
# before the cycleroute-switch, to be able
# to really exlude them be setting cost to infinity
# to really exclude them be setting cost to infinity
#
if ( highway=steps ) then ( if allow_steps then 40 else 10000 )
else if ( route=ferry ) then ( if allow_ferries then 5.67 else 10000 )
@ -215,7 +321,7 @@ assign costfactor
#
# some other highway types
#
if ( highway=pedestrian ) then 3
if ( highway=pedestrian ) then ( if isbike then ( if hascycleway then 1.1 else 2.2 ) else 3 )
else if ( highway=bridleway ) then 5
else if ( highway=cycleway ) then 1
else if ( isresidentialorliving ) then ( if isunpaved then 1.5 else 1.1 )
@ -228,12 +334,12 @@ assign costfactor
#
else if ( highway=track|road|path|footway ) then
(
if ( tracktype=grade1 ) then ( if probablyGood then 1.0 else 1.3 )
else if ( tracktype=grade2 ) then ( if probablyGood then 1.1 else 2.0 )
else if ( tracktype=grade3 ) then ( if probablyGood then 1.5 else 3.0 )
else if ( tracktype=grade4 ) then ( if probablyGood then 2.0 else 5.0 )
else if ( tracktype=grade5 ) then ( if probablyGood then 3.0 else 5.0 )
else ( if probablyGood then 1.0 else 5.0 )
if ( tracktype=grade1 ) then ( if probablyGood then 1.0 else add 1.0 multiply 0.3 unpavedPenalty )
else if ( tracktype=grade2 ) then ( if probablyGood then 1.1 else add 1.1 multiply 0.9 unpavedPenalty )
else if ( tracktype=grade3 ) then ( if probablyGood then 1.5 else add 1.5 multiply 1.5 unpavedPenalty )
else if ( tracktype=grade4 ) then ( if probablyGood then 2.0 else add 2.0 multiply 3.0 unpavedPenalty )
else if ( tracktype=grade5 ) then ( if probablyGood then 3.0 else add 3.0 multiply 2.0 unpavedPenalty )
else ( if probablyGood then 1.0 else add 1.0 multiply 4.0 unpavedPenalty )
)
#
@ -326,5 +432,7 @@ assign footaccess =
else not foot=private|no
assign initialcost =
if or highway=traffic_signals and highway=crossing crossing=traffic_signals then 20
else
if bikeaccess then 0
else ( if footaccess then 100 else 1000000 )