osmgl 0.31.31 → 0.31.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core.d.ts +3784 -171
- package/dist/icons-full.d.cts +3 -0
- package/dist/icons-full.d.ts +3 -0
- package/dist/nav.d.ts +3591 -3
- package/dist/navigram.d.ts +6465 -6
- package/dist/osmgl.d.ts +20809 -7
- package/package.json +1 -1
- package/dist/index-BGX0JCbO.d.ts +0 -639
- package/dist/model-mshqbG69.d.ts +0 -4239
- package/dist/nav-C8QvUodP.d.ts +0 -2660
- package/dist/speed-index-kbbQG2xX.d.ts +0 -197
package/dist/nav-C8QvUodP.d.ts
DELETED
|
@@ -1,2660 +0,0 @@
|
|
|
1
|
-
import { bx as NavRoute, x as Model, a7 as StyleLayerSpec, a8 as StyleSpec, a6 as SourceSpec, ab as ThemeSpecV2, Y as PolylineOptions, A as AlongFade, Z as PolylineSegment } from './model-mshqbG69.js';
|
|
2
|
-
import { Geom } from 'polygon-clipping';
|
|
3
|
-
|
|
4
|
-
type LonLat$2 = [number, number];
|
|
5
|
-
/** Фикс геолокации. `timeMs` — время самого фикса (монотонное у источника), не время приёма. */
|
|
6
|
-
interface NavFix {
|
|
7
|
-
pos: LonLat$2;
|
|
8
|
-
timeMs: number;
|
|
9
|
-
/** Радиус ошибки, м; нет — неизвестно. */
|
|
10
|
-
accuracyM?: number | null;
|
|
11
|
-
speedMps?: number | null;
|
|
12
|
-
bearingDeg?: number | null;
|
|
13
|
-
/** Источник: Android знает его точно; веб — нет (тогда судим по точности). */
|
|
14
|
-
provider?: 'gps' | 'network' | 'fused' | null;
|
|
15
|
-
/**
|
|
16
|
-
* Сколько фиксу было в момент приёма, мс (Android: `elapsedRealtimeNanos` приёма минус фикса). Нет —
|
|
17
|
-
* свежий. Время самого фикса (`timeMs`) этого не говорит: часы источника с часами приёма не сравнить.
|
|
18
|
-
*/
|
|
19
|
-
ageMs?: number | null;
|
|
20
|
-
}
|
|
21
|
-
/** Хуже этой точности фикс не берём вовсе, если GPS жив. */
|
|
22
|
-
declare const FIX_ACC_MAX = 100;
|
|
23
|
-
/** Хуже этой точности фикс не двигает машину по трассе (OsmAnd: 50 м). */
|
|
24
|
-
declare const FIX_ACC_ROUTE = 50;
|
|
25
|
-
/** Без явного источника: точность хуже — считаем фикс сетевым. */
|
|
26
|
-
declare const FIX_NET_ACC = 30;
|
|
27
|
-
/** Сколько после последнего GPS-фикса сетевые не принимаем (OsmAnd: 12 с). */
|
|
28
|
-
declare const FIX_NET_HOLD_MS = 12000;
|
|
29
|
-
/** Предел скорости между фиксами, м/с (≈216 км/ч), и запас к прошлой скорости. */
|
|
30
|
-
declare const FIX_VMAX = 60;
|
|
31
|
-
/**
|
|
32
|
-
* Сколько ОТВЕРГНУТЫХ, но согласных между собой фиксов подряд нужно, чтобы поверить: машина и правда там
|
|
33
|
-
* (туннель, долгий провал). Несогласные — разные выбросы — счёт начинают заново.
|
|
34
|
-
*/
|
|
35
|
-
declare const FIX_REJECT_RESET = 3;
|
|
36
|
-
/**
|
|
37
|
-
* Фикс старше этого при приёме (мс) — не текущее место: последняя известная точка при подписке, пачка
|
|
38
|
-
* после фона. OsmAnd считает кешированную точку устаревшей через 2 мин, мы для ведения строже: 10 с —
|
|
39
|
-
* больше любой задержки доставки живого фикса и меньше, чем машина проедет незаметно.
|
|
40
|
-
*/
|
|
41
|
-
declare const FIX_MAX_AGE_MS = 10000;
|
|
42
|
-
/**
|
|
43
|
-
* Живой поток одного источника: возраст соседних фиксов отличается не больше чем на это (мс) и не больше
|
|
44
|
-
* половины шага между ними. У пачки старых фиксов, доставленных разом, возраст убывает ровно на шаг.
|
|
45
|
-
*/
|
|
46
|
-
declare const FIX_STREAM_JITTER_MS = 1000;
|
|
47
|
-
/** Меньший возраст живого потока больше этого (мс) — это сдвиг часов источника, а не задержка доставки. */
|
|
48
|
-
declare const FIX_SKEW_MIN_MS = 2000;
|
|
49
|
-
type NavFixVerdict = 'ok' | 'stale' | 'network' | 'inaccurate' | 'worse' | 'jump';
|
|
50
|
-
/** Сетевой ли фикс: по источнику, а без него — по точности. */
|
|
51
|
-
declare function isNetworkFix(f: NavFix): boolean;
|
|
52
|
-
/** Устарел ли фикс к моменту приёма. */
|
|
53
|
-
declare const isOldFix: (f: NavFix) => boolean;
|
|
54
|
-
/**
|
|
55
|
-
* Отбор фиксов. Первый свежий фикс берём всегда (хоть какой-то лучше никакого); дальше — по правилам выше.
|
|
56
|
-
* Пока GPS не было (или он пропал дольше чем на 12 с), сетевые фиксы — единственный источник, их берём.
|
|
57
|
-
* Не по порядку и устаревшие ('stale') не берём никогда и состояние ими не трогаем.
|
|
58
|
-
*/
|
|
59
|
-
declare class NavFixFilter {
|
|
60
|
-
/** Последний принятый — приведённый к часам приёма (как `norm`). */
|
|
61
|
-
last: NavFix | null;
|
|
62
|
-
lastGpsMs: number;
|
|
63
|
-
rejects: number;
|
|
64
|
-
/** Последний отвергнутый (не 'stale', не 'network'): с ним сверяется следующий, подтверждая новое место. */
|
|
65
|
-
pending: NavFix | null;
|
|
66
|
-
/** Последний поданный фикс, приведённый к часам приёма: время плюс сдвиг часов источника, возраст без сдвига. */
|
|
67
|
-
norm: NavFix | null;
|
|
68
|
-
/** Свежие, но «не новее принятого» подряд (и по порядку между собой): `FIX_REJECT_RESET` — принятый из будущего. */
|
|
69
|
-
staleRun: number;
|
|
70
|
-
private staleLastMs;
|
|
71
|
-
/** Поток каждого источника: прошлый фикс (время и возраст), меньший возраст живого потока, сдвиг часов. */
|
|
72
|
-
private streams;
|
|
73
|
-
/** Сдвиг часов источника (мс), снятый по его живому потоку; 0 — часы согласны с часами приёма. */
|
|
74
|
-
skewMs(provider: string | null | undefined): number;
|
|
75
|
-
/**
|
|
76
|
-
* Привести фикс к часам приёма. Живой поток (возраст соседних почти не меняется) учит сдвиг часов источника —
|
|
77
|
-
* меньший возраст потока, если он больше `FIX_SKEW_MIN_MS`; сдвиг помнится и через разрывы потока. Фикс без
|
|
78
|
-
* возраста (веб) не трогаем.
|
|
79
|
-
*/
|
|
80
|
-
private normalize;
|
|
81
|
-
accept(f0: NavFix): NavFixVerdict;
|
|
82
|
-
reset(): void;
|
|
83
|
-
}
|
|
84
|
-
/**
|
|
85
|
-
* Окно поиска проекции: назад — max(80 м, точность), чтобы увидеть разворот (сам откат принимаем
|
|
86
|
-
* только подтверждённым), вперёд — 150 м плюс путь за время. Дальше назад не смотрим: на петле
|
|
87
|
-
* точку притянуло бы к другому её концу.
|
|
88
|
-
*/
|
|
89
|
-
declare const PROG_BACK_MIN = 80;
|
|
90
|
-
declare const PROG_AHEAD = 150;
|
|
91
|
-
/** Откат назад, после которого (3 фикса подряд) верим, что развернулись (Mapbox iOS). */
|
|
92
|
-
declare const PROG_BACK_CONFIRM = 3;
|
|
93
|
-
declare const PROG_BACK_M = 50;
|
|
94
|
-
/** Прыжок вперёд дальше правдоподобного — верим со второго фикса подряд. */
|
|
95
|
-
declare const PROG_JUMP_CONFIRM = 2;
|
|
96
|
-
/** Дальше этого (м) от проекции в окне — ищем по всей трассе (долгий провал, туннель, сход). */
|
|
97
|
-
declare const PROG_WIDE_M = 60;
|
|
98
|
-
/**
|
|
99
|
-
* Дальнюю проекцию (по всей трассе) берём, только если фикс лежит на самой трассе: не дальше
|
|
100
|
-
* max(этого, точности фикса), м. Иначе мы просто съехали, а у далёкого куска трассы, который проходит
|
|
101
|
-
* рядом с объездом, машине делать нечего: перестроение всё равно заберёт её оттуда.
|
|
102
|
-
*/
|
|
103
|
-
declare const PROG_WIDE_ON_M = 25;
|
|
104
|
-
/**
|
|
105
|
-
* Гистерезис выбора отрезка: проекция дальше правдоподобного пути вперёд берётся, только если она ближе
|
|
106
|
-
* к фиксу хотя бы на столько, м. На параллельных проездах, развязках и эстакадах, где трасса идёт рядом
|
|
107
|
-
* сама с собой, шум GPS в несколько метров иначе перекидывал метр на другой её кусок.
|
|
108
|
-
*/
|
|
109
|
-
declare const PROG_SWITCH_M = 10;
|
|
110
|
-
/**
|
|
111
|
-
* Ближнее окно вперёд: путь за время по скорости фикса (не меньше `PROG_NEAR_MPS`) с запасом в полтора раза,
|
|
112
|
-
* плюс точность и `PROG_NEAR_M`. Всё, что дальше, — только через гистерезис `PROG_SWITCH_M`.
|
|
113
|
-
*/
|
|
114
|
-
declare const PROG_NEAR_MPS = 3;
|
|
115
|
-
declare const PROG_NEAR_M = 15;
|
|
116
|
-
/**
|
|
117
|
-
* Грубый фикс (хуже `FIX_ACC_ROUTE`) держит метр, только пока точный был не раньше этого (мс, по времени фиксов).
|
|
118
|
-
* Дальше грубые двигают метр вперёд в ближнем окне: спутник в руке в машине бывает грубее 50 м подолгу, и метка
|
|
119
|
-
* стояла бы всю дорогу.
|
|
120
|
-
*/
|
|
121
|
-
declare const PROG_COARSE_HOLD_MS = 5000;
|
|
122
|
-
interface NavProgressOut {
|
|
123
|
-
/** Метр трассы, который принимаем. */
|
|
124
|
-
dist: number;
|
|
125
|
-
/** Сколько метров фикс от трассы (для `OffRouteWatch`); `Infinity` — фикс трассу не трогал. */
|
|
126
|
-
off: number;
|
|
127
|
-
/** Скорость вдоль трассы, м/с: из фикса, а без неё — по приросту метра. */
|
|
128
|
-
speedMps: number;
|
|
129
|
-
/** Подтверждён откат назад: развернулись — приложение перестраивает маршрут. */
|
|
130
|
-
reversed: boolean;
|
|
131
|
-
}
|
|
132
|
-
/** Ближайшая проекция точки на участок трассы [from, to] (в метрах); отступ — до точки внутри участка. */
|
|
133
|
-
declare function snapWindow(r: NavRoute, p: LonLat$2, from: number, to: number): {
|
|
134
|
-
dist: number;
|
|
135
|
-
off: number;
|
|
136
|
-
};
|
|
137
|
-
/**
|
|
138
|
-
* Прогресс по трассе. Ищем проекцию в окне вокруг принятого метра: назад `PROG_BACK_MIN`, вперёд — сперва
|
|
139
|
-
* правдоподобный путь за время, дальше до `PROG_AHEAD` — только если там ближе на `PROG_SWITCH_M`; не нашли
|
|
140
|
-
* близко (> `PROG_WIDE_M`) — по всей трассе (долгий провал), но берём её, только если фикс на ней (`PROG_WIDE_ON_M`). Дальше — монотонность: мелкий откат — дрожание, метр стоит; откат
|
|
141
|
-
* от 50 м три фикса подряд — развернулись; прыжок вперёд дальше правдоподобного — верим со второго.
|
|
142
|
-
* Фикс хуже 50 м по точности метр не двигает (только сообщает `off`).
|
|
143
|
-
*/
|
|
144
|
-
declare class NavProgress {
|
|
145
|
-
dist: number | null;
|
|
146
|
-
last: NavFix | null;
|
|
147
|
-
back: number;
|
|
148
|
-
jumps: number;
|
|
149
|
-
/** Время последнего точного фикса (не грубее `FIX_ACC_ROUTE`). */
|
|
150
|
-
accurateMs: number;
|
|
151
|
-
update(r: NavRoute, f: NavFix): NavProgressOut;
|
|
152
|
-
reset(): void;
|
|
153
|
-
}
|
|
154
|
-
/**
|
|
155
|
-
* Переезд точки к новому фиксу, мс: по интервалу между фиксами (точка едет непрерывно, а не прыгает раз в
|
|
156
|
-
* секунду), но не короче `PUCK_GLIDE_MIN_MS` и не дольше `PUCK_GLIDE_MAX_MS` (Organic Maps: стрелка не
|
|
157
|
-
* анимируется дольше 1.5 с; MapLibre `LocationAnimatorCoordinator`: длительность — интервал фиксов).
|
|
158
|
-
*/
|
|
159
|
-
declare const PUCK_GLIDE_MIN_MS = 200;
|
|
160
|
-
declare const PUCK_GLIDE_MAX_MS = 1500;
|
|
161
|
-
/** Дальше этого (м) — переносим сразу: ехать полкилометра по экрану — не сглаживание, а ложное движение. */
|
|
162
|
-
declare const PUCK_TELEPORT_M = 500;
|
|
163
|
-
/**
|
|
164
|
-
* СТОИМ — ТОЧКУ НЕ ДВИГАЕМ (22.10.2026). Спутник у неподвижного телефона дрожит на метры: Redmi Note 11 у окна —
|
|
165
|
-
* точность 8.8 м, скорость 0.0, каждую секунду новая точка в паре метров от прежней. Каждый такой фикс вёл точку, а у OM
|
|
166
|
-
* и камеру слежения (`easeTo` на время переезда ≈1 с), и неподвижная карта рисовала 25–57 кадров/с при 60–90 % ядра.
|
|
167
|
-
* Фикс со скоростью ниже `PUCK_STILL_MPS` в пределах своей точности от ПОКАЗАННОЙ точки (не ближе `PUCK_STILL_MIN_M`, не
|
|
168
|
-
* дальше `PUCK_STILL_MAX_M`) — то же место: `push` отвечает `false` и ставит `held`. Сравнение — с показанной точкой, а не
|
|
169
|
-
* с прошлым фиксом: медленный дрейф не копится незаметно, а вывозит точку, как только уйдёт за порог. Без скорости
|
|
170
|
-
* (сеть, веб) — не держим: идущего пешком не отличить от дрожания.
|
|
171
|
-
*/
|
|
172
|
-
declare const PUCK_STILL_MPS = 0.5;
|
|
173
|
-
declare const PUCK_STILL_MIN_M = 3;
|
|
174
|
-
declare const PUCK_STILL_MAX_M = 15;
|
|
175
|
-
/**
|
|
176
|
-
* Точка «я здесь» без маршрута (свободная карта у обоих приложений). Раньше приложение двигало метку на
|
|
177
|
-
* КАЖДЫЙ фикс подряд — спутниковый и сетевой вперемешку, и сетевой (Wi-Fi/сота, 20–500 м) уводил точку
|
|
178
|
-
* в сторону, а следующий спутниковый возвращал: «прыгает и сразу назад». Теперь:
|
|
179
|
-
* - фикс проходит тот же `NavFixFilter`, что и в ведении (сеть при живом GPS, выбросы, порядок, возраст);
|
|
180
|
-
* - устаревший фикс показывается, только пока не показано ничего (последняя известная точка при
|
|
181
|
-
* запуске — «Моё место» не ждёт спутника), и следующий свежий берётся без сверки с ним;
|
|
182
|
-
* - точка не переносится, а ЕДЕТ от нарисованного места к новому фиксу (`at`), прерванный переезд
|
|
183
|
-
* продолжается с того места, где точка сейчас.
|
|
184
|
-
* Время — часы приложения (мс), те же для `push` и `at`.
|
|
185
|
-
*/
|
|
186
|
-
declare class NavPuck {
|
|
187
|
-
readonly filter: NavFixFilter;
|
|
188
|
-
/** Последний показанный фикс (цель переезда); `null` — показывать нечего. */
|
|
189
|
-
fix: NavFix | null;
|
|
190
|
-
/** Показан устаревший фикс («пока ничего лучше нет»). */
|
|
191
|
-
provisional: boolean;
|
|
192
|
-
private from;
|
|
193
|
-
private t0;
|
|
194
|
-
private dur;
|
|
195
|
-
private lastPushMs;
|
|
196
|
-
/** Последний `push` ответил `false`, потому что стоим (`PUCK_STILL_MPS`), а не потому что фикс отвергнут. */
|
|
197
|
-
held: boolean;
|
|
198
|
-
/** Фикс пришёл в `nowMs`: `true` — точку надо вести к нему (новая цель), `false` — отвергнут или стоим (`held`). */
|
|
199
|
-
push(f: NavFix, nowMs: number): boolean;
|
|
200
|
-
/** Где нарисовать точку в `nowMs`; `null` — ещё нечего. */
|
|
201
|
-
at(nowMs: number): LonLat$2 | null;
|
|
202
|
-
/** Длительность текущего переезда, мс (0 — перенос): камере слежения — та же, чтобы точка не уплывала из центра. */
|
|
203
|
-
get glideMs(): number;
|
|
204
|
-
/** Идёт ли переезд: приложению — крутить кадры, пока `true`. */
|
|
205
|
-
moving(nowMs: number): boolean;
|
|
206
|
-
reset(): void;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
type LonLat$1 = [number, number];
|
|
210
|
-
type NavCarKind = 'arrow' | 'arrow3d' | 'sedan' | 'pickup' | 'suv';
|
|
211
|
-
/** Варианты, у которых есть 3D-модель (всё, кроме плоской стрелки — её рисуют фигуры курсора). */
|
|
212
|
-
type NavCarModelKind = Exclude<NavCarKind, 'arrow'>;
|
|
213
|
-
/** Порядок выбора в настройках: прежняя стрелка первой, объёмная — рядом с ней. */
|
|
214
|
-
declare const NAV_CAR_KINDS: NavCarKind[];
|
|
215
|
-
declare const NAV_CAR_LABELS: Record<NavCarKind, string>;
|
|
216
|
-
/** Настройка → вариант; пусто и неизвестное — стрелка (так было до машин). */
|
|
217
|
-
declare function navCarKind(id?: string | null): NavCarKind;
|
|
218
|
-
declare const NAV_CAR: {
|
|
219
|
-
/**
|
|
220
|
-
* Наименьшая длина машины на экране, пиксели. Как у Google: на обзорных зумах машина не тает в
|
|
221
|
-
* точку, а держит размер значка (заметно крупнее круга курсора — 28.5 px); настоящие 4.5 м
|
|
222
|
-
* начинаются только вблизи (z20+).
|
|
223
|
-
*/
|
|
224
|
-
minPx: number;
|
|
225
|
-
/** Зазор над линией маршрута, метры: колёса стоят на ленте, а не в ней (у курсора тоже +0.02). */
|
|
226
|
-
lift: number;
|
|
227
|
-
/** Высота фаски низа кузова, метры. */
|
|
228
|
-
chamfer: number;
|
|
229
|
-
};
|
|
230
|
-
/**
|
|
231
|
-
* Кузов: сечения поперёк машины от носа к корме — `[s, w, belt, wt, top]`: расстояние от носа,
|
|
232
|
-
* полуширина по борту, высота пояса (низ окон), полуширина и высота верха (крыша/капот). Между
|
|
233
|
-
* сечениями — сегменты (`segs`, на один меньше), буква решает, чем покрыт верх и бока над поясом:
|
|
234
|
-
* B — кузов, W — стекло сверху и с боков (лобовое, заднее), R — крыша с боковыми окнами,
|
|
235
|
-
* P — стойка (весь сегмент кузовом), D — кузов пикапа (стенки и пол — тёмным пластиком).
|
|
236
|
-
*/
|
|
237
|
-
interface NavCarBody {
|
|
238
|
-
length: number;
|
|
239
|
-
/** Полуширина по борту (наибольшая), метры. */
|
|
240
|
-
width: number;
|
|
241
|
-
/** Клиренс: низ кузова над землёй. */
|
|
242
|
-
clearance: number;
|
|
243
|
-
color: string;
|
|
244
|
-
sections: number[][];
|
|
245
|
-
segs: string;
|
|
246
|
-
/** Колёса: радиус, ширина, расстояния осей от носа. */
|
|
247
|
-
wheel: {
|
|
248
|
-
r: number;
|
|
249
|
-
w: number;
|
|
250
|
-
axles: [number, number];
|
|
251
|
-
};
|
|
252
|
-
/** Рейлинги на крыше: от и до (расстояние от носа), полуразнос, высота. */
|
|
253
|
-
rails?: [number, number, number, number];
|
|
254
|
-
}
|
|
255
|
-
declare const NAV_CAR_BODIES: Record<Exclude<NavCarKind, 'arrow' | 'arrow3d'>, NavCarBody>;
|
|
256
|
-
/**
|
|
257
|
-
* ОБЪЁМНАЯ СТРЕЛКА (`arrow3d`) — значок «как у Яндекс Навигатора»: скруглённый шеврон-«подушка» с
|
|
258
|
-
* белой каймой, глянцем и мягкой тенью. Своя геометрия, не снятая с чужой модели.
|
|
259
|
-
*
|
|
260
|
-
* • СИЛУЭТ — шеврон в плане (x вправо, z назад, остриё в −z): остриё, правое крыло, выемка, левое
|
|
261
|
-
* крыло. Каждый угол скруглён ДУГОЙ ОКРУЖНОСТИ — рациональной квадратичной кривой Безье (`corners`:
|
|
262
|
-
* доли входящего и исходящего ребра и вес = синус половины угла), `steps` отрезков на дугу. Только
|
|
263
|
-
* сложение, умножение и деление: тригонометрии нет, порты совпадают с вебом до байта. Формула
|
|
264
|
-
* записана симметрично (`t·u`, `(wa+wb)+wp`), поэтому левая половина — точное отражение правой.
|
|
265
|
-
* • ОБЪЁМ — кольца, отступающие от силуэта внутрь по нормали вершины: вертикальный борт (`base` →
|
|
266
|
-
* `wall`), белая скруглённая кайма (`rim`: ширина, высота — четверть эллипса) и синяя «подушка»
|
|
267
|
-
* (`dome`), над ней — крышка с подъёмом середины (`crown`). Профиль четверти — таблица точек
|
|
268
|
-
* единичной окружности с рациональными координатами (`arc`: 3-4-5, 7-24-25), нормали гладкие:
|
|
269
|
-
* по профилю и по силуэту, поэтому свет и блик текут по всей стрелке без граней.
|
|
270
|
-
* • ЦВЕТ И ГЛЯНЕЦ — без новых шейдеров, в материалах GLB: синий маршрута с градиентом по высоте
|
|
271
|
-
* (`low` у основания подушки → `top` → светлая крышка `high`), борт глубже, кайма белая; малая
|
|
272
|
-
* шероховатость даёт блик солнца и френелевское отражение неба у краёв (ветка `reflection`
|
|
273
|
-
* программы моделей). Ночью — свой набор (`NAV_ARROW_PALETTES.night`, модель `arrow3d-night`):
|
|
274
|
-
* ЯРКОСТЬ ДАЁТ СВЕЧЕНИЕ, А НЕ ЦВЕТ. Ночная тема гасит свет сцены (у NaviGram: рассеянный 0.34
|
|
275
|
-
* голубоватый, ключевой 0.3 против 0.48/0.6 днём) — освещённая часть синего падает на треть. Первый
|
|
276
|
-
* набор (цвет светлее дневного, свечение 0.05–0.3) под таким светом выходил ТЕМНЕЕ дневной стрелки
|
|
277
|
-
* (замер Redmi 23.10.2026: L 116 против 129); светлее она была только на стилях MapLibre с дневным
|
|
278
|
-
* светом. Поэтому ночью цвет темнее, а свечение крупное: под ночным светом стрелка заметно ярче
|
|
279
|
-
* дневной, и от света темы зависит слабо (оценка по граням: 135 ночью против 99 днём, на дневном
|
|
280
|
-
* свете 154). Проверка — тест `ночная стрелка ярче` в `tests/nav-car.test.mjs`.
|
|
281
|
-
* • ПРЕДЕЛ — отступ колец (`rim[0] + dome[0]`) меньше радиуса самой тугой дуги (остриё, крылья —
|
|
282
|
-
* ≈0.26 м): иначе внутренние кольца на углах завернулись бы.
|
|
283
|
-
*/
|
|
284
|
-
declare const NAV_ARROW: {
|
|
285
|
-
/** Длина скруглённого силуэта от острия до концов крыльев, метры (по ней поза держит `minPx`, как у машин). */
|
|
286
|
-
length: number;
|
|
287
|
-
/** Опорный контур до скругления: остриё, правое крыло, выемка, левое крыло. */
|
|
288
|
-
outer: number[][];
|
|
289
|
-
/** Скругление углов: доля ребра к предыдущей вершине, доля ребра к следующей, вес дуги. */
|
|
290
|
-
corners: number[][];
|
|
291
|
-
/** Отрезков на дугу угла (чётное: середина дуги острия и выемки ложится точно на ось). */
|
|
292
|
-
steps: number;
|
|
293
|
-
/** Низ борта над подложкой-тенью, метры. */
|
|
294
|
-
base: number;
|
|
295
|
-
/** Верх борта. */
|
|
296
|
-
wall: number;
|
|
297
|
-
/** Белая кайма: ширина внутрь и высота скругления. */
|
|
298
|
-
rim: number[];
|
|
299
|
-
/** Синяя «подушка»: ширина внутрь и высота. */
|
|
300
|
-
dome: number[];
|
|
301
|
-
/** Подъём середины крышки над краем подушки. */
|
|
302
|
-
crown: number;
|
|
303
|
-
/** Центр крышки и подложки в плане (из него силуэт виден целиком). */
|
|
304
|
-
center: number[];
|
|
305
|
-
/** Четверть профиля: (cos, sin) от «наружу» до «вверх» — рациональные точки окружности. */
|
|
306
|
-
arc: number[][];
|
|
307
|
-
};
|
|
308
|
-
/** Цвета стрелки (`#rrggbb`): крышка, подушка, низ подушки, кайма, борт; свечение — RGB 0..1 (ночью). */
|
|
309
|
-
interface NavArrowPalette {
|
|
310
|
-
high: string;
|
|
311
|
-
top: string;
|
|
312
|
-
low: string;
|
|
313
|
-
bevel: string;
|
|
314
|
-
side: string;
|
|
315
|
-
highGlow?: [number, number, number];
|
|
316
|
-
topGlow?: [number, number, number];
|
|
317
|
-
lowGlow?: [number, number, number];
|
|
318
|
-
bevelGlow?: [number, number, number];
|
|
319
|
-
sideGlow?: [number, number, number];
|
|
320
|
-
}
|
|
321
|
-
declare const NAV_ARROW_PALETTES: {
|
|
322
|
-
day: NavArrowPalette;
|
|
323
|
-
night: NavArrowPalette;
|
|
324
|
-
};
|
|
325
|
-
/** Материалы — в этом порядке и уходят в GLB (пустые пропускаются). */
|
|
326
|
-
interface NavCarMaterial {
|
|
327
|
-
name: string;
|
|
328
|
-
color: [number, number, number, number];
|
|
329
|
-
metallic: number;
|
|
330
|
-
roughness: number;
|
|
331
|
-
emissive?: [number, number, number];
|
|
332
|
-
blend?: boolean;
|
|
333
|
-
}
|
|
334
|
-
/** `#rrggbb` → RGBA 0..1. */
|
|
335
|
-
declare function navCarColor(hex: string): [number, number, number, number];
|
|
336
|
-
/** Кусок меша одного материала: треугольники подряд, у каждого свои три вершины (плоские грани). */
|
|
337
|
-
interface NavCarPart {
|
|
338
|
-
material: NavCarMaterial;
|
|
339
|
-
positions: number[];
|
|
340
|
-
normals: number[];
|
|
341
|
-
}
|
|
342
|
-
/**
|
|
343
|
-
* Силуэт стрелки: точки по кругу (остриё → правое крыло → выемка → левое крыло, по `steps + 1` на угол;
|
|
344
|
-
* между углами — прямые рёбра) и единичные нормали вершин наружу (средняя двух соседних рёбер).
|
|
345
|
-
*/
|
|
346
|
-
declare function navArrowOutline(): {
|
|
347
|
-
points: number[][];
|
|
348
|
-
normals: number[][];
|
|
349
|
-
};
|
|
350
|
-
/** Меш значка кусками по материалам (пустые куски выброшены); `night` — ночные цвета (только у стрелки). */
|
|
351
|
-
declare function navCarMesh(kind: NavCarModelKind, night?: boolean): NavCarPart[];
|
|
352
|
-
/** Число с четырьмя знаками: округление к ближайшему (половина — вверх по модулю). */
|
|
353
|
-
declare function fmt4(v: number): string;
|
|
354
|
-
/** Число с одним знаком (пути превью). */
|
|
355
|
-
declare function fmt1(v: number): string;
|
|
356
|
-
/**
|
|
357
|
-
* Имя модели в GLB и в адресе: вариант, у ночной стрелки — с `-night`. У машин ночного набора нет —
|
|
358
|
-
* их GLB от `night` не зависит.
|
|
359
|
-
*/
|
|
360
|
-
declare function navCarModelId(kind: NavCarModelKind, night?: boolean): string;
|
|
361
|
-
/** GLB значка: одна сетка, примитив на материал, позиции и нормали Float32, индексы Uint32. */
|
|
362
|
-
declare function navCarGlb(kind: NavCarModelKind, night?: boolean): Uint8Array;
|
|
363
|
-
/** FNV-1a 32 бита — отпечаток GLB в фикстурах (строкой из восьми шестнадцатеричных цифр). */
|
|
364
|
-
declare function navCarHash(bytes: Uint8Array): string;
|
|
365
|
-
interface NavCarPose {
|
|
366
|
-
lng: number;
|
|
367
|
-
lat: number;
|
|
368
|
-
/** Высота колёс над землёй, метры: над линией маршрута и лентой, на эстакаде — с её отметкой. */
|
|
369
|
-
altitude: number;
|
|
370
|
-
/** Курс по часовой, градусы 0..360 (`rotation` модели). */
|
|
371
|
-
rotation: number;
|
|
372
|
-
/** Множитель к настоящему размеру: 1 вблизи, больше — чтобы машина не была мельче `minPx`. */
|
|
373
|
-
scale: number;
|
|
374
|
-
}
|
|
375
|
-
/**
|
|
376
|
-
* Поза машины: точка и курс курсора (их сглаживает `NavTracker`), масштаб по метрам в пикселе
|
|
377
|
-
* экрана на широте машины и высота полотна под ней (`roadLiftM` — эстакада по ленте, 0 на земле).
|
|
378
|
-
* Для стрелки — `null`: её рисуют фигуры `navCursorShapes`.
|
|
379
|
-
*/
|
|
380
|
-
declare function navCarPose(kind: NavCarKind, pos: LonLat$1, brgDeg: number, metersPerPixel: number, roadLiftM?: number): NavCarPose | null;
|
|
381
|
-
/**
|
|
382
|
-
* Отметка ленты на метре трассы `m`: профили — станции и высоты точек площадных кусков ленты
|
|
383
|
-
* (`RibbonFeature.stations` + `heightAt` по уровню). Внутри куска — линейно между соседними
|
|
384
|
-
* станциями; кусков на метре несколько (полосы рядом) — наибольшая; вне ленты — 0.
|
|
385
|
-
*/
|
|
386
|
-
declare function navCarLiftAt(profiles: {
|
|
387
|
-
stations: number[];
|
|
388
|
-
heights: number[];
|
|
389
|
-
}[], m: number): number;
|
|
390
|
-
interface NavCarIcon {
|
|
391
|
-
width: number;
|
|
392
|
-
height: number;
|
|
393
|
-
/** Пути SVG с заливкой, снизу вверх. */
|
|
394
|
-
paths: {
|
|
395
|
-
d: string;
|
|
396
|
-
fill: string;
|
|
397
|
-
}[];
|
|
398
|
-
}
|
|
399
|
-
/** SVG-разметка превью целиком (для веба). */
|
|
400
|
-
declare function navCarIconSvg(kind: NavCarKind): string;
|
|
401
|
-
/**
|
|
402
|
-
* Превью 48×24: машина сбоку (нос влево) по тем же сечениям, что модель, — силуэт цвета кузова,
|
|
403
|
-
* окна по сегментам W/R, колёса с колпаками. Стрелка — синий круг с белой стрелкой курсора.
|
|
404
|
-
*/
|
|
405
|
-
declare function navCarIcon(kind: NavCarKind): NavCarIcon;
|
|
406
|
-
|
|
407
|
-
/** Что оверлею нужно от карты (`Map` движка подходит как есть). */
|
|
408
|
-
interface NavCarHost {
|
|
409
|
-
addModel(model: Model): unknown;
|
|
410
|
-
removeModel(model: Model): unknown;
|
|
411
|
-
triggerRepaint(): unknown;
|
|
412
|
-
/**
|
|
413
|
-
* Фокус окон домов (`Map.setFacadeFocus`): в ведении окна стен рисуются только около машины (вариант A владельца,
|
|
414
|
-
* 22.10.2026). Необязателен — хозяину без домов он не нужен.
|
|
415
|
-
*/
|
|
416
|
-
setFacadeFocus?(pos: [number, number] | null): unknown;
|
|
417
|
-
}
|
|
418
|
-
declare class NavCarOverlay {
|
|
419
|
-
private readonly map;
|
|
420
|
-
/** Модели по вариантам (`navCarModelId`) — создаются при первом выборе и живут, пока жив оверлей. */
|
|
421
|
-
private models;
|
|
422
|
-
/** Какая модель сейчас на карте (`null` — никакой). */
|
|
423
|
-
private shown;
|
|
424
|
-
private _kind;
|
|
425
|
-
private _night;
|
|
426
|
-
constructor(map: NavCarHost);
|
|
427
|
-
/**
|
|
428
|
-
* Вариант значка. `'arrow'` — машины нет (стрелку рисует приложение фигурами `navCursorShapes`).
|
|
429
|
-
* Смена варианта снимает прежнюю модель сразу, новая встаёт со следующего `update`.
|
|
430
|
-
*/
|
|
431
|
-
get kind(): NavCarKind;
|
|
432
|
-
set kind(value: NavCarKind);
|
|
433
|
-
/**
|
|
434
|
-
* Ночные цвета значка (тёмная тема карты). Меняет только объёмную стрелку: её модель снимается сразу,
|
|
435
|
-
* ночная (или дневная) встаёт со следующего `update`.
|
|
436
|
-
*/
|
|
437
|
-
get night(): boolean;
|
|
438
|
-
set night(value: boolean);
|
|
439
|
-
/** Видна ли машина сейчас (после `update` с вариантом-машиной). */
|
|
440
|
-
get visible(): boolean;
|
|
441
|
-
/**
|
|
442
|
-
* Поставить машину в точку `pos` (`[lon, lat]`) с курсом `bearing` (градусы по часовой) на зуме
|
|
443
|
-
* карты `zoom`; `roadLiftM` — отметка полотна под машиной (эстакада), 0 на земле. Возвращает
|
|
444
|
-
* `false`, если выбрана стрелка — тогда рисует приложение.
|
|
445
|
-
*/
|
|
446
|
-
update(pos: [number, number], bearing: number, zoom: number, roadLiftM?: number): boolean;
|
|
447
|
-
/** Убрать машину с карты (выбор остаётся). */
|
|
448
|
-
clear(): void;
|
|
449
|
-
/** Снять все модели с карты — оверлей больше не нужен. */
|
|
450
|
-
destroy(): void;
|
|
451
|
-
/** Машину убрали — ведения нет: окна снова везде. */
|
|
452
|
-
private hide;
|
|
453
|
-
private hideModel;
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
/**
|
|
457
|
-
* ЛЕНТА МАРШРУТА ПО ПОЛОСАМ — геометрия (как у Baidu: на детальной улице линия маршрута становится
|
|
458
|
-
* полупрозрачной лентой по рекомендуемым полосам).
|
|
459
|
-
*
|
|
460
|
-
* Чистые функции без движка и сети (проверка — `lane-ribbon-geom.test.ts`). Вход — план полос
|
|
461
|
-
* (`api/lanes.ts`, контракт `POST /tiles/ldroads/guidance`) и та же трасса, что ушла в запрос:
|
|
462
|
-
* все метры плана считаются ВДОЛЬ неё.
|
|
463
|
-
*
|
|
464
|
-
* ★ ВСЁ ПАРАМЕТРИЗУЕТСЯ МЕТРОМ МАРШРУТА. Осевая полосы — своя ломаная (её даёт сервер, смещённую по
|
|
465
|
-
* профилю), но каждая её точка получает «станцию» — проекцию на трассу. Тогда «полоса на метре s»
|
|
466
|
-
* — интерполяция по станциям, и всё остальное становится сложением точек на одной станции:
|
|
467
|
-
* лента на две соседние полосы — середина их осевых, S-переход из полосы в полосу — смесь двух
|
|
468
|
-
* точек с весом smoothstep, стык с обычной линией маршрута — смесь с точкой самой трассы. Своего
|
|
469
|
-
* смещения кривых для этого не нужно, и лента не «срезает» повороты осевой.
|
|
470
|
-
*
|
|
471
|
-
* ★ ПЛОСКАЯ СИСТЕМА МЕТРОВ вокруг трассы (равнопромежуточная): на маршруте в несколько километров
|
|
472
|
-
* ошибка — доли процента, а разница с серверными метрами ровно такая же, как у любых двух
|
|
473
|
-
* реализаций длины.
|
|
474
|
-
*/
|
|
475
|
-
|
|
476
|
-
type LonLat = [number, number];
|
|
477
|
-
interface XY {
|
|
478
|
-
x: number;
|
|
479
|
-
y: number;
|
|
480
|
-
}
|
|
481
|
-
/** Плоская система метров вокруг точки. */
|
|
482
|
-
interface Frame {
|
|
483
|
-
toXY(p: LonLat): XY;
|
|
484
|
-
toLonLat(p: XY): LonLat;
|
|
485
|
-
}
|
|
486
|
-
declare function frameAt(origin: LonLat): Frame;
|
|
487
|
-
/** Гладкая ступенька 0→1: нулевая производная на концах — S-переход без излома на входе и выходе. */
|
|
488
|
-
declare const smoothstep: (t: number) => number;
|
|
489
|
-
interface Measured {
|
|
490
|
-
pts: XY[];
|
|
491
|
-
/** Накопленная длина к каждой точке, метры. */
|
|
492
|
-
cum: number[];
|
|
493
|
-
length: number;
|
|
494
|
-
}
|
|
495
|
-
declare function measure(pts: XY[], lengths?: number[]): Measured;
|
|
496
|
-
/**
|
|
497
|
-
* Длина звена — ТОЙ ЖЕ ФОРМУЛОЙ, ЧТО У СЕРВЕРА (`LdLaneGraph.DistanceM`, `LD-LANE-GUIDANCE.md`,
|
|
498
|
-
* «Метры»): плоская на каждом звене, косинус СРЕДНЕЙ широты звена. Все метры плана — вдоль трассы
|
|
499
|
-
* этой мерой; гаверсинус или общий косинус дали бы расхождение до 10 м на 10 км.
|
|
500
|
-
*/
|
|
501
|
-
declare function linkM(a: LonLat, b: LonLat): number;
|
|
502
|
-
/** Трасса `[lon, lat]` в метрах: точки — в плоской системе, накопленная длина — мерой сервера. */
|
|
503
|
-
declare function measureRoute(geometry: LonLat[], frame: Frame): Measured;
|
|
504
|
-
/** Точка на метре `s` (за концами — продолжение крайнего отрезка). */
|
|
505
|
-
declare function pointAt(m: Measured, s: number): XY;
|
|
506
|
-
/** Курс на метре `s`: единичный вектор по ходу. */
|
|
507
|
-
declare function tangentAt(m: Measured, s: number): XY;
|
|
508
|
-
/** Курс в градусах по часовой от севера — для камеры. */
|
|
509
|
-
declare function bearingAt(m: Measured, s: number, ahead?: number): number;
|
|
510
|
-
/**
|
|
511
|
-
* Метр трассы, ближайший к точке. `from`/`to` — окно поиска: трасса может пройти мимо одного
|
|
512
|
-
* места дважды (разворот, петля), и полоса одного участка не должна «прилипнуть» к другому.
|
|
513
|
-
*/
|
|
514
|
-
declare function project(m: Measured, p: XY, from?: number, to?: number): {
|
|
515
|
-
s: number;
|
|
516
|
-
d: number;
|
|
517
|
-
};
|
|
518
|
-
/** Дробление ломаной: точки не реже `step` метров. */
|
|
519
|
-
declare function densify(pts: XY[], step: number): XY[];
|
|
520
|
-
/** Кусок ломаной между метрами `from` и `to` её СОБСТВЕННОЙ длины. */
|
|
521
|
-
declare function sliceLine(pts: XY[], from: number, to: number): XY[];
|
|
522
|
-
/**
|
|
523
|
-
* СМЕЩЁННАЯ КРИВАЯ: каждая точка сдвигается на свой `offsets[i]` метров вправо по ходу.
|
|
524
|
-
*
|
|
525
|
-
* Нормаль в вершине — биссектриса соседних отрезков, длина поправлена на угол (как у стыка
|
|
526
|
-
* «miter»), но не больше чем вдвое: на остром изломе честный miter улетает на десятки метров.
|
|
527
|
-
*/
|
|
528
|
-
declare function offsetLine(pts: XY[], offsets: number[] | number): XY[];
|
|
529
|
-
/** Боковой сдвиг точки от трассы на метре `s`, метры вправо по ходу. */
|
|
530
|
-
declare function lateralAt(route: Measured, s: number, p: XY): number;
|
|
531
|
-
/** Осевая полосы со станциями: `s[i]` — метр трассы точки `pts[i]`, строго растёт. */
|
|
532
|
-
interface Track {
|
|
533
|
-
s: number[];
|
|
534
|
-
pts: XY[];
|
|
535
|
-
}
|
|
536
|
-
/**
|
|
537
|
-
* Осевая полосы → станции. Точки, станция которых не растёт (осевая шире трассы на развороте,
|
|
538
|
-
* хвост за перекрёстком, загнутый назад), выкидываются: функция «точка по метру» обязана быть
|
|
539
|
-
* однозначной.
|
|
540
|
-
*/
|
|
541
|
-
declare function laneTrack(route: Measured, centre: XY[], window: [number, number]): Track | null;
|
|
542
|
-
/**
|
|
543
|
-
* Точка полосы на метре `s`. За концами осевой — тот же боковой сдвиг от трассы, что у крайней
|
|
544
|
-
* точки: лента не обрывается и не загибается к оси, если осевая чуть короче участка.
|
|
545
|
-
*/
|
|
546
|
-
declare function trackAt(route: Measured, tr: Track, s: number): XY;
|
|
547
|
-
/** Точка, сдвинутая от трассы на метре `s` на `off` метров вправо. */
|
|
548
|
-
declare function offsetPoint(route: Measured, s: number, off: number): XY;
|
|
549
|
-
/** Отступ ленты от краёв полосы (на обе стороны вместе): лента не должна лечь на разметку. */
|
|
550
|
-
declare const RIBBON_MARGIN_M = 0.7;
|
|
551
|
-
/** Шаг ленты вдоль маршрута. */
|
|
552
|
-
declare const RIBBON_STEP_M = 2;
|
|
553
|
-
/** Длина стыка ленты с обычной линией маршрута на краях покрытия. */
|
|
554
|
-
declare const JOIN_M = 25;
|
|
555
|
-
/**
|
|
556
|
-
* Скругление оси ленты на изломах (сигма гауссова окна, метры). Излом — поворот трассы на
|
|
557
|
-
* перекрёстке или скачок между осевыми соседних отрезков улицы: без скругления контур ленты на
|
|
558
|
-
* внутренней стороне угла выворачивался петлёй. Радиус дуги на повороте 90° — около 1.6 сигмы.
|
|
559
|
-
*/
|
|
560
|
-
declare const CORNER_SMOOTH_M = 4.5;
|
|
561
|
-
/** Излом — поворот направления в точке оси больше этого (градусы). */
|
|
562
|
-
declare const CORNER_DEG = 8;
|
|
563
|
-
/**
|
|
564
|
-
* `band-passed`/`allowed-passed` — пройденная в ведении часть ленты (серая, `lib/route-progress.ts`);
|
|
565
|
-
* `buildRibbon` их не строит.
|
|
566
|
-
*/
|
|
567
|
-
type RibbonKind = 'band' | 'allowed' | 'chevron' | 'band-passed' | 'allowed-passed';
|
|
568
|
-
/**
|
|
569
|
-
* ФОРМА КОНЦА ЛЕНТЫ там, где она кончается без продолжения (начало и конец маршрута, края дыр в
|
|
570
|
-
* плане; не стык с линией маршрута и не разрез в точке машины или по кускам):
|
|
571
|
-
* - `round` — полукруг радиусом полуширины, касательный к кромкам (как `line-cap: round`);
|
|
572
|
-
* - `flat` — прямой срез поперёк ленты в последней точке оси (как было до скруглений);
|
|
573
|
-
* - `arrow` — заострённый конец-стрелка на КОНЦЕ маршрута (как у Baidu на точке назначения):
|
|
574
|
-
* кромки сходятся в вершину впереди оси на `ARROW_TIP_K` полуширины; начало при этом — `round`.
|
|
575
|
-
* Скругление и стрелка выходят за последнюю точку оси (на полуширину и `ARROW_TIP_K` полуширины).
|
|
576
|
-
*/
|
|
577
|
-
type RibbonCap = 'round' | 'flat' | 'arrow';
|
|
578
|
-
declare const RIBBON_CAPS: readonly RibbonCap[];
|
|
579
|
-
declare const DEFAULT_RIBBON_CAP: RibbonCap;
|
|
580
|
-
declare const isRibbonCap: (v: unknown) => v is RibbonCap;
|
|
581
|
-
/** Отрезков на полукруг конца: излом на стыке кромки и полукруга — π/(2·N), 2.8°. */
|
|
582
|
-
declare const CAP_SEGMENTS = 32;
|
|
583
|
-
/** Длина острия стрелки за последней точкой оси, в полуширинах ленты (угол при вершине ≈ 67°). */
|
|
584
|
-
declare const ARROW_TIP_K = 1.5;
|
|
585
|
-
interface RibbonFeature {
|
|
586
|
-
kind: RibbonKind;
|
|
587
|
-
/** Осевая куска, `[lon, lat]` (у ленты — уже скруглённая на изломах). */
|
|
588
|
-
line: LonLat[];
|
|
589
|
-
/** Ширина, метры: у ленты — наибольшая по куску (сама форма — в `outline`). */
|
|
590
|
-
width: number;
|
|
591
|
-
/** Уровень (эстакада 1, земля 0, тоннель −1) у каждой точки `line` — по нему берётся высота. */
|
|
592
|
-
levels: number[];
|
|
593
|
-
/**
|
|
594
|
-
* Контур площадной фичи (`band`, `allowed`) — замкнутое кольцо `[lon, lat]` против
|
|
595
|
-
* часовой, без самопересечений. Рисуется готовым многоугольником: форму ленты считает клиент, а
|
|
596
|
-
* не движок из оси и ширины (у той сборки на изломе внутренняя кромка выворачивалась, и earcut
|
|
597
|
-
* заливал треугольник через квартал).
|
|
598
|
-
*/
|
|
599
|
-
outline?: LonLat[];
|
|
600
|
-
/**
|
|
601
|
-
* Метр трассы у каждой точки `line` (не убывает) — по нему пройденная часть ленты отрезается в
|
|
602
|
-
* ведении (`lib/route-progress.ts`). У шеврона — метры его двух концов.
|
|
603
|
-
*/
|
|
604
|
-
stations?: number[];
|
|
605
|
-
/** Ширина ленты у каждой точки `line`, метры (площадные фичи) — контур отрезанной части. */
|
|
606
|
-
widths?: number[];
|
|
607
|
-
/**
|
|
608
|
-
* Форма начала и конца (площадные фичи), `RibbonCap`: уже с учётом стыков — где лента переходит
|
|
609
|
-
* в линию маршрута, там `flat`. Куски ленты (ведение, резка по `CHUNK_M`) берут форму только у
|
|
610
|
-
* своих настоящих концов, на разрезах — прямо.
|
|
611
|
-
*/
|
|
612
|
-
caps?: [RibbonCap, RibbonCap];
|
|
613
|
-
}
|
|
614
|
-
interface Ribbon {
|
|
615
|
-
features: RibbonFeature[];
|
|
616
|
-
/** Где обычная линия маршрута уступает ленте: метры вдоль трассы. */
|
|
617
|
-
hidden: [number, number][];
|
|
618
|
-
/**
|
|
619
|
-
* Ось ОСНОВНОЙ ленты для позы машины навигатора (`laneCarTrack` в `nav-car.ts`): те же точки и метры, что у её
|
|
620
|
-
* фич `band` (`line`, `stations`), и доля плана в позе машины. Нет основной ленты — поля нет.
|
|
621
|
-
*/
|
|
622
|
-
car?: RibbonCar;
|
|
623
|
-
}
|
|
624
|
-
/**
|
|
625
|
-
* МАШИНА ЕДЕТ ПО ЛЕНТЕ (этап 1 «как обычный режим полос Baidu/Amap», 23.10.2026): ось основной ленты — та самая, что
|
|
626
|
-
* нарисована (`band.line` после скругления изломов), с метрами трассы и ВЕСОМ ПЛАНА в каждой точке:
|
|
627
|
-
* · 1 — на куске покрытия плана (машина на оси ленты, в том числе пока лента переходит в полосу из ленты вне
|
|
628
|
-
* покрытия по `RAMP_SLOPE`);
|
|
629
|
-
* · вне покрытия — `CAR_OUTSIDE_WEIGHT` = 1 (решение владельца 24.10.2026): лента там — догадка «полполосы справа»
|
|
630
|
-
* (`OUTSIDE_LANE_M`), и машина едет по ней же, а не по линии маршрута на 1,65 м левее. Плавность на краях куска
|
|
631
|
-
* даёт сама ось ленты: она входит в полосу и выходит из неё по `RAMP_SLOPE`;
|
|
632
|
-
* · при весе вне покрытия меньше 1 между ними — подъезд на `JOIN_M` до края куска (`carWeight`, smoothstep).
|
|
633
|
-
* Метры не убывают; кусков основной ленты несколько (лента только на покрытии, `outside: false`) — они идут подряд.
|
|
634
|
-
*/
|
|
635
|
-
interface RibbonCar {
|
|
636
|
-
stations: number[];
|
|
637
|
-
line: LonLat[];
|
|
638
|
-
weights: number[];
|
|
639
|
-
}
|
|
640
|
-
/**
|
|
641
|
-
* Склеить пересекающиеся и близкие отрезки покрытия: щель меньше `gap` — это перекрёсток между
|
|
642
|
-
* двумя участками, и лента через него идёт непрерывно, а не прыгает в линию маршрута и обратно.
|
|
643
|
-
*/
|
|
644
|
-
declare function mergeRanges(ranges: [number, number][], gap?: number, limit?: [number, number]): [number, number][];
|
|
645
|
-
/** Подряд идущие номера полос — группы ленты (две соседние полосы — одна лента во всю ширину). */
|
|
646
|
-
declare function contiguousGroups(lanes: PlanLane[]): PlanLane[][];
|
|
647
|
-
/**
|
|
648
|
-
* ЛЕНТА ВНЕ ПОКРЫТИЯ: где детальных дорог нет, маршрут тоже идёт лентой — шириной в одну полосу,
|
|
649
|
-
* в правой половине дороги по ходу (смещение от оси трассы на полполосы). Полос там никто не
|
|
650
|
-
* знает; ширина и сторона — по умолчанию, свои можно передать (`BuildOptions.outside`).
|
|
651
|
-
*/
|
|
652
|
-
declare const OUTSIDE_LANE_M = 3.3;
|
|
653
|
-
/**
|
|
654
|
-
* Переход между лентой по полосам и лентой вне покрытия: ширина и смещение меняются не круче
|
|
655
|
-
* этого (метров на метр; с запасом до 5 см на метр — сглаживание оси добавляет свои доли) — длина
|
|
656
|
-
* перехода `1.5 · Δ / RAMP_SLOPE` (у smoothstep наибольший наклон в полтора раза больше среднего;
|
|
657
|
-
* разница ширин считается вдвое — `evenWidths` у порога ровняет ширину вдвое круче), но не короче
|
|
658
|
-
* `JOIN_M` и не длиннее половины куска покрытия.
|
|
659
|
-
*/
|
|
660
|
-
declare const RAMP_SLOPE = 0.045;
|
|
661
|
-
interface OutsideOptions {
|
|
662
|
-
/** Ширина полосы вне покрытия, метры (лента — она минус `RIBBON_MARGIN_M`). */
|
|
663
|
-
laneM?: number;
|
|
664
|
-
/** Смещение оси ленты от оси трассы вправо по ходу, метры (односторонняя улица — 0). */
|
|
665
|
-
offsetM?: number;
|
|
666
|
-
}
|
|
667
|
-
interface BuildOptions {
|
|
668
|
-
/** Склеивать покрытие через щель не длиннее (метры). */
|
|
669
|
-
gapM?: number;
|
|
670
|
-
/**
|
|
671
|
-
* Лента и вне покрытия (по умолчанию — да, `OUTSIDE_LANE_M` справа от оси). `false` — как
|
|
672
|
-
* раньше: лента только на покрытии, на его краях сходится к линии маршрута.
|
|
673
|
-
*/
|
|
674
|
-
outside?: OutsideOptions | false;
|
|
675
|
-
/**
|
|
676
|
-
* Форма концов ленты (`RibbonCap`, по умолчанию `round`). У основной ленты — начало (`arrow` там
|
|
677
|
-
* — `round`) и конец; прочие группы и разрешённые полосы — `round`, у `flat` — прямые.
|
|
678
|
-
*/
|
|
679
|
-
cap?: RibbonCap;
|
|
680
|
-
}
|
|
681
|
-
/**
|
|
682
|
-
* ЛЕНТА ИЗ ПЛАНА.
|
|
683
|
-
*
|
|
684
|
-
* Главный путь — одна непрерывная лента на каждый кусок покрытия: по участку — на группу
|
|
685
|
-
* рекомендуемых полос (той, куда ведёт перестроение, иначе — на самую широкую), в `changes` —
|
|
686
|
-
* S-переход из полосы в группу, между участками — плавная смесь конца одного с началом другого.
|
|
687
|
-
* Вне покрытия (`BuildOptions.outside`, по умолчанию) лента продолжается шириной в одну полосу
|
|
688
|
-
* справа от оси трассы, и линия маршрута уступает ей целиком; на краях покрытия ширина и смещение
|
|
689
|
-
* переходят плавно (`RAMP_SLOPE`). С `outside: false` — по-старому: на краях покрытия ось ленты
|
|
690
|
-
* сходится к оси трассы, дальше идёт линия маршрута. Остальные
|
|
691
|
-
* группы рекомендуемых — своими лентами по участку, `allowed` — бледной лентой, `other` — ничего.
|
|
692
|
-
* Все площадные фичи — готовым контуром (`outline`), шевроны — отдельными прямыми.
|
|
693
|
-
*/
|
|
694
|
-
declare function buildRibbon(plan: LanePlan, geometry: LonLat[], opts?: BuildOptions): Ribbon;
|
|
695
|
-
/**
|
|
696
|
-
* ПОВОРОТ ЧЕРЕЗ УЗЕЛ — по графу полос, как скругление угла асфальта у стенда. Полоса приходящего
|
|
697
|
-
* отрезка и полоса уходящего — две прямые (направления берутся за пределами узла, где осевые
|
|
698
|
-
* чистые); ось ленты в окне `[lo, hi]` — прямая по приходящей полосе до точки их пересечения и
|
|
699
|
-
* прямая по уходящей, а дугу на изломе делает `smoothCorners` (гауссово окно по длине: касательная
|
|
700
|
-
* и кривизна непрерывны, кривизна — колоколом). Раньше ось в узле шла по осевым отрезков как
|
|
701
|
-
* есть: конец приходящей полосы торчал за начало дуги (сервер ведёт осевую до середины узла, а
|
|
702
|
-
* уходящая полоса начинается сбоку от неё), и кромки ленты выходили со ступенькой и горбом.
|
|
703
|
-
*
|
|
704
|
-
* Окно — до `TURN_WINDOW_M` в каждую сторону от стыка (не дальше половины отрезка), поворот
|
|
705
|
-
* положе `TURN_MIN_DEG` не трогается: там стык отрезков — продолжение улицы. Точки окна
|
|
706
|
-
* раскладываются по новой кривой пропорционально станциям; ширина переходит от приходящей к
|
|
707
|
-
* уходящей плавно (smoothstep), уровень — прежний.
|
|
708
|
-
*/
|
|
709
|
-
declare const TURN_WINDOW_M = 14;
|
|
710
|
-
declare const TURN_MIN_DEG = 20;
|
|
711
|
-
/** Функция нормального распределения (Абрамовиц — Стиган 7.1.26, ошибка < 1.5e-7). */
|
|
712
|
-
declare function normalCdf(z: number): number;
|
|
713
|
-
/**
|
|
714
|
-
* ВЕС ПЛАНА ВНЕ ПОКРЫТИЯ (решение владельца 24.10.2026): 1 — машина и вне покрытия на оси ленты «полполосы справа»,
|
|
715
|
-
* как в обычном режиме полос Baidu/Amap; 0 — на линии маршрута (так было в этапе 1, 23.10.2026).
|
|
716
|
-
*/
|
|
717
|
-
declare const CAR_OUTSIDE_WEIGHT = 1;
|
|
718
|
-
/**
|
|
719
|
-
* ВЕС ПЛАНА В ПОЗЕ МАШИНЫ на метре `s` (`RibbonCar.weights`): на куске покрытия `[a, b]` — 1 (машина на ленте, в
|
|
720
|
-
* том числе пока лента переходит из полосы в ленту вне покрытия), вне кусков — `CAR_OUTSIDE_WEIGHT`, за `JOIN_M` до
|
|
721
|
-
* края куска — подъезд smoothstep к 1 (при весе вне покрытия меньше 1: машина съезжает на ленту по метрам).
|
|
722
|
-
*/
|
|
723
|
-
declare function carWeight(s: number, runs: [number, number][]): number;
|
|
724
|
-
/**
|
|
725
|
-
* Значение на метре `s` по точкам с метрами `st` (не убывают): линейно между соседними, за концами — крайнее. На
|
|
726
|
-
* повторе метра (окно поворота, `filletTurn`) берётся первая точка.
|
|
727
|
-
*/
|
|
728
|
-
declare function valueAt(st: number[], v: number[], s: number): number;
|
|
729
|
-
/** Станции от `a` до `b` через `step`, концы включены. */
|
|
730
|
-
declare function stationsBetween(a: number, b: number, step: number): number[];
|
|
731
|
-
/**
|
|
732
|
-
* РОВНАЯ ШИРИНА: полосы соседних отрезков одной улицы расходятся на сантиметры (3.5 и 3.333 м), и
|
|
733
|
-
* лента от этого шла бы ступеньками. Ширина, отличающаяся от средней по куску меньше чем на
|
|
734
|
-
* `EVEN_WIDTH_M`, приравнивается к ней; настоящая смена (лента на две полосы) остаётся, а между
|
|
735
|
-
* порогом и двумя порогами ширина непрерывно возвращается к своей.
|
|
736
|
-
*/
|
|
737
|
-
declare const EVEN_WIDTH_M = 0.5;
|
|
738
|
-
declare function evenWidths(widths: number[]): number[];
|
|
739
|
-
/** Допуск прореживания оси шевронов, метры. */
|
|
740
|
-
declare const CHEVRON_TOLERANCE_M = 0.1;
|
|
741
|
-
/** Прямой кусок оси короче этого шевронов не получает (метры). */
|
|
742
|
-
declare const CHEVRON_MIN_RUN_M = 6;
|
|
743
|
-
/** Дуглас — Пойкер: номера оставленных точек (концы — всегда). */
|
|
744
|
-
declare function simplifyIdx(pts: XY[], tol: number): number[];
|
|
745
|
-
/** Шаг точек ленты после пересборки по собственной длине оси, метры. */
|
|
746
|
-
declare const OUTLINE_STEP_M = 1;
|
|
747
|
-
/**
|
|
748
|
-
* Ломаная с атрибутами → точки через равный шаг ПО СОБСТВЕННОЙ ДЛИНЕ. Станции маршрута для этого не
|
|
749
|
-
* годятся: на внутренней стороне поворота полоса короче трассы, и точки там сбивались в кучу —
|
|
750
|
-
* окно сглаживания сжималось, дуга выходила с радиусом в пару метров.
|
|
751
|
-
*/
|
|
752
|
-
declare function resampleLine(pts: XY[], attrs: number[][], step?: number): {
|
|
753
|
-
pts: XY[];
|
|
754
|
-
attrs: number[][];
|
|
755
|
-
};
|
|
756
|
-
/** Сглаживание ширины по точкам оси (сигма — в точках, т. е. метрах после `resampleLine`). */
|
|
757
|
-
declare const WIDTH_SMOOTH_PTS = 2;
|
|
758
|
-
/**
|
|
759
|
-
* ШИРИНА БЕЗ ИЗЛОМОВ: ширина приходит по станциям через 2 м и после пересборки оси через метр
|
|
760
|
-
* идёт ломаной — на переходе ширины (поворот на две полосы, `filletTurn`) кромка от этого шла
|
|
761
|
-
* зубцами через точку. Гаусс по точкам; ровная ширина остаётся ровной (только там, где она
|
|
762
|
-
* меняется, что-то и сглаживается), концы — на месте.
|
|
763
|
-
*/
|
|
764
|
-
declare function smoothWidths(w: number[], sigma?: number): number[];
|
|
765
|
-
/**
|
|
766
|
-
* СКРУГЛЕНИЕ ИЗЛОМОВ ОСИ. Точки идут через равный шаг (`resampleLine`); у излома ось сглаживается
|
|
767
|
-
* гауссовым окном, и только там: в пределах двух сигм от излома берётся сглаженная точка, дальше
|
|
768
|
-
* за полторы сигмы — плавный возврат к исходной. Прямые участки и S-переходы (они и так гладкие)
|
|
769
|
-
* остаются точно в полосе.
|
|
770
|
-
*
|
|
771
|
-
* Сигма — ПО УГЛУ ИЗЛОМА: поворот на перекрёстке (90°) — `CORNER_SMOOTH_M`, дуга радиусом около
|
|
772
|
-
* 1.6 сигмы; пологий излом улицы (20–30°) — пропорционально меньше, иначе лента срезала бы его и
|
|
773
|
-
* съезжала с полосы на кромку. Изломы ближе трёх метров друг к другу — один (на повороте осевые
|
|
774
|
-
* соседних отрезков стыкуются двумя изломами со скачком между ними).
|
|
775
|
-
*
|
|
776
|
-
* За концами ломаная продолжается ЦЕНТРАЛЬНЫМ отражением (`2·p₀ − pₖ`): прямая остаётся прямой, а
|
|
777
|
-
* крайние точки — на месте, то есть лента по-прежнему начинается ровно на конце линии маршрута.
|
|
778
|
-
*/
|
|
779
|
-
declare function smoothCorners(pts: XY[], sigmaM?: number): XY[];
|
|
780
|
-
/**
|
|
781
|
-
* КОНТУР ЛЕНТЫ: правая кромка по ходу, форма конца (`caps[1]`), левая кромка обратно, форма начала
|
|
782
|
-
* (`caps[0]`) — кольцо против часовой. Нормаль в точке — по хорде соседей (ось гладкая, «miter» не
|
|
783
|
-
* нужен). Точка кромки, которая пошла бы назад относительно оси (кривизна круче полуширины),
|
|
784
|
-
* выбрасывается: кромка не делает петлю. Концы кромок — ровно `centre ± normal · half` крайних
|
|
785
|
-
* точек, от них и строится форма конца (`capPoints`).
|
|
786
|
-
*/
|
|
787
|
-
declare function outlineOf(centre: XY[], half: number[], normals?: XY[], caps?: [RibbonCap, RibbonCap]): XY[];
|
|
788
|
-
/**
|
|
789
|
-
* ФОРМА КОНЦА — точки контура МЕЖДУ концами кромок (сами концы кромок — в `edgesOf`). `c` — крайняя
|
|
790
|
-
* точка оси, `nrm` — нормаль вправо в ней, `h` — полуширина. Конец (`atEnd`) — от правой кромки
|
|
791
|
-
* через переднюю точку к левой, начало — от левой через заднюю к правой: кольцо остаётся против
|
|
792
|
-
* часовой. Полукруг `c + h·(±n·cos θ ± t·sin θ)`, θ = kπ/`CAP_SEGMENTS`: в θ = 0 касательная к
|
|
793
|
-
* нему — направление оси, то есть кромка переходит в дугу без излома (ось у конца — крайний отрезок,
|
|
794
|
-
* по нему и нормаль, `normalsOf`).
|
|
795
|
-
*/
|
|
796
|
-
declare function capPoints(c: XY, nrm: XY, h: number, cap: RibbonCap, atEnd: boolean): XY[];
|
|
797
|
-
/** Кромки ленты по ходу: правая и левая (то, из чего `outlineOf` собирает кольцо). */
|
|
798
|
-
declare function edgesOf(centre: XY[], half: number[], normals?: XY[]): {
|
|
799
|
-
right: XY[];
|
|
800
|
-
left: XY[];
|
|
801
|
-
};
|
|
802
|
-
/**
|
|
803
|
-
* Нормали оси вправо по ходу — по хорде соседей (у концов — по крайнему отрезку). Отдельно от
|
|
804
|
-
* `outlineOf`: у двух половин ленты, разрезанной в точке машины (`lib/route-progress.ts`), нормаль
|
|
805
|
-
* в точке разреза обязана быть одной — тогда кромки сходятся без щели и нахлёста.
|
|
806
|
-
*/
|
|
807
|
-
declare function normalsOf(centre: XY[]): XY[];
|
|
808
|
-
interface RoutePiece {
|
|
809
|
-
coords: LonLat[];
|
|
810
|
-
/** Для каждой точки куска — номер отрезка исходной трассы, на котором она лежит. */
|
|
811
|
-
source: number[];
|
|
812
|
-
}
|
|
813
|
-
/**
|
|
814
|
-
* Трасса без скрытых отрезков (метры) — куски для обычной линии маршрута. На концах куска точка
|
|
815
|
-
* ставится ровно на границу: линия упирается в начало ленты без щели и без нахлёста.
|
|
816
|
-
*/
|
|
817
|
-
declare function routePieces(geometry: LonLat[], hidden: [number, number][]): RoutePiece[];
|
|
818
|
-
/** Метры трассы до точек (манёвров): проекция по порядку, каждая не раньше предыдущей. */
|
|
819
|
-
declare function metresAlong(geometry: LonLat[], points: LonLat[]): number[];
|
|
820
|
-
/** Трасса в метрах — для ведения (точка и курс по метру). */
|
|
821
|
-
declare function routeMeasure(geometry: LonLat[]): {
|
|
822
|
-
frame: Frame;
|
|
823
|
-
route: Measured;
|
|
824
|
-
};
|
|
825
|
-
/** Высота полотна в точке на уровне, метры. */
|
|
826
|
-
type HeightAt = (p: LonLat, level: number) => number;
|
|
827
|
-
/** Этаж эстакады стенда (`LEVEL_HEIGHT` у `vendor/city.js`) — запасная высота без сцены. */
|
|
828
|
-
declare const LEVEL_HEIGHT_M = 8;
|
|
829
|
-
declare const fallbackHeight: HeightAt;
|
|
830
|
-
/**
|
|
831
|
-
* Свойства высоты фичи — как у краски стенда: ровная — `lift`, со склоном — `liftPath`
|
|
832
|
-
* (`lon,lat,h;…`, разбирает движок, `parseLift`). Нулевая высота — без свойства вовсе.
|
|
833
|
-
*/
|
|
834
|
-
declare function liftProps(f: RibbonFeature, heightAt: HeightAt): Record<string, number | string>;
|
|
835
|
-
/** То же по готовым отметкам точек `line` — ведение режет ленту, не спрашивая поле высот заново. */
|
|
836
|
-
declare function liftPropsOf(line: LonLat[], hs: number[]): Record<string, number | string>;
|
|
837
|
-
|
|
838
|
-
/**
|
|
839
|
-
* ПЛАН ПОЛОС ВДОЛЬ МАРШРУТА — `POST /tiles/ldroads/guidance` (под общим ключом шлюза, как остальные
|
|
840
|
-
* `/tiles/ldroads/*`; контракт — `docs/map-v2/LD-LANE-GUIDANCE.md` монорепозитория).
|
|
841
|
-
*
|
|
842
|
-
* Перенесено из веб-карты (`src/WebMap/src/api/lanes.ts` + `map/lane-plan.ts`) без изменения
|
|
843
|
-
* поведения: типы, тело запроса (`lanePlanRequest`, как `requestFor` веба) и разбор ответа
|
|
844
|
-
* (`parseLanePlan`). Пара у портов — `LanePlan.kt` / `LanePlan.swift`.
|
|
845
|
-
*
|
|
846
|
-
* ★ Сервис НЕОБЯЗАТЕЛЕН: нет ручки (404/405/501), ошибка, мусор в ответе, пустое покрытие — всё это
|
|
847
|
-
* `null`, и карта рисует обычную линию маршрута. Сеть — у приложения: `fetchLanePlan` берёт функцию
|
|
848
|
-
* `fetch` снаружи (и адрес — `Endpoints`/своя база), сам движок в сеть не ходит.
|
|
849
|
-
*
|
|
850
|
-
* ★ Заглушка веба `?laneMock=1` (план по опубликованным улицам на клиенте) — НЕ здесь: она про
|
|
851
|
-
* отладку сайта и тянет его данные.
|
|
852
|
-
*/
|
|
853
|
-
|
|
854
|
-
type LaneState = 'recommended' | 'allowed' | 'other';
|
|
855
|
-
interface PlanLane {
|
|
856
|
-
laneId: string;
|
|
857
|
-
/** 0 — левая по ходу. */
|
|
858
|
-
index: number;
|
|
859
|
-
widthM: number;
|
|
860
|
-
/** Осевая полосы ПО ХОДУ, `[lon, lat]`. */
|
|
861
|
-
centre: [number, number][];
|
|
862
|
-
state: LaneState;
|
|
863
|
-
turns: string[];
|
|
864
|
-
}
|
|
865
|
-
interface PlanSegment {
|
|
866
|
-
fromM: number;
|
|
867
|
-
toM: number;
|
|
868
|
-
wayId: number | string;
|
|
869
|
-
dir: string;
|
|
870
|
-
/** 1 — эстакада, 0 — земля, −1 — тоннель. */
|
|
871
|
-
level: number;
|
|
872
|
-
/** В какой полосе лента в начале отрезка (добавочное поле сервера; у заглушки может не быть). */
|
|
873
|
-
ribbonLaneId?: string;
|
|
874
|
-
lanes: PlanLane[];
|
|
875
|
-
}
|
|
876
|
-
interface PlanChange {
|
|
877
|
-
fromLane: string;
|
|
878
|
-
toLane: string;
|
|
879
|
-
startM: number;
|
|
880
|
-
endM: number;
|
|
881
|
-
}
|
|
882
|
-
interface PlanManeuver {
|
|
883
|
-
atM: number;
|
|
884
|
-
kind: string;
|
|
885
|
-
/** Полосы, с которых манёвр выполняется по плану. */
|
|
886
|
-
laneIds: string[];
|
|
887
|
-
/** Стрелки полос подхода: что разрешено с каждой. */
|
|
888
|
-
arrows: {
|
|
889
|
-
laneId: string;
|
|
890
|
-
turns: string[];
|
|
891
|
-
}[];
|
|
892
|
-
}
|
|
893
|
-
interface LanePlan {
|
|
894
|
-
version: string;
|
|
895
|
-
/** Как сопоставлено: `edges` | `geometry` | `mixed` | `null` (покрытия нет). Добавочное поле. */
|
|
896
|
-
matchedBy?: string | null;
|
|
897
|
-
coverage: [number, number][];
|
|
898
|
-
segments: PlanSegment[];
|
|
899
|
-
changes: PlanChange[];
|
|
900
|
-
maneuvers: PlanManeuver[];
|
|
901
|
-
}
|
|
902
|
-
interface LanePlanRequest {
|
|
903
|
-
geometry: [number, number][];
|
|
904
|
-
edges?: (number | string)[];
|
|
905
|
-
graphVersion: number | null;
|
|
906
|
-
maneuvers: {
|
|
907
|
-
atM: number;
|
|
908
|
-
type: string;
|
|
909
|
-
modifier: string;
|
|
910
|
-
}[];
|
|
911
|
-
}
|
|
912
|
-
declare const GUIDANCE_URL = "/tiles/ldroads/guidance";
|
|
913
|
-
/** Манёвр маршрута: где он и что это (как шаг `/route`: `type` + `modifier`). */
|
|
914
|
-
interface RouteManeuver {
|
|
915
|
-
at: LonLat;
|
|
916
|
-
type: string;
|
|
917
|
-
modifier?: string;
|
|
918
|
-
}
|
|
919
|
-
/**
|
|
920
|
-
* Маршрут для плана полос: трасса по ходу (`[lon, lat]`) и её манёвры. `edges` — `edgeId` шагов
|
|
921
|
-
* `/route`, если они есть у приложения: с ними сервис сопоставляет точнее.
|
|
922
|
-
*/
|
|
923
|
-
interface LaneRoute {
|
|
924
|
-
geometry: LonLat[];
|
|
925
|
-
maneuvers?: RouteManeuver[];
|
|
926
|
-
edges?: (number | string)[];
|
|
927
|
-
graphVersion?: number | null;
|
|
928
|
-
}
|
|
929
|
-
/**
|
|
930
|
-
* Тело запроса плана: трасса и манёвры с метрами вдоль неё (как `requestFor` веб-карты). Рёбер
|
|
931
|
-
* графа нет — поле опущено.
|
|
932
|
-
*/
|
|
933
|
-
declare function lanePlanRequest(route: LaneRoute): LanePlanRequest;
|
|
934
|
-
/** Ручки нет (404/405/501) — не спрашиваем снова столько времени. */
|
|
935
|
-
declare const ABSENT_RETRY_MS: number;
|
|
936
|
-
/** Минимум от `fetch`, который нужен запросу плана (подходит `globalThis.fetch`). */
|
|
937
|
-
type FetchLike = (url: string, init: {
|
|
938
|
-
method: string;
|
|
939
|
-
headers: Record<string, string>;
|
|
940
|
-
body: string;
|
|
941
|
-
signal?: AbortSignal;
|
|
942
|
-
}) => Promise<{
|
|
943
|
-
ok: boolean;
|
|
944
|
-
status: number;
|
|
945
|
-
json(): Promise<unknown>;
|
|
946
|
-
}>;
|
|
947
|
-
interface FetchLanePlanOptions {
|
|
948
|
-
/** Адрес ручки (по умолчанию — `GUIDANCE_URL` на своём сайте). */
|
|
949
|
-
url?: string;
|
|
950
|
-
/** Функция запроса (по умолчанию — `globalThis.fetch`). */
|
|
951
|
-
fetch?: FetchLike;
|
|
952
|
-
signal?: AbortSignal;
|
|
953
|
-
}
|
|
954
|
-
/**
|
|
955
|
-
* Запрос плана у сервиса. Любая ошибка — `null`; нет ручки — `null` и `ABSENT_RETRY_MS` без
|
|
956
|
-
* запросов (на каждый `url` свой счётчик).
|
|
957
|
-
*/
|
|
958
|
-
declare function fetchLanePlan(req: LanePlanRequest, opts?: FetchLanePlanOptions): Promise<LanePlan | null>;
|
|
959
|
-
/** Сбросить память об отсутствующей ручке (тесты, смена стенда). */
|
|
960
|
-
declare function resetLanePlanAbsence(): void;
|
|
961
|
-
/**
|
|
962
|
-
* Ответ → план. Отбрасывается всё, что не описывает полосу или участок: рисовать по этому будет
|
|
963
|
-
* движок, и мусор дешевле поймать здесь. Нет покрытия или участков — `null` (полос нет).
|
|
964
|
-
*/
|
|
965
|
-
declare function parseLanePlan(raw: unknown): LanePlan | null;
|
|
966
|
-
|
|
967
|
-
/** Зум тайлов источника ленты: `maxzoom` geojson-источника osmgl по умолчанию — 18. */
|
|
968
|
-
declare const RIBBON_TILE_Z = 18;
|
|
969
|
-
/** Единиц в тайле (`EXTENT` geojson-источника osmgl). */
|
|
970
|
-
declare const TILE_EXTENT = 4096;
|
|
971
|
-
/** Выдвиг вершины на разрезе, единиц тайла (`SURFACE_CUT_BLEED` osmgl). */
|
|
972
|
-
declare const CUT_BLEED = 1;
|
|
973
|
-
/** `[lon, lat]` → единицы тайла z18 во всём мире (та же меркаторская формула, что у движка). */
|
|
974
|
-
declare function toUnits(p: LonLat): [number, number];
|
|
975
|
-
declare function fromUnits(u: [number, number]): LonLat;
|
|
976
|
-
/**
|
|
977
|
-
* Отступ от границы тайла номер `k` (её координата — `k · 4096` единиц z18) у куска СПРАВА/СНИЗУ от
|
|
978
|
-
* неё. Сосед слева/сверху касается границы, и движок выдвигает его на единицу своего тайла; кусок
|
|
979
|
-
* справа обязан начаться ровно там же — после округления координат тайла (geojson-источник
|
|
980
|
-
* округляет до целых) — и не лечь на границу сам (иначе выдвинется и он):
|
|
981
|
-
* - тайл z18: 1.2 и 0.6 округляются до 1 = выдвиг соседа;
|
|
982
|
-
* - тайл z17 (зум карты 17.5–18): у чётной границы (она же граница z17) 1.2 единицы z18 — это 0.6
|
|
983
|
-
* единицы z17, округляется до 1 = выдвиг соседа на его z17; нечётная граница лежит ВНУТРИ тайла
|
|
984
|
-
* z17, сосед там не выдвигается, и 0.6 единицы z18 = 0.3 единицы z17 округляются до нуля — кусок
|
|
985
|
-
* сходится с соседом в той же точке.
|
|
986
|
-
*/
|
|
987
|
-
declare const cutInset: (k: number) => number;
|
|
988
|
-
/**
|
|
989
|
-
* Многоугольник (`[outer, ...holes]`, кольца `[lon, lat]`) → многоугольники по тайлам z18 с правилом
|
|
990
|
-
* стыка `cutInset`. Целиком внутри тайла и далеко от его левой и верхней границ — как есть.
|
|
991
|
-
*/
|
|
992
|
-
declare function tileParts(poly: LonLat[][]): LonLat[][][];
|
|
993
|
-
/** Маска: многоугольники в единицах z18 с рамками — вычитаются только задетые. */
|
|
994
|
-
interface Mask {
|
|
995
|
-
polys: {
|
|
996
|
-
box: [number, number, number, number];
|
|
997
|
-
geom: Geom;
|
|
998
|
-
}[];
|
|
999
|
-
}
|
|
1000
|
-
declare function maskOf(rings: LonLat[][]): Mask;
|
|
1001
|
-
/** Кольцо минус маска → кольца-многоугольники (`[outer, ...holes]`). Не задето — как есть. */
|
|
1002
|
-
declare function minusMask(ring: LonLat[], mask: Mask): LonLat[][][];
|
|
1003
|
-
/** Длина куска ленты по станциям, метры: столько пересчитывается при движении машины. */
|
|
1004
|
-
declare const CHUNK_M = 40;
|
|
1005
|
-
/** Кусок площадной фичи: вид и дробный диапазон её точек; `cut` — один из концов в точке машины. */
|
|
1006
|
-
interface AreaSpan {
|
|
1007
|
-
kind: RibbonKind;
|
|
1008
|
-
from: number;
|
|
1009
|
-
to: number;
|
|
1010
|
-
cut?: boolean;
|
|
1011
|
-
}
|
|
1012
|
-
/**
|
|
1013
|
-
* Разбиение площадной фичи на куски: границы — станции, кратные `CHUNK_M` (от ведения не
|
|
1014
|
-
* зависят — куски без машины одни и те же, их можно хранить), и точка машины `s` (позади — `*-passed`).
|
|
1015
|
-
*/
|
|
1016
|
-
declare function areaSpans(f: RibbonFeature, s: number | null, chunkM?: number): AreaSpan[];
|
|
1017
|
-
/**
|
|
1018
|
-
* Ось фичи в плоских метрах с нормалями — одна на фичу, общая для всех её кусков. `caps` — форма
|
|
1019
|
-
* её настоящих концов (`RibbonFeature.caps`): её получают только куски, доходящие до конца фичи.
|
|
1020
|
-
*/
|
|
1021
|
-
interface AreaFrame {
|
|
1022
|
-
frame: Frame;
|
|
1023
|
-
xy: XY[];
|
|
1024
|
-
normals: XY[];
|
|
1025
|
-
widths: number[];
|
|
1026
|
-
caps: [RibbonCap, RibbonCap];
|
|
1027
|
-
}
|
|
1028
|
-
declare function areaFrame(f: RibbonFeature): AreaFrame;
|
|
1029
|
-
/**
|
|
1030
|
-
* Контур куска `[from, to]` фичи: точки, нормали и ширины на концах — интерполяция соседних. Конец
|
|
1031
|
-
* куска на конце фичи — её формы (`AreaFrame.caps`: скругление, стрелка), на разрезе — прямой: там
|
|
1032
|
-
* кусок встык продолжает соседний. Форма конца — часть того же кольца, дальше — то же вычитание и
|
|
1033
|
-
* резка по тайлам, что у всей ленты.
|
|
1034
|
-
*/
|
|
1035
|
-
declare function spanOutline(af: AreaFrame, from: number, to: number): LonLat[];
|
|
1036
|
-
/** Ось куска `[from, to]` — `[lon, lat]`, для свойств высоты. */
|
|
1037
|
-
declare const spanLine: (f: RibbonFeature, from: number, to: number) => LonLat[];
|
|
1038
|
-
|
|
1039
|
-
/**
|
|
1040
|
-
* ПРОЙДЕННАЯ ЧАСТЬ МАРШРУТА — СЕРАЯ (как у Baidu: позади машины линия и лента по полосам серые,
|
|
1041
|
-
* впереди — синие или цветом пробок; граница — ровно в точке машины).
|
|
1042
|
-
*
|
|
1043
|
-
* Чистые функции без движка (проверка — `route-progress.test.ts` и общие фикстуры
|
|
1044
|
-
* `tests/fixtures/ld-lane-ribbon/`, их же гоняют порты Android и iOS). Метр прогресса — метр
|
|
1045
|
-
* трассы той же мерой, что у плана полос и ведения: плоская формула на звено (`linkM`).
|
|
1046
|
-
*
|
|
1047
|
-
* ★ ЛИНИЯ: синяя линия маршрута остаётся ЦЕЛОЙ, серая пройденная кладётся ПОВЕРХ неё (кусками вне
|
|
1048
|
-
* ленты по полосам). Резать синюю нельзя: шевроны движок ставит от начала линии, и у линии,
|
|
1049
|
-
* укорачиваемой с начала, стрелки ехали бы вместе с машиной. Под серой (непрозрачной) синие
|
|
1050
|
-
* шевроны не видны.
|
|
1051
|
-
*
|
|
1052
|
-
* ★ ЛЕНТА: площадные фичи (`band`, `allowed`) режутся в точке машины на две — пройденную
|
|
1053
|
-
* (`*-passed`, серая) и оставшуюся, с ОДНОЙ нормалью в точке разреза: кромки сходятся без щели и
|
|
1054
|
-
* нахлёста. Шевроны целиком позади выбрасываются; шеврон, на котором машина, остаётся целым (по той
|
|
1055
|
-
* же причине, что у линии) — его пройденную часть закрывает серая лента, слой которой выше
|
|
1056
|
-
* шевронов, — там стрелки бледные.
|
|
1057
|
-
*/
|
|
1058
|
-
|
|
1059
|
-
/** Трасса с накопленными метрами к каждой точке (мерой сервера, `linkM`). */
|
|
1060
|
-
interface RouteLine {
|
|
1061
|
-
geometry: LonLat[];
|
|
1062
|
-
cum: number[];
|
|
1063
|
-
length: number;
|
|
1064
|
-
}
|
|
1065
|
-
declare function routeLine(geometry: LonLat[]): RouteLine;
|
|
1066
|
-
/**
|
|
1067
|
-
* Точка трассы на метре `s`. Доля по звену — по его длине мерой сервера, сама точка — в градусах:
|
|
1068
|
-
* плоская система метров аффинна градусам, так что это та же точка, что у `routePieces`.
|
|
1069
|
-
*/
|
|
1070
|
-
declare function pointOn(line: RouteLine, s: number): LonLat;
|
|
1071
|
-
/** Кусок трассы между метрами (концы — точно на метрах). Короче `minM` — пусто. */
|
|
1072
|
-
declare function lineBetween(line: RouteLine, from: number, to: number, minM?: number): LonLat[];
|
|
1073
|
-
/** Пройденный кусок короче этого не рисуется (его и так закрывает метка машины). */
|
|
1074
|
-
declare const PASSED_MIN_M = 0.5;
|
|
1075
|
-
/**
|
|
1076
|
-
* Пройденные куски ОБЫЧНОЙ линии: трасса вне ленты по полосам (`hidden`, как у `routePieces`) от
|
|
1077
|
-
* начала до метра `s`. Пусто — ничего не пройдено (или всё пройденное — под лентой).
|
|
1078
|
-
*/
|
|
1079
|
-
declare function passedPieces(line: RouteLine, hidden: [number, number][], s: number): LonLat[][];
|
|
1080
|
-
/**
|
|
1081
|
-
* Положение метра `s` среди станций (не убывают): дробный номер точки в `[0, n − 1]`. На ровном
|
|
1082
|
-
* месте (повтор станции) — первая точка после него.
|
|
1083
|
-
*/
|
|
1084
|
-
declare function fracIndex(stations: number[], s: number): number;
|
|
1085
|
-
/**
|
|
1086
|
-
* Значения точек между дробными номерами `a` и `b`: значение на `a`, все целые строго между,
|
|
1087
|
-
* значение на `b`. Так режутся и ось, и атрибуты точек (ширина, уровень, станция, высота).
|
|
1088
|
-
*/
|
|
1089
|
-
declare function sliceAt<T>(values: T[], a: number, b: number, mix: (x: T, y: T, t: number) => T): T[];
|
|
1090
|
-
declare const mixNum: (x: number, y: number, t: number) => number;
|
|
1091
|
-
declare const mixLevel: (x: number, y: number, t: number) => number;
|
|
1092
|
-
declare const mixLonLat: (x: LonLat, y: LonLat, t: number) => LonLat;
|
|
1093
|
-
/** Пройденный вид площадной фичи. */
|
|
1094
|
-
declare const passedKind: (k: RibbonKind) => RibbonKind;
|
|
1095
|
-
/** Кусок ленты на карте: фича и откуда она взята — номер исходной и дробный диапазон её точек. */
|
|
1096
|
-
interface RibbonPiece {
|
|
1097
|
-
feature: RibbonFeature;
|
|
1098
|
-
source: number;
|
|
1099
|
-
from: number;
|
|
1100
|
-
to: number;
|
|
1101
|
-
}
|
|
1102
|
-
/**
|
|
1103
|
-
* ЛЕНТА НА МЕТРЕ ВЕДЕНИЯ `s`: позади — серая, впереди — как была. `null` — ведения нет, лента
|
|
1104
|
-
* целиком цветная. Фичи без станций остаются как есть.
|
|
1105
|
-
*/
|
|
1106
|
-
declare function ribbonAtProgress(features: RibbonFeature[], s: number | null): RibbonPiece[];
|
|
1107
|
-
/**
|
|
1108
|
-
* Что из данных ленты меняется на метре `s`: число фич целиком позади и есть ли фича, которую
|
|
1109
|
-
* режет точка машины. Пока это не меняется, данные источника заново не заливаются.
|
|
1110
|
-
*/
|
|
1111
|
-
declare function ribbonProgressState(features: RibbonFeature[], s: number | null): {
|
|
1112
|
-
passed: number;
|
|
1113
|
-
cut: boolean;
|
|
1114
|
-
};
|
|
1115
|
-
|
|
1116
|
-
/**
|
|
1117
|
-
* ВЕДЕНИЕ ПО ПОЛОСАМ — что показать на метре маршрута: следующий манёвр, ряд стрелок полос и
|
|
1118
|
-
* камеру (наклон и приближение у манёвра внутри покрытия, как у Baidu).
|
|
1119
|
-
*
|
|
1120
|
-
* Чистые функции (проверка — `lane-guidance.test.ts`). ★ Подсказка говорит, КУДА ВСТАТЬ, и никогда
|
|
1121
|
-
* — «вы в полосе N»: своей полосы карта не знает (точности приёмника на это не хватает).
|
|
1122
|
-
*/
|
|
1123
|
-
|
|
1124
|
-
/** Ближе этого к манёвру внутри покрытия камера наклоняется и приближается. */
|
|
1125
|
-
declare const CLOSE_M = 300;
|
|
1126
|
-
declare const FAR_VIEW: {
|
|
1127
|
-
pitch: number;
|
|
1128
|
-
zoom: number;
|
|
1129
|
-
};
|
|
1130
|
-
declare const CLOSE_VIEW: {
|
|
1131
|
-
pitch: number;
|
|
1132
|
-
zoom: number;
|
|
1133
|
-
};
|
|
1134
|
-
/** Ряд стрелок подсказки дальше этого не показывается: заранее он только отвлекает. */
|
|
1135
|
-
declare const HINT_M = 600;
|
|
1136
|
-
/** Манёвр плана впереди (или только что пройденный — пока не отъехали `AFTER_M`). */
|
|
1137
|
-
declare function upcoming(plan: LanePlan | null, s: number): PlanManeuver | null;
|
|
1138
|
-
/** Доля «близкого вида» 0..1 на метре `s`. */
|
|
1139
|
-
declare function closeness(plan: LanePlan | null, s: number): number;
|
|
1140
|
-
/** Наклон и зум камеры ведения на метре `s`. */
|
|
1141
|
-
declare function guidanceCamera(plan: LanePlan | null, s: number): {
|
|
1142
|
-
pitch: number;
|
|
1143
|
-
zoom: number;
|
|
1144
|
-
close: number;
|
|
1145
|
-
};
|
|
1146
|
-
interface HintLane {
|
|
1147
|
-
laneId: string;
|
|
1148
|
-
turns: string[];
|
|
1149
|
-
/** Сюда вставать: полоса из `laneIds` манёвра. */
|
|
1150
|
-
recommended: boolean;
|
|
1151
|
-
/** Тоже годится, но план её не выбрал (`allowed` на подходе). */
|
|
1152
|
-
allowed: boolean;
|
|
1153
|
-
}
|
|
1154
|
-
interface LaneHint {
|
|
1155
|
-
atM: number;
|
|
1156
|
-
kind: string;
|
|
1157
|
-
lanes: HintLane[];
|
|
1158
|
-
}
|
|
1159
|
-
/**
|
|
1160
|
-
* Ряд стрелок для манёвра: полосы подхода (участок, на котором стоит манёвр) слева направо,
|
|
1161
|
-
* стрелки — из `arrows` манёвра, иначе — у самой полосы.
|
|
1162
|
-
*/
|
|
1163
|
-
declare function hintFor(plan: LanePlan | null, m: PlanManeuver | null): LaneHint | null;
|
|
1164
|
-
/** Подсказка на метре `s`: только если манёвр ближе `HINT_M`. */
|
|
1165
|
-
declare function hintAt(plan: LanePlan | null, s: number): (LaneHint & {
|
|
1166
|
-
distanceM: number;
|
|
1167
|
-
}) | null;
|
|
1168
|
-
/**
|
|
1169
|
-
* Ряд стрелок у точки манёвра (шаг списка манёвров приложения): манёвр плана в 25 м от точки по трассе
|
|
1170
|
-
* `geometry` (`hintForStep` веб-карты, `laneHintAt` портов). `null` — у шага полос нет.
|
|
1171
|
-
*/
|
|
1172
|
-
declare function hintNear(plan: LanePlan | null, geometry: LonLat[], at: LonLat): LaneHint | null;
|
|
1173
|
-
/** Кадр ведения: камера и что показать (`guideStep` веб-карты). */
|
|
1174
|
-
interface GuideFrame {
|
|
1175
|
-
center: LonLat;
|
|
1176
|
-
zoom: number;
|
|
1177
|
-
pitch: number;
|
|
1178
|
-
bearing: number;
|
|
1179
|
-
/** Доля «близкого вида» 0..1. */
|
|
1180
|
-
close: number;
|
|
1181
|
-
/** Курс по маршруту, градусы, — для своей метки «я здесь». */
|
|
1182
|
-
courseDeg: number;
|
|
1183
|
-
/** Метр камеры (сглаженный метр ведения): до него линия и лента серые, на нём — значок. */
|
|
1184
|
-
s: number;
|
|
1185
|
-
}
|
|
1186
|
-
/**
|
|
1187
|
-
* ВЕДЕНИЕ ПО ПЛАНУ — метр маршрута и камера, как `stores/lanes.ts` (`advance`, `locate`) и `guideStep`
|
|
1188
|
-
* (`MapView.vue`) веб-карты, одним классом без карты и часов: приложение зовёт `locate` на каждую
|
|
1189
|
-
* геолокацию или `advance` в демо-проезде, а на каждый кадр — `step(dt)` и ставит камеру из ответа.
|
|
1190
|
-
* Камера сглаживается по кадрам: скачок наклона на пороге читался бы рывком. Пара у портов — `LaneGuide`
|
|
1191
|
-
* (Kotlin) и `navigram/lane_guide` натива; сверка — `kmp/fixtures/lane-guide.json`.
|
|
1192
|
-
*/
|
|
1193
|
-
declare class LaneGuide {
|
|
1194
|
-
readonly plan: LanePlan | null;
|
|
1195
|
-
readonly measure: {
|
|
1196
|
-
frame: Frame;
|
|
1197
|
-
route: Measured;
|
|
1198
|
-
} | null;
|
|
1199
|
-
/** Метр маршрута, на котором «мы». */
|
|
1200
|
-
progressM: number;
|
|
1201
|
-
private cam;
|
|
1202
|
-
private started;
|
|
1203
|
-
constructor(plan: LanePlan | null, geometry: LonLat[]);
|
|
1204
|
-
get lengthM(): number;
|
|
1205
|
-
/** Начать с текущей камеры (наклон, зум): вход в ведение плавный, курс — по ходу с упреждением 30 м. */
|
|
1206
|
-
start(pitch: number, zoom: number, fromM?: number): void;
|
|
1207
|
-
/** Демо-проезд: шаг времени (секунды); у манёвра притормаживает, как машина на повороте. false — доехали. */
|
|
1208
|
-
advance(dt: number, speedMps?: number): boolean;
|
|
1209
|
-
/** Геолокация → метр маршрута (окно вперёд: назад по трассе не прыгаем). false — дальше 60 м от трассы. */
|
|
1210
|
-
locate(pos: LonLat): boolean;
|
|
1211
|
-
/** Подсказка полос на метре ведения — для панели приложения. */
|
|
1212
|
-
hint(): (LaneHint & {
|
|
1213
|
-
distanceM: number;
|
|
1214
|
-
}) | null;
|
|
1215
|
-
/** Камера на кадр. `follow` — метр камеры догоняет метр ведения сразу (демо), иначе плавно. */
|
|
1216
|
-
step(dtSec: number, follow?: boolean): GuideFrame | null;
|
|
1217
|
-
}
|
|
1218
|
-
|
|
1219
|
-
/**
|
|
1220
|
-
* ПОЛОТНО ДОРОГ — ОТДЕЛЬНЫЙ НАБОР ТАЙЛОВ.
|
|
1221
|
-
*
|
|
1222
|
-
* Перенесено из `src/WebMap/src/lib/roadbed-layer.ts` (04.10.2026) — одно место на веб-карту и
|
|
1223
|
-
* редактор стилей админки: пресет «Карта navi.gram.tj» собирается этим же кодом, и асфальт в нём
|
|
1224
|
-
* ровно тот, что рисует публичная карта. Тот же код у Kotlin (`navigram/Roadbed.kt`) и Swift
|
|
1225
|
-
* (`Navigram/Roadbed.swift`); общий эталон — `kmp/fixtures/navigram.json`.
|
|
1226
|
-
*
|
|
1227
|
-
* В общих тайлах v3 дорога — линия: у неё есть класс, имя и ширина в пикселях, но нет ни кромки,
|
|
1228
|
-
* ни перекрёстка, ни разметки. Здесь же лежат готовые ФИГУРЫ: асфальт с бордюром, пятно
|
|
1229
|
-
* перекрёстка, скруглённый бордюром угол, краска по кромкам, эстакада с подходами.
|
|
1230
|
-
*
|
|
1231
|
-
* Считаются они не здесь и не по тайлам, а на сервере, один раз на весь регион
|
|
1232
|
-
* (`deploy/rebuild-roadbed-tiles.sh`). Иначе никак: полотно строится по ГРАФУ всей сети — куски
|
|
1233
|
-
* склеиваются в улицы, перекрёстки накрываются общим пятном, подход к эстакаде тянется на сотни
|
|
1234
|
-
* метров. В тайл это не помещается: на z16 тайл — полкилометра, а буфер вокруг него — метры, и с
|
|
1235
|
-
* двух сторон общей границы вышли бы разные перекрёстки и разорванная разметка.
|
|
1236
|
-
*
|
|
1237
|
-
* Линии дорог при этом никуда не деваются: на мелком плане полотно тоньше пикселя, и до z15 карта
|
|
1238
|
-
* рисует их как раньше. Выше они УСТУПАЮТ полотну (`yieldTo`, см. `REPLACED`), а не гаснут.
|
|
1239
|
-
*/
|
|
1240
|
-
/**
|
|
1241
|
-
* Полотно приходит с потолка z16 и растягивается выше. Набор собран с z15, но берём его только с z16
|
|
1242
|
-
* (см. `BED_FROM`): тайлы z15 не нужны, раз полотно на этом зуме не рисуется.
|
|
1243
|
-
*
|
|
1244
|
-
* Ниже z15 полотна в наборе нет ВОВСЕ.
|
|
1245
|
-
*
|
|
1246
|
-
* Не «нет в стиле», а нет в тайлах: на z13 тайл — это пять километров, и слитый контур сети целого
|
|
1247
|
-
* города, обрезанный по нему, весит десятки мегабайт. Показывать его всё равно не на чем — до z15
|
|
1248
|
-
* карта рисует дороги линиями (см. `BED_FROM`), — поэтому такие тайлы просто не собираются.
|
|
1249
|
-
*/
|
|
1250
|
-
declare function roadbedSource(url: string): {
|
|
1251
|
-
url: string;
|
|
1252
|
-
minzoom: number;
|
|
1253
|
-
maxzoom: number;
|
|
1254
|
-
};
|
|
1255
|
-
/** Имя источника полотна. */
|
|
1256
|
-
declare const ROADBED_SOURCE = "roadbed";
|
|
1257
|
-
/** Адрес полотна относительно сайта (`Endpoints.roadbed` у пустой базы). */
|
|
1258
|
-
declare const ROADBED_URL = "/tileserver/data/roadbed/{z}/{x}/{y}.pbf";
|
|
1259
|
-
/**
|
|
1260
|
-
* КРАСКА ПОЛОТНА — БОЛЬШЕ НЕ РИСУЕТСЯ (решение владельца, 23.10.2026).
|
|
1261
|
-
*
|
|
1262
|
-
* В наборе полотна есть своя разметка (`roadmark`: осевые, полосы, кромки, стоп-линии, зебры;
|
|
1263
|
-
* `roadarrow`: стрелки), но она грубая — построена по графу OSM, а не нарисована. Разметку на карте
|
|
1264
|
-
* теперь даёт только сервис детальных дорог (`ldroads`, слои `ld-mark-*`), как веб-карта с `mark=0`:
|
|
1265
|
-
* там, где улицы нарисованы в редакторе, она точная, а где не нарисованы — асфальт без краски.
|
|
1266
|
-
*
|
|
1267
|
-
* Слоёв краски полотна в стиле нет вовсе — не «спрятаны», а не добавлены: спрятанный слой воркер всё
|
|
1268
|
-
* равно собирает (тайл кешируется на все случаи), а телефону это лишние вершины в каждом тайле z16.
|
|
1269
|
-
*
|
|
1270
|
-
* Список оставлен пустым для выключателя «Разметка» приложений и веб-карты: зебры набора точек
|
|
1271
|
-
* (`crossing`) он по-прежнему гасит, а краски полотна гасить больше нечего.
|
|
1272
|
-
*/
|
|
1273
|
-
declare const ROADMARK_LAYER_IDS: string[];
|
|
1274
|
-
/**
|
|
1275
|
-
* РЕЖИМ ПОЛОТНА: «один уровень» или «с высотами» (переключатель в «Слоях»).
|
|
1276
|
-
*
|
|
1277
|
-
* Разница не только в высоте, но и в самих фигурах: в одном уровне вся сеть — плоская сетка стенда
|
|
1278
|
-
* (`roadMesh`), с высотами — наземная сетка без поднятых участков и сами поднятые участки с
|
|
1279
|
-
* профилем подъёма. Поэтому режим живёт В ДАННЫХ: генератор (`deploy/roadbed/build.mjs`) метит
|
|
1280
|
-
* фигуру свойством `mode` — `both` (общее), `flat` или `lift`, — а стиль берёт общее и своё.
|
|
1281
|
-
* Фигура без метки (набор, собранный до разделения) видна в обоих режимах.
|
|
1282
|
-
*/
|
|
1283
|
-
type RoadbedMode = 'flat' | 'lift';
|
|
1284
|
-
/** Фильтры всех делящихся слоёв для режима — их ставит `setRoadbedMode` в движке карты. */
|
|
1285
|
-
declare function roadbedModeFilters(mode: RoadbedMode): Record<string, unknown[]>;
|
|
1286
|
-
/** Слои полотна — по ним переключатель растровой подложки понимает, что гасить. */
|
|
1287
|
-
declare const ROADBED_LAYER_IDS: string[];
|
|
1288
|
-
/**
|
|
1289
|
-
* ПРЕЖНИЕ ЦВЕТА ПОЛОТНА — СВОИМИ ХЕКСАМИ, ДЛЯ ТЕХ ПАЛИТР, КОМУ ССЫЛКА НЕ ИДЁТ.
|
|
1290
|
-
*
|
|
1291
|
-
* Обычно асфальт берёт цвет дорог у темы (см. `bedLayer`), и это правильно: улица не должна менять
|
|
1292
|
-
* масть на границе зумов. Но тема вольна ставить дорогам цвет, который годится ЛИНИИ и не годится
|
|
1293
|
-
* ПОЛОСЕ: у ледяной палитры дороги золотые (#ffd86b), и полотно по ним выходит песчаным полем
|
|
1294
|
-
* вместо асфальта.
|
|
1295
|
-
*
|
|
1296
|
-
* Такие палитры и получают этот набор — ровно то, чем полотно было до перехода на тему.
|
|
1297
|
-
* Накладывается он как обычная правка темы, по id слоя (`paint[id]` темы v2). Имена — формата v2
|
|
1298
|
-
* (osmgl 0.20): у слоя `surface` цвет асфальта — `osmgl-surface-color`, борт —
|
|
1299
|
-
* `osmgl-surface-side-color`; прежние `color`/`sideColor` движок ещё понимает, но с предупреждением.
|
|
1300
|
-
*/
|
|
1301
|
-
declare const ROADBED_FIXED_PAINT: Record<string, Record<string, unknown>>;
|
|
1302
|
-
/**
|
|
1303
|
-
* Полотно поверх базового стиля.
|
|
1304
|
-
*
|
|
1305
|
-
* Слои встают СРАЗУ ЗА линиями дорог, а не в конец списка: выше них идут подписи, щиты и всё, что
|
|
1306
|
-
* дорога несёт на себе, — уехав в конец, асфальт накрыл бы их собой.
|
|
1307
|
-
*/
|
|
1308
|
-
/**
|
|
1309
|
-
* `mode` — начальный режим полотна. Он входит в стиль сразу, а не ставится фильтрами после
|
|
1310
|
-
* создания карты: смена фильтров до первой загрузки заставляла движок начинать заново, и карта
|
|
1311
|
-
* с `lift=1` в адресе полминуты стояла пустой (прод, 28.09.2026).
|
|
1312
|
-
*/
|
|
1313
|
-
/** Источники поверхностей земли: всё это под полотном, а не поверх него. */
|
|
1314
|
-
declare const GROUND_LAYERS: string[];
|
|
1315
|
-
/** Выше этого земля под полотном не поднимается: асфальт — 0.09 (метры; см. отметку полотна). */
|
|
1316
|
-
declare const GROUND_TOP = 0.05;
|
|
1317
|
-
/**
|
|
1318
|
-
* ЗЕМЛЯ — ПОД ПОЛОТНОМ, И ПОРЯДОК ВНУТРИ НЕЁ ТОТ ЖЕ.
|
|
1319
|
-
*
|
|
1320
|
-
* Городской стиль поднимает зелень и площадки ради рельефа: парковка 0.19 м, лес 0.175, парк 0.15.
|
|
1321
|
-
* Полотно дорог лежит на 0.15 (тогда и тротуар полотна — на 0.12), и всё, что выше, НАКРЫВАЛО асфальт там, где контур
|
|
1322
|
-
* парковки или леса заходит на проезжую часть, а парк стоял с асфальтом вровень и мерцал (телефон,
|
|
1323
|
-
* дорога вдоль парковки, 08.10.2026). Детальный асфальт (`ld-lift.mjs`, верх 0.25) при этом выше
|
|
1324
|
-
* обоих — его не трогаем.
|
|
1325
|
-
*
|
|
1326
|
-
* Чинится здесь, а не в базовом стиле: конфликт есть только там, где есть полотно, а базовый стиль
|
|
1327
|
-
* живёт и без него (и его эталоны у всех платформ). Поверхности земли сжимаются ОДНИМ множителем так,
|
|
1328
|
-
* чтобы самая высокая встала на `GROUND_TOP`: порядок и доли между ними сохраняются, рельеф остаётся
|
|
1329
|
-
* читаемым. Вместе с отметкой масштабируются основание и спуск фаски — иначе фаска выйдет выше верха.
|
|
1330
|
-
*/
|
|
1331
|
-
declare function groundUnderBed(layers: StyleLayerSpec[]): StyleLayerSpec[];
|
|
1332
|
-
declare function roadbedStyle(base: StyleSpec, url?: string, mode?: RoadbedMode): StyleSpec;
|
|
1333
|
-
/**
|
|
1334
|
-
* Слои полотна в этом стиле — по ИСТОЧНИКУ.
|
|
1335
|
-
*
|
|
1336
|
-
* Их несколько (асфальт, тоннель), и список имён, набранный руками,
|
|
1337
|
-
* устаревал бы с каждой правкой раскладки.
|
|
1338
|
-
*/
|
|
1339
|
-
declare function roadbedLayerIds(style: StyleSpec): string[];
|
|
1340
|
-
|
|
1341
|
-
/**
|
|
1342
|
-
* Откуда берутся данные.
|
|
1343
|
-
*
|
|
1344
|
-
* `base` — адрес сайта без хвостового `/`. ПУСТАЯ база даёт адреса ОТНОСИТЕЛЬНЫЕ — так их пишет
|
|
1345
|
-
* веб-карта: в проде их разводит шлюз, в разработке — прокси Vite, и сборка не привязана к домену.
|
|
1346
|
-
* Приложению без шлюза база нужна полная. Ключ добавляется КО ВСЕМ адресам данных: шлюз проверяет
|
|
1347
|
-
* его и у тайлов, и у шрифтов, и у пробок.
|
|
1348
|
-
*/
|
|
1349
|
-
declare class Endpoints {
|
|
1350
|
-
readonly base: string;
|
|
1351
|
-
readonly key: string;
|
|
1352
|
-
constructor(base?: string, key?: string | null);
|
|
1353
|
-
/** Есть ли вообще сеть. Пусто — у приложения (у веба база пустая, но шлюз есть всегда). */
|
|
1354
|
-
get online(): boolean;
|
|
1355
|
-
/**
|
|
1356
|
-
* Наш ли это сервер — тот, которому положен ключ портала: происхождение адреса (схема, хост, порт)
|
|
1357
|
-
* равно происхождению базы. Только целиком: по началу строки (`startsWith(base)`) ключ уходил и
|
|
1358
|
-
* `https://navi.gram.tj.evil.com/…`, и `https://navi.gram.tjx/…`. Путь не сравнивается: ключ
|
|
1359
|
-
* проверяет шлюз, а он у происхождения один.
|
|
1360
|
-
*/
|
|
1361
|
-
owns(url: string): boolean;
|
|
1362
|
-
url(path: string): string;
|
|
1363
|
-
get apiKey(): string | null;
|
|
1364
|
-
get tiles(): string;
|
|
1365
|
-
get fonts(): string;
|
|
1366
|
-
get roadbed(): string;
|
|
1367
|
-
get traffic(): string;
|
|
1368
|
-
get raster(): string;
|
|
1369
|
-
get model3d(): string;
|
|
1370
|
-
/** База сервиса моделей: ключ он подставляет во все свои адреса сам. */
|
|
1371
|
-
get objects3d(): string;
|
|
1372
|
-
}
|
|
1373
|
-
/**
|
|
1374
|
-
* ПРОИСХОЖДЕНИЕ АДРЕСА — `схема://хост:порт` в нижнем регистре, порт по умолчанию числом (http 80,
|
|
1375
|
-
* https 443); не абсолютный адрес или сомнительный — `null`. По нему и только по нему решается, кому
|
|
1376
|
-
* уходит ключ портала (`Endpoints.owns`).
|
|
1377
|
-
*
|
|
1378
|
-
* Разбор свой, а не `new URL()`: тот же текст стоит в портах (`originOf` у Kotlin, Swift и натива),
|
|
1379
|
-
* и ответ обязан совпадать до символа. Поэтому всё, что разные разборщики понимают по-разному,
|
|
1380
|
-
* отбрасывается, а не угадывается: данные пользователя (`user@host` — у браузера хост ПОСЛЕ `@`),
|
|
1381
|
-
* обратная косая в имени хоста (у браузера это путь, у HTTP-клиента — как повезёт), `%`, пробелы,
|
|
1382
|
-
* не-ASCII. Чужому серверу при этом ключ точно не уйдёт, своему — только по чистому адресу.
|
|
1383
|
-
*/
|
|
1384
|
-
declare function originOf(url: string): string | null;
|
|
1385
|
-
/** Адреса относительно сайта — то, что пишет веб-карта (и стиль, опубликованный с сайта). */
|
|
1386
|
-
declare const SITE_ENDPOINTS: Endpoints;
|
|
1387
|
-
/**
|
|
1388
|
-
* Дополнительные наборы тайлов.
|
|
1389
|
-
*
|
|
1390
|
-
* У основного потолок z14, поэтому мелкие зумы берутся из мирового набора, а планы этажей и точки
|
|
1391
|
-
* живут отдельно: они пересобираются на порядки чаще и по другому расписанию.
|
|
1392
|
-
*
|
|
1393
|
-
* Потолок точек 16, а не 14: точке хватало и четырнадцатого — её рисуют значком постоянного
|
|
1394
|
-
* размера, — а зебра перехода лежит НА асфальте, и её полоса в 0,6 м на z14 схлопывается в единицу
|
|
1395
|
-
* тайла (см. deploy/rebuild-navpoints-tiles.sh). Выше шестнадцатого движок растягивает сам.
|
|
1396
|
-
*/
|
|
1397
|
-
declare function naviGramSources(at: Endpoints): Record<string, {
|
|
1398
|
-
url: string;
|
|
1399
|
-
minzoom: number;
|
|
1400
|
-
maxzoom: number;
|
|
1401
|
-
}>;
|
|
1402
|
-
/**
|
|
1403
|
-
* Стиль карты: «объёмный город» + полотно дорог + пробки + растровая подложка (обе выключены).
|
|
1404
|
-
*
|
|
1405
|
-
* Основа — `CITY_STYLE`: рельеф (зелень приподнята, вода утоплена) со скруглёнными углами и
|
|
1406
|
-
* сплошными материалами. Он собран ПОД ТЕНИ, и включать их надо вместе с ним: без теней его уровни
|
|
1407
|
-
* и фаски видно только на просвет.
|
|
1408
|
-
*
|
|
1409
|
-
* ПОЛОТНО ДОРОГ добавляется ПЕРВЫМ, до пробок и подложки: оно гасит линейные слои проезжей части
|
|
1410
|
-
* выше своего зума, и делать это надо по исходному стилю, пока к нему не примешались чужие слои с
|
|
1411
|
-
* похожими именами.
|
|
1412
|
-
*
|
|
1413
|
-
* `mode` — начальный режим полотна. Он входит в стиль сразу, а не ставится фильтрами после
|
|
1414
|
-
* создания карты: смена фильтров до первой загрузки заставляла движок начинать заново, и карта с
|
|
1415
|
-
* `lift=1` в адресе полминуты стояла пустой (прод, 28.09.2026).
|
|
1416
|
-
*/
|
|
1417
|
-
declare function cityStyle(at?: Endpoints, mode?: RoadbedMode): StyleSpec;
|
|
1418
|
-
/**
|
|
1419
|
-
* ТОТ ЖЕ НАБОР СЛОЁВ, НО НА РЕЛЬЕФЕ.
|
|
1420
|
-
*
|
|
1421
|
-
* Рельеф у движка — это не покраска, а другой способ рисовать землю: плоские слои уезжают в
|
|
1422
|
-
* текстуру тайла, и она натягивается на сетку высот. Поэтому это отдельный стиль, а не тумблер: в
|
|
1423
|
-
* нём нет объёмных поверхностей (они рисуются мимо драпировки и остались бы лежать на нуле) и есть
|
|
1424
|
-
* источник высот. Пробки и растровая подложка добавляются к нему так же, как к обычному.
|
|
1425
|
-
*
|
|
1426
|
-
* ПОЛОТНА ДОРОГ ЗДЕСЬ НЕТ по той же причине, по которой нет прочих объёмных поверхностей: оно
|
|
1427
|
-
* рисуется мимо драпировки и осталось бы лежать на нуле, пока земля под ним уходит в гору.
|
|
1428
|
-
*/
|
|
1429
|
-
declare function terrainStyle(at?: Endpoints): StyleSpec;
|
|
1430
|
-
/**
|
|
1431
|
-
* Адреса тайлов стиля от корня сервера (`/tileserver/...`) — через `Endpoints.url`, как у остальных
|
|
1432
|
-
* источников NaviGram (пара — `withAbsoluteTiles` у Swift, там правка была раньше). В браузере такой
|
|
1433
|
-
* адрес достраивает сама страница, на телефоне его нужно достроить явно: иначе у стиля рельефа источник
|
|
1434
|
-
* высот не грузился вовсе, и решётка рельефа оставалась плоской — на Android рельефная тема была плоской
|
|
1435
|
-
* картой с голубой пеленой тона низин (15.10.2026). У веба база пустая и ключа нет — адреса те же.
|
|
1436
|
-
*/
|
|
1437
|
-
declare function withAbsoluteTiles(style: StyleSpec, at: Endpoints): StyleSpec;
|
|
1438
|
-
/**
|
|
1439
|
-
* Светлая и тёмная темы карты.
|
|
1440
|
-
*
|
|
1441
|
-
* Светлая — «объёмная» палитра GramMaps: у неё дома и земля разведены по тону так, что тень от дома
|
|
1442
|
-
* ложится на видимую поверхность, а не на такое же пятно. Тёмная — ночная, с той же геометрией.
|
|
1443
|
-
*/
|
|
1444
|
-
declare const THEME_LIGHT: string;
|
|
1445
|
-
declare const THEME_DARK: string;
|
|
1446
|
-
/**
|
|
1447
|
-
* Те же две темы, но СТЕКЛО В ТОН СТЕНЕ.
|
|
1448
|
-
*
|
|
1449
|
-
* Синее остекление задаёт фасаду второй цвет, и на плотной застройке город читается сеткой окон, а
|
|
1450
|
-
* не домами. Кому нужен спокойный фасад, тот включает эту пару: рельеф дому остаётся от откосов и
|
|
1451
|
-
* теней, а контраст уходит. Темы выведены движком из основных, поэтому палитра у них общая.
|
|
1452
|
-
*/
|
|
1453
|
-
declare const THEME_LIGHT_TONE: string;
|
|
1454
|
-
declare const THEME_DARK_TONE: string;
|
|
1455
|
-
/**
|
|
1456
|
-
* Ледяная — ОТДЕЛЬНЫЙ стиль, а не вариант светлой: у неё своя палитра целиком (земля, дороги, вода,
|
|
1457
|
-
* зелень) и нет окон вовсе, поэтому и «окна в тон» ей нечего менять.
|
|
1458
|
-
*/
|
|
1459
|
-
declare const THEME_ICE: string;
|
|
1460
|
-
/** Та же ледяная, но со стеклом в тон стене — как `3d-tone` у светлой. */
|
|
1461
|
-
declare const THEME_ICE_TONE: string;
|
|
1462
|
-
/**
|
|
1463
|
-
* АТЛАС — пара от дизайнера, перенесённая из его стиля MapLibre. Стоит особняком: в автоматическую
|
|
1464
|
-
* смену по солнцу не встаёт, палитру человек выбирает сам.
|
|
1465
|
-
*/
|
|
1466
|
-
declare const THEME_ATLAS_DAY: string;
|
|
1467
|
-
declare const THEME_ATLAS_NIGHT: string;
|
|
1468
|
-
/** Атласная ли это палитра — обе её половины. */
|
|
1469
|
-
declare function isAtlasTheme(theme: string): boolean;
|
|
1470
|
-
/** Ледяная с учётом тумблера «окна в тон». */
|
|
1471
|
-
declare function iceThemeFor(inTone: boolean): string;
|
|
1472
|
-
/** Ледяной ли это стиль — оба его варианта. */
|
|
1473
|
-
declare function isIceTheme(theme: string): boolean;
|
|
1474
|
-
/** Тема с учётом тумблера «окна в тон»: пара выбирается по светлоте, вариант — по признаку. */
|
|
1475
|
-
declare function themeFor(dark: boolean, inTone: boolean): string;
|
|
1476
|
-
declare function themeV2(name: string): ThemeSpecV2 | null;
|
|
1477
|
-
/**
|
|
1478
|
-
* ТЕМА, ДОВЕДЁННАЯ ДЛЯ ПОЛОТНА.
|
|
1479
|
-
*
|
|
1480
|
-
* Асфальт красится цветом дорог темы, и почти везде это то, что нужно. У ледяной палитры — нет:
|
|
1481
|
-
* дороги в ней золотые, и полоса асфальта шириной в улицу читается песком, а не покрытием. Поэтому
|
|
1482
|
-
* ей возвращается прежний набор цветов полотна, обычной правкой темы по id слоя. Остальным темам —
|
|
1483
|
-
* их имя как есть.
|
|
1484
|
-
*
|
|
1485
|
-
* Правка живёт здесь, а не в самой теме движка: слоёв полотна нет в базовом стиле, они появляются
|
|
1486
|
-
* только у карты (`roadbedStyle`), и тема движка про них знать не должна.
|
|
1487
|
-
*/
|
|
1488
|
-
declare function themeForRoadbed(theme: string): string | ThemeSpecV2;
|
|
1489
|
-
/**
|
|
1490
|
-
* Довести ПОСЧИТАННУЮ тему до варианта «окна в тон».
|
|
1491
|
-
*
|
|
1492
|
-
* Тема на момент суток получается смешиванием светлой с тёмной, готового варианта у неё нет.
|
|
1493
|
-
* Правится ровно то же, что и у самих вариантов: цвет стекла берётся у стены, свечение гасится.
|
|
1494
|
-
*/
|
|
1495
|
-
declare function withWindowsInTone(theme: ThemeSpecV2, dark: number): ThemeSpecV2;
|
|
1496
|
-
/**
|
|
1497
|
-
* Тёмная ли тема карты — по её СОБСТВЕННОМУ фону, а не по имени.
|
|
1498
|
-
*
|
|
1499
|
-
* За этим идёт тема интерфейса: белая панель поверх ночной карты слепит. Имена сравнивать
|
|
1500
|
-
* бесполезно — тем два десятка, и «светлая» среди них не одна.
|
|
1501
|
-
*/
|
|
1502
|
-
declare function isDarkTheme(theme: string, style: StyleSpec): boolean;
|
|
1503
|
-
/**
|
|
1504
|
-
* Детальные 3D-объекты: раскладка слоя размещений.
|
|
1505
|
-
*
|
|
1506
|
-
* С z17 — НА ЗУМ ПОЗЖЕ объёмных домов (30.09.2026, ради нагрузки на телефон). Дома встают объёмом
|
|
1507
|
-
* с z16, поэтому одинокого дворца посреди плоской карты не бывает: ниже порога модели нет, и на её
|
|
1508
|
-
* месте стоит обычный дом. И СРАЗУ В ПОЛНОЙ ГЕОМЕТРИИ: упрощённый lod1 у порога показа читается
|
|
1509
|
-
* как брак. БЮДЖЕТ оставлен движку: кадр сажает КОЛИЧЕСТВО объектов, а не их подробность.
|
|
1510
|
-
*/
|
|
1511
|
-
declare const OBJECTS3D_LAYOUT: {
|
|
1512
|
-
readonly minZoom: 17;
|
|
1513
|
-
readonly fullDetail: true;
|
|
1514
|
-
};
|
|
1515
|
-
/** Источник размещений 3D-объектов и слой моделей в стиле карты. */
|
|
1516
|
-
declare const OBJECTS3D_SOURCE = "model3d";
|
|
1517
|
-
declare const OBJECTS3D_LAYER_ID = "objects3d";
|
|
1518
|
-
/**
|
|
1519
|
-
* Источник размещений: набор `model3d` собран ровно на z14 (`-Z14 -z14`), поэтому нижний зум равен
|
|
1520
|
-
* верхнему — с `minzoom: 0` на каждый покрывающий тайл ниже четырнадцатого уходил бы запрос-404.
|
|
1521
|
-
* Сервис моделей — свойство источника: номера файлов в тайле имеют смысл только у него.
|
|
1522
|
-
*/
|
|
1523
|
-
declare function objects3dSource(at?: Endpoints): SourceSpec;
|
|
1524
|
-
/**
|
|
1525
|
-
* СТИЛЬ С ДЕТАЛЬНЫМИ 3D-ОБЪЕКТАМИ — слоем стиля, а не опцией карты (04.10.2026).
|
|
1526
|
-
*
|
|
1527
|
-
* Пока объекты задавались опцией `objects3d`, в редакторе стилей их не было вовсе: превью не рисовало
|
|
1528
|
-
* ни светофоров, ни фонарей, а спрятать или настроить их из стиля было нечем. Слой тот же, что прежде
|
|
1529
|
-
* собирала из опции карта (`objects3d` на источнике `model3d`), и с той же раскладкой
|
|
1530
|
-
* (`OBJECTS3D_LAYOUT`: порог z17 — порогом слоя, сразу полная геометрия), поэтому облик карты не
|
|
1531
|
-
* меняется; опция у карты, если она ещё задана, при таком слое как слой не действует.
|
|
1532
|
-
*
|
|
1533
|
-
* Ставится последним: модели рисует свой проход вместе со зданиями, и место в списке на облик не
|
|
1534
|
-
* влияет, а в дереве редактора слой оказывается сверху, где его и ищут.
|
|
1535
|
-
*/
|
|
1536
|
-
declare function withObjects3D(style: StyleSpec, at?: Endpoints): StyleSpec;
|
|
1537
|
-
/**
|
|
1538
|
-
* Высота, на которой лежат объекты приложения поверх карты, метры.
|
|
1539
|
-
*
|
|
1540
|
-
* Земля в этом стиле не совсем плоская: дороги подняты на 0,18…0,225 м, лес — на 0,175, и всё это
|
|
1541
|
-
* рисуется в проходе объёма с записью глубины. Маршрут на нулевой высоте оказался бы ПОД дорогой,
|
|
1542
|
-
* по которой идёт. Четверть метра кладёт его поверх всей этой геометрии и ниже любого дома.
|
|
1543
|
-
*/
|
|
1544
|
-
declare const OVERLAY_ALTITUDE = 0.28;
|
|
1545
|
-
|
|
1546
|
-
/**
|
|
1547
|
-
* ДЕТАЛЬНЫЕ ДОРОГИ И ЛЕНТА ПОЛОС В СТИЛЕ КАРТЫ — чистая часть: разбор ответов сервиса
|
|
1548
|
-
* (`/tiles/ldroads/index`, `/tiles/ldroads/style.json`), вставка их слоёв в стиль карты, слои и
|
|
1549
|
-
* данные ленты по полосам. Пара у портов — `LdRoads.kt` / `LdRoads.swift` (те же имена).
|
|
1550
|
-
*
|
|
1551
|
-
* ★ СЦЕНА ЗДЕСЬ НЕ СТРОИТСЯ. Веб-карта (`src/WebMap/src/map/ld-roads.ts`) собирает полотно улиц
|
|
1552
|
-
* редактора у себя (воркер стенда) и режет асфальт своим протоколом — это остаётся у неё. Здесь —
|
|
1553
|
-
* контракт для приложений (`docs/map-v2/LD-MOBILE.md`): слои — `style.json` сервиса (формат osmgl
|
|
1554
|
-
* v1, id `ld-*`, источник `ld-roads`), данные — векторные тайлы z14–16, асфальт — уже обрезанный
|
|
1555
|
-
* под скрытыми дорогами (`/tiles/ldroads/roadbed/…` вместо URL источника `roadbed`). Сеть — у
|
|
1556
|
-
* приложения.
|
|
1557
|
-
*
|
|
1558
|
-
* ★ СЛОИ ВСТАЮТ СРАЗУ ЗА ПОЛОТНОМ КАРТЫ (за `roadbed`; до 23.10.2026 — за его краской `roadarrow`,
|
|
1559
|
-
* которой больше нет) — под дома, подписи и пробки; лента полос — сразу за ними (на их асфальте).
|
|
1560
|
-
* Разметка карты — ТОЛЬКО их (`ld-mark-*`): краски полотна в стиле нет (`ROADMARK_LAYER_IDS`).
|
|
1561
|
-
*
|
|
1562
|
-
* Слои ленты, `withLaneRibbon`, поле высот `heightsFromScene` и данные источника (`RibbonGeoJson`)
|
|
1563
|
-
* перенесены из `src/WebMap/src/map/lane-ribbon.ts` без изменения поведения.
|
|
1564
|
-
*/
|
|
1565
|
-
|
|
1566
|
-
type Layer = Record<string, unknown>;
|
|
1567
|
-
/** Источник детальных дорог. Слои `style.json` сервиса ссылаются на него. */
|
|
1568
|
-
declare const LD_SOURCE = "ld-roads";
|
|
1569
|
-
/** Приставка id слоёв детальных дорог. */
|
|
1570
|
-
declare const LD_LAYER_PREFIX = "ld-";
|
|
1571
|
-
/**
|
|
1572
|
-
* Слой полотна карты, за которым встают детальные дороги: асфальт (`roadbed`) — последний слой полотна.
|
|
1573
|
-
* Был `roadarrow` (стрелки краски полотна); краски в стиле больше нет. `style.json` сервиса по-прежнему
|
|
1574
|
-
* подсказывает `insertAfter: roadarrow` — клиенты это поле не читают.
|
|
1575
|
-
*/
|
|
1576
|
-
declare const LD_AFTER = "roadbed";
|
|
1577
|
-
declare const LD_INDEX_PATH = "/tiles/ldroads/index";
|
|
1578
|
-
declare const ldStylePath: (version: string) => string;
|
|
1579
|
-
declare const ldRoadbedPath: (version: string) => string;
|
|
1580
|
-
/**
|
|
1581
|
-
* Адрес из ответа сервиса (как `Endpoints.resolve` портов): относительный (`/tiles/…`) — от базы и с
|
|
1582
|
-
* ключом, абсолютный на нашу базу — с ключом, если его там нет, чужой — как есть.
|
|
1583
|
-
*
|
|
1584
|
-
* «На нашу базу» — то же происхождение (`Endpoints.owns`), а не то же начало строки: по началу ключ
|
|
1585
|
-
* получал `https://navi.gram.tj.evil.com/…`. `//хост/…` — адрес БЕЗ схемы на чужой хост, а не путь
|
|
1586
|
-
* от корня: базу к нему не приставляем и ключ не даём.
|
|
1587
|
-
*/
|
|
1588
|
-
declare function resolveUrl(at: Endpoints, pathOrUrl: string): string;
|
|
1589
|
-
/** Индекс участков: версия и сколько их. Пустой набор — детальных дорог нет нигде. */
|
|
1590
|
-
interface LdIndex {
|
|
1591
|
-
version: string;
|
|
1592
|
-
areas: number;
|
|
1593
|
-
}
|
|
1594
|
-
/** Индекс (текст или разобранный JSON) → версия и число участков; не наш ответ — `null`. */
|
|
1595
|
-
declare function parseLdIndex(json: string | unknown): LdIndex | null;
|
|
1596
|
-
/** Слои детальных дорог от сервиса: источник (адрес уже полный) и слои. */
|
|
1597
|
-
interface LdStyle {
|
|
1598
|
-
version: string;
|
|
1599
|
-
tiles: string;
|
|
1600
|
-
minzoom: number;
|
|
1601
|
-
maxzoom: number;
|
|
1602
|
-
layers: Layer[];
|
|
1603
|
-
}
|
|
1604
|
-
/** Приставка слоёв разметки детальных дорог. */
|
|
1605
|
-
declare const LD_MARK_PREFIX = "ld-mark-";
|
|
1606
|
-
/**
|
|
1607
|
-
* ★ РАЗМЕТКА ДЕТАЛЬНЫХ ДОРОГ ПРОЯВЛЯЕТСЯ, А НЕ ВКЛЮЧАЕТСЯ (25.10.2026). У слоёв разметки сервиса (`ld-mark-*`: стрелки
|
|
1608
|
-
* полос, зебры, стоп-линии, линии полос) `minzoom` 17.5, а камера ведения у манёвра проходит этот зум туда и обратно
|
|
1609
|
-
* (`NAV_VIEW.ZOOM_MIN…ZOOM_MAX` 15.6–18.8): вся разметка, и прежде всего белые стрелки полос у перекрёстка, появлялась и
|
|
1610
|
-
* пропадала РАЗОМ за кадр — жалоба владельца «на поворотах мигают белые стрелки». Замер натива `ld_arrow_flicker_test`
|
|
1611
|
-
* (зум 17.5 ± 0.25, Худжанд): пикселей стрелок 136 → 0 за один кадр. Теперь ниже порога на `LD_MARK_FADE_ZOOM` уровня
|
|
1612
|
-
* разметка проявляется по зуму (`opacity` 0 → своя). Слой со своей прозрачностью-выражением не трогается.
|
|
1613
|
-
*/
|
|
1614
|
-
declare const LD_MARK_FADE_ZOOM = 0.35;
|
|
1615
|
-
/**
|
|
1616
|
-
* `style.json` сервиса → слои. Адрес тайлов приводится к полному (`resolveUrl`: база и ключ). Нет
|
|
1617
|
-
* адреса или слоёв — `null`: стиль карты не трогаем.
|
|
1618
|
-
*/
|
|
1619
|
-
declare function parseLdStyle(json: string | unknown, at: Endpoints): LdStyle | null;
|
|
1620
|
-
/** Источник детальных дорог для стиля. */
|
|
1621
|
-
declare function ldSource(ld: LdStyle): {
|
|
1622
|
-
url: string;
|
|
1623
|
-
minzoom: number;
|
|
1624
|
-
maxzoom: number;
|
|
1625
|
-
};
|
|
1626
|
-
/**
|
|
1627
|
-
* Стиль карты с детальными дорогами: их источник и слои за полотном (`roadbed`), асфальт — с
|
|
1628
|
-
* обрезанного адреса (`roadbedUrl`). Стиль без полотна (рельеф) не трогается — возвращается тот же
|
|
1629
|
-
* объект: детальным улицам там не на чем лежать.
|
|
1630
|
-
*/
|
|
1631
|
-
declare function withLdRoads(style: StyleSpec, ld: LdStyle, roadbedUrl?: string | null): StyleSpec;
|
|
1632
|
-
/** Id слоёв детальных дорог в стиле — для выключателей. */
|
|
1633
|
-
declare function ldLayerIds(style: StyleSpec): string[];
|
|
1634
|
-
/** Источник ленты (GeoJSON приложения). */
|
|
1635
|
-
declare const LANE_SOURCE = "lane-ribbon";
|
|
1636
|
-
/**
|
|
1637
|
-
* С этого зума линия маршрута уступает ленте. Ниже полоса (3–3.5 м) уже тоньше линии маршрута
|
|
1638
|
-
* (9 px ≈ 4 м на z18, 8 м на z17) — лента читалась бы бледной ниткой; у Baidu полосный вид тоже
|
|
1639
|
-
* включается только на крупных зумах (`docs/map-v2/ROUTE-LINE-BAIDU.md`).
|
|
1640
|
-
*/
|
|
1641
|
-
declare const LANE_MIN_ZOOM = 17.5;
|
|
1642
|
-
/**
|
|
1643
|
-
* ПЛОЩАДЬ ЛЕНТЫ ОБЪЕКТАМИ КАРТЫ (`RibbonAreas`): цвет, прозрачность и порядок каждого вида. Порядок —
|
|
1644
|
-
* между невыбранными вариантами (10) и линией маршрута (20), над границей прохода (`ROUTE_OVERLAY_Z`, 15):
|
|
1645
|
-
* лента закрывает невыбранные варианты, линия, пройденная часть и стрелки поворотов лежат на ней.
|
|
1646
|
-
*/
|
|
1647
|
-
declare const RIBBON_AREA_PAINT: Record<'band' | 'allowed' | 'band-passed' | 'allowed-passed', {
|
|
1648
|
-
color: string;
|
|
1649
|
-
opacity: number;
|
|
1650
|
-
zIndex: number;
|
|
1651
|
-
}>;
|
|
1652
|
-
/** Данные ленты в ведении перезаливаются не чаще (мс) — ≤ 10 Гц, и только пока машина на ленте. */
|
|
1653
|
-
declare const LANE_PROGRESS_MIN_MS = 100;
|
|
1654
|
-
/** Пустой набор GeoJSON. */
|
|
1655
|
-
declare const EMPTY_GEOJSON: {
|
|
1656
|
-
type: string;
|
|
1657
|
-
features: unknown[];
|
|
1658
|
-
};
|
|
1659
|
-
/**
|
|
1660
|
-
* Слои ленты — как у Baidu в полосном виде: одна полупрозрачная синяя лента без контуров, белые
|
|
1661
|
-
* шевроны по ней и бледная лента разрешённых полос; в ведении пройденная часть — серая.
|
|
1662
|
-
*/
|
|
1663
|
-
declare function laneRibbonLayers(): Record<string, unknown>[];
|
|
1664
|
-
/** Слой шевронов ленты — его гасят вместе со стрелками линии маршрута (`routeLineOptions(…, arrows)`). */
|
|
1665
|
-
declare const LANE_RIBBON_CHEVRON_LAYER = "lane-ribbon-chevron";
|
|
1666
|
-
/** Id слоёв ленты — для отладки и выключателей. */
|
|
1667
|
-
declare const laneRibbonLayerIds: () => string[];
|
|
1668
|
-
/**
|
|
1669
|
-
* Стиль карты с источником и слоями ленты — сразу за слоями детальных дорог (иначе за `roadbed`).
|
|
1670
|
-
* Повторный вызов слои заменяет, а не дублирует.
|
|
1671
|
-
*
|
|
1672
|
-
* `buffer: 0` — без поля за краем тайла: каждый тайл получает ровно свой квадрат (как этого добиться
|
|
1673
|
-
* при выдвиге вершин разреза движком — `tileParts` в `lane-ribbon-render.ts`). Зум тайлов — 18
|
|
1674
|
-
* (`maxzoom` по умолчанию), на нём и считается та резка: менять его без неё нельзя.
|
|
1675
|
-
*/
|
|
1676
|
-
declare function withLaneRibbon(style: StyleSpec, data?: unknown): StyleSpec;
|
|
1677
|
-
/** Фича сцены детальных дорог (GeoJSON) — то, из чего берутся отметки полотна. */
|
|
1678
|
-
interface SceneFeature {
|
|
1679
|
-
geometry: {
|
|
1680
|
-
type: string;
|
|
1681
|
-
coordinates: unknown;
|
|
1682
|
-
};
|
|
1683
|
-
properties: Record<string, unknown>;
|
|
1684
|
-
}
|
|
1685
|
-
/**
|
|
1686
|
-
* Поле высот по фичам сцены детальных дорог: отрезки с отметками (`liftPath`/`lift`), по уровням
|
|
1687
|
-
* (`layer`). Точка дальше 22 м от полотна своего уровня — этаж × 8 м (`fallbackHeight`).
|
|
1688
|
-
*/
|
|
1689
|
-
declare function heightsFromScene(features: SceneFeature[]): HeightAt;
|
|
1690
|
-
/**
|
|
1691
|
-
* ВЫСОТА ТРАССЫ — ОДНА НА ВСЕХ: линия маршрута, лента по полосам, стрелки поворотов (и машина
|
|
1692
|
-
* навигатора) лежат на одной поверхности — `OVERLAY_ALTITUDE` над отметкой полотна НА МЕТРЕ ТРАССЫ.
|
|
1693
|
-
* Отметка по метру — `routeLiftAt`; лента берёт её по станциям своих точек (`RibbonGeoJson`), объекты
|
|
1694
|
-
* карты — по точке, приведённой к метру трассы (`routeLiftField`). Своей модели высоты ни у ленты, ни у
|
|
1695
|
-
* стрелок нет: на каждом метре трассы они на той же отметке, что и линия, — на земле на асфальте, на
|
|
1696
|
-
* эстакаде на настиле, на подходе по одному склону.
|
|
1697
|
-
*/
|
|
1698
|
-
declare const ROUTE_TOP = 0.28;
|
|
1699
|
-
/** Отметка полотна на метре трассы, метры (0 — земля). */
|
|
1700
|
-
type RouteLiftAt = (m: number) => number;
|
|
1701
|
-
/** Отметка полотна в точке `(lng, lat)`, метры (`MapObjectOptions.liftAt` объектов карты). */
|
|
1702
|
-
type LiftField = (lng: number, lat: number) => number;
|
|
1703
|
-
/** Профиль отметок: метры трассы точек куска и их отметки. */
|
|
1704
|
-
interface LiftProfile {
|
|
1705
|
-
stations: number[];
|
|
1706
|
-
heights: number[];
|
|
1707
|
-
}
|
|
1708
|
-
/**
|
|
1709
|
-
* Профили отметок трассы — по ОСНОВНОЙ ленте (`band`: рекомендуемые полосы идут по самой трассе),
|
|
1710
|
-
* отметки — поле высот `heights` по уровням точек. Основной ленты нет — по всем площадным кускам.
|
|
1711
|
-
*/
|
|
1712
|
-
declare function routeLiftProfiles(ribbon: Ribbon, heights?: HeightAt): LiftProfile[];
|
|
1713
|
-
/**
|
|
1714
|
-
* Отметка полотна на метре `m` трассы по профилям: внутри куска — линейно между станциями; кусков на
|
|
1715
|
-
* метре несколько — наибольшая; вне ленты — 0 (не на ленте — земля). Та же функция, что высота машины
|
|
1716
|
-
* навигатора (`navCarLiftAt`).
|
|
1717
|
-
*/
|
|
1718
|
-
declare function routeLiftAt(ribbon: Ribbon, heights?: HeightAt): RouteLiftAt;
|
|
1719
|
-
/** Дальше этого от трассы точка объекта к ней не приводится (не на трассе — земля), метры. */
|
|
1720
|
-
declare const ROUTE_LIFT_REACH_M = 25;
|
|
1721
|
-
/**
|
|
1722
|
-
* Отметка трассы в точке для объектов карты (`liftAt` линии, пройденной части, стрелок поворотов):
|
|
1723
|
-
* точка приводится к ближайшему метру трассы `geometry` (мерой `routeLine`, той же, что станции ленты)
|
|
1724
|
-
* и берёт `liftAt` этого метра. Дальше `ROUTE_LIFT_REACH_M` от трассы — 0. `null` — у трассы нет
|
|
1725
|
-
* отметок (лента без эстакад и без ленты вовсе: все на земле).
|
|
1726
|
-
*/
|
|
1727
|
-
declare function routeLiftField(geometry: LonLat[], liftAt: RouteLiftAt): LiftField | null;
|
|
1728
|
-
interface RibbonGeoJsonFeature {
|
|
1729
|
-
type: 'Feature';
|
|
1730
|
-
id: number;
|
|
1731
|
-
geometry: {
|
|
1732
|
-
type: 'Polygon';
|
|
1733
|
-
coordinates: LonLat[][];
|
|
1734
|
-
} | {
|
|
1735
|
-
type: 'LineString';
|
|
1736
|
-
coordinates: LonLat[];
|
|
1737
|
-
};
|
|
1738
|
-
properties: Record<string, unknown>;
|
|
1739
|
-
}
|
|
1740
|
-
interface RibbonGeoJsonData {
|
|
1741
|
-
type: 'FeatureCollection';
|
|
1742
|
-
features: RibbonGeoJsonFeature[];
|
|
1743
|
-
}
|
|
1744
|
-
/**
|
|
1745
|
-
* ДАННЫЕ ИСТОЧНИКА ЛЕНТЫ (то, что веб-карта заливала в `lane-ribbon` из `LaneRibbonLayer.push`):
|
|
1746
|
-
* `kind`, `width` (метры), `layer` (наибольший уровень), высота (`lift`/`liftPath`). Площадные
|
|
1747
|
-
* фичи — многоугольниками без нахлёста (`minusMask`) и разрезанными по сетке тайлов z18
|
|
1748
|
-
* (`tileParts`), в ведении — с серой пройденной частью (`areaSpans`); шевроны — осью, целиком
|
|
1749
|
-
* позади машины не рисуются.
|
|
1750
|
-
*
|
|
1751
|
-
* ★ У ПОРТОВ (`RibbonGeoJson` в `LdRoads.kt`) резки по тайлам и вычитания нет — там отдаются целые
|
|
1752
|
-
* контуры: шов полупрозрачной ленты по границе тайла — особенность веб-движка (`SURFACE_CUT_BLEED`).
|
|
1753
|
-
*
|
|
1754
|
-
* Кэширует всё, что не зависит от точки машины: на шаге ведения пересчитывается только кусок с ней.
|
|
1755
|
-
*/
|
|
1756
|
-
declare class RibbonGeoJson {
|
|
1757
|
-
readonly ribbon: Ribbon;
|
|
1758
|
-
private heights;
|
|
1759
|
-
private options;
|
|
1760
|
-
/** Отметки точек каждой фичи ленты (по полю высот). */
|
|
1761
|
-
private hs;
|
|
1762
|
-
/** Свойства высоты кусков без точки машины: `номер:вид:от:до`. */
|
|
1763
|
-
private props;
|
|
1764
|
-
/** Многоугольники кусков без точки машины (после вычитания ленты и резки по тайлам). */
|
|
1765
|
-
private shapes;
|
|
1766
|
-
private frames;
|
|
1767
|
-
private masks;
|
|
1768
|
-
/**
|
|
1769
|
-
* `options.areas: false` — без площадных фич: площадь ленты рисуется объектами карты единым
|
|
1770
|
-
* полигоном (`RibbonAreas`, `lane-ribbon-mesh.ts`), в источнике остаются только шевроны.
|
|
1771
|
-
* `options.lift` — высота полотна под точкой (`routeSurfaceField`): отметки точек берутся по ней, а
|
|
1772
|
-
* не по метру трассы — тем же, чем стоят на полотне лента, линия и стрелки.
|
|
1773
|
-
*/
|
|
1774
|
-
constructor(ribbon: Ribbon, heights?: HeightAt, options?: {
|
|
1775
|
-
areas?: boolean;
|
|
1776
|
-
lift?: LiftField | null;
|
|
1777
|
-
});
|
|
1778
|
-
/** Другая высота полотна под точкой (догрузилась сетка детальных дорог). */
|
|
1779
|
-
setLift(lift: LiftField | null): void;
|
|
1780
|
-
/** Другое поле высот (сцена детальных дорог перестроена) — отметки берутся заново. */
|
|
1781
|
-
setHeights(heights: HeightAt): void;
|
|
1782
|
-
/** Отметка трассы по метру (`routeLiftAt`) — общая с линией маршрута и стрелками. */
|
|
1783
|
-
private routeLift;
|
|
1784
|
-
/**
|
|
1785
|
-
* Отметки точек фичи — ОТМЕТКА ТРАССЫ на станциях точек (`routeLiftAt`): лента лежит на той же
|
|
1786
|
-
* высоте, что линия маршрута и стрелки на том же метре. Фича без станций — по полю высот.
|
|
1787
|
-
*/
|
|
1788
|
-
private heightsOf;
|
|
1789
|
-
/**
|
|
1790
|
-
* Маска фичи `i`: контуры площадных фич главнее её — основная лента главнее разрешённых полос,
|
|
1791
|
-
* среди равных — раньше построенная.
|
|
1792
|
-
*/
|
|
1793
|
-
private maskFor;
|
|
1794
|
-
private shapesOf;
|
|
1795
|
-
/** GeoJSON на метре ведения (`null` — ведения нет, лента целиком цветная). */
|
|
1796
|
-
at(progress: number | null): RibbonGeoJsonData;
|
|
1797
|
-
}
|
|
1798
|
-
/** Данные источника ленты без ведения (лента целиком цветная). */
|
|
1799
|
-
declare function ribbonGeoJson(ribbon: Ribbon, heightAt?: HeightAt): RibbonGeoJsonData;
|
|
1800
|
-
|
|
1801
|
-
/**
|
|
1802
|
-
* ЛЕНТА ПО ПОЛОСАМ — ЕДИНЫМ ПОЛИГОНОМ, НА ВЫСОТЕ НАСТОЯЩЕГО ПОЛОТНА.
|
|
1803
|
-
*
|
|
1804
|
-
* Разбор и источники — `docs/lane-ribbon-mesh.md`. Коротко:
|
|
1805
|
-
*
|
|
1806
|
-
* ★ ОДИН ПИКСЕЛЬ — ОДНА КРАСКА. Лента полупрозрачная, и любой нахлёст двух кусков даёт пятно
|
|
1807
|
-
* двойной яркости. Поэтому краска не накладывается кусками, а строится НЕПЕРЕКРЫВАЮЩАЯСЯ геометрия:
|
|
1808
|
-
* куски одного вида и одной полосы метров (`CHUNK_M`) сливаются объединением (polygon-clipping —
|
|
1809
|
-
* Мартинес–Руэда в изводе Майка Фогеля), а из каждой группы вычитается всё, что нарисовано раньше
|
|
1810
|
-
* (основная лента главнее разрешённых полос, ближняя к началу трассы — дальней). Итог — набор
|
|
1811
|
-
* многоугольников, которые касаются, но не перекрываются; каждый — один объект карты, earcut
|
|
1812
|
-
* разбивает его на треугольники один раз. Сумма площадей треугольников равна площади ленты — это и
|
|
1813
|
-
* проверяют тесты (`tests/navigram-lane-ribbon-mesh.test.mjs`).
|
|
1814
|
-
*
|
|
1815
|
-
* ★ ВЕДЕНИЕ. Группа, которую режет точка машины, делится на пройденную (серую) и оставшуюся части
|
|
1816
|
-
* пересечением и разностью с пройденными кусками своей группы — две маленькие операции на шаг ведения;
|
|
1817
|
-
* остальные группы берутся из кэша как есть.
|
|
1818
|
-
*
|
|
1819
|
-
* ★ ВЫСОТА — ОТ НАСТОЯЩЕГО ПОЛОТНА ПОД ТОЧКОЙ (`meshSurface`, `routeSurfaceField`): каждая вершина
|
|
1820
|
-
* ленты, линии маршрута и стрелок поворотов берёт отметку верха сетки детальных дорог ровно под собой
|
|
1821
|
-
* (треугольник с нормалью вверх; из нескольких — ближайший к ожидаемой отметке трассы, чтобы дорога
|
|
1822
|
-
* под эстакадой не взлетела на настил). Там, где сетка загружена, но под точкой её нет, — земля;
|
|
1823
|
-
* где сетки нет вовсе — отметка трассы (`routeLiftField`).
|
|
1824
|
-
*/
|
|
1825
|
-
|
|
1826
|
-
/** Кусок ленты для отрисовки: вид, многоугольник (`[outer, ...holes]`, кольца `[lon, lat]`, замкнуты). */
|
|
1827
|
-
interface RibbonArea {
|
|
1828
|
-
/** Постоянный ключ: тот же кусок на следующем шаге ведения — тот же объект карты. */
|
|
1829
|
-
key: string;
|
|
1830
|
-
kind: RibbonKind;
|
|
1831
|
-
polygon: LonLat[][];
|
|
1832
|
-
/**
|
|
1833
|
-
* Какие кромки сглаживать (`RouteArea.feather`): `feather[r][i]` — кромка `i → i+1` кольца `r`
|
|
1834
|
-
* (кольца — без замыкающей точки). Сглаживается только край ленты; шов с соседним куском ленты —
|
|
1835
|
-
* нет: там с обеих сторон краска, и полоса сглаживания легла бы на соседа второй краской.
|
|
1836
|
-
*/
|
|
1837
|
-
feather: boolean[][];
|
|
1838
|
-
}
|
|
1839
|
-
type Box = [number, number, number, number];
|
|
1840
|
-
/**
|
|
1841
|
-
* ПРОЙДЕННОЕ РАСТВОРЯЕТСЯ, А НЕ ОБРЫВАЕТСЯ (22.10.2026, просьба владельца «синий свет плавно уменьшался позади
|
|
1842
|
-
* машины»). Раньше группу с точкой машины резало пересечением: синяя кончалась ровно под машиной, а дальше шла
|
|
1843
|
-
* серая — ступенька на всю ширину ленты, и перекладывалась она шагом ведения (≤ 10 Гц). Теперь (`passAt`) группы
|
|
1844
|
-
* не режутся: у группы рядом с машиной рисуются ЦЕЛИКОМ и синяя, и серая, а какая где видна, решает шейдер по
|
|
1845
|
-
* метру трассы в вершине (`stationsFor`) и метру машины в униформе (`MapObject.along`): синяя гаснет на
|
|
1846
|
-
* `RIBBON_PASS_FADE_M` позади машины, серая на том же отрезке проявляется. Метр машины — каждым кадром, без
|
|
1847
|
-
* пересборки; набор объектов меняется, только когда группа входит в окно у машины или выходит из него.
|
|
1848
|
-
*/
|
|
1849
|
-
/** Длина растворения синей ленты позади машины, метры. */
|
|
1850
|
-
declare const RIBBON_PASS_FADE_M = 20;
|
|
1851
|
-
/**
|
|
1852
|
-
* Запас окна у машины, метры: группа рисуется обеими красками, пока задевает [машина − длина − запас,
|
|
1853
|
-
* машина + запас]. На границе окна та краска, что уходит, уже погашена шейдером, — смена набора не видна.
|
|
1854
|
-
*/
|
|
1855
|
-
declare const RIBBON_PASS_MARGIN_M = 5;
|
|
1856
|
-
/** Кусок ленты в ведении с растворением позади машины (`RibbonAreas.passAt`). */
|
|
1857
|
-
interface PassArea extends RibbonArea {
|
|
1858
|
-
/** Номер группы — для метров в точках (`RibbonAreas.stationsFor`). */
|
|
1859
|
-
group: number;
|
|
1860
|
-
/**
|
|
1861
|
-
* Сторона растворения (`AlongFade.dir`): +1 — синяя, гаснет позади машины; −1 — серая, проявляется позади
|
|
1862
|
-
* машины; 0 — у группы нет метров трассы, рисуется как есть.
|
|
1863
|
-
*/
|
|
1864
|
-
dir: 1 | -1 | 0;
|
|
1865
|
-
}
|
|
1866
|
-
/**
|
|
1867
|
-
* ПЛОЩАДЬ ЛЕНТЫ БЕЗ НАХЛЁСТОВ — по группам «категория × полоса метров `CHUNK_M`».
|
|
1868
|
-
*
|
|
1869
|
-
* Строится один раз на ленту; на шаге ведения пересчитывается только группа с точкой машины.
|
|
1870
|
-
*/
|
|
1871
|
-
declare class RibbonAreas {
|
|
1872
|
-
readonly ribbon: Ribbon;
|
|
1873
|
-
private readonly chunkM;
|
|
1874
|
-
/** Группы по порядку отрисовки: сначала основная лента, потом разрешённые полосы; внутри — по метрам. */
|
|
1875
|
-
private groups;
|
|
1876
|
-
private frames;
|
|
1877
|
-
private built;
|
|
1878
|
-
constructor(ribbon: Ribbon, chunkM?: number);
|
|
1879
|
-
private frame;
|
|
1880
|
-
/** Куски каждой фичи по полосам метров (без ведения) — сырьё групп. */
|
|
1881
|
-
private build;
|
|
1882
|
-
/** Лежит ли точка (единицы z18) внутри ленты — какой-нибудь группы. */
|
|
1883
|
-
private inside;
|
|
1884
|
-
/** Кромки многоугольника на краю ленты: с одной стороны лента, с другой — нет. */
|
|
1885
|
-
private featherOf;
|
|
1886
|
-
private featherCache;
|
|
1887
|
-
/** Метры трассы группы `[lo, hi]` (`null` — у её фич метров нет). */
|
|
1888
|
-
private spans;
|
|
1889
|
-
private spanOf;
|
|
1890
|
-
/** Что рисует группа на метре `progress`: `b` — синяя, `x` — синяя и серая (окно у машины), `g` — серая. */
|
|
1891
|
-
private passMode;
|
|
1892
|
-
/**
|
|
1893
|
-
* Отпечаток набора кусков `passAt` на метре `progress`: тот же — объекты те же, менять нужно только метр машины
|
|
1894
|
-
* у растворения (`MapObject.along`).
|
|
1895
|
-
*/
|
|
1896
|
-
passKey(progress: number | null, fadeM?: number): string;
|
|
1897
|
-
/**
|
|
1898
|
-
* Куски ленты в ведении С РАСТВОРЕНИЕМ ПОЗАДИ МАШИНЫ: группы целиком (без резки по точке машины), синие —
|
|
1899
|
-
* впереди и в окне у машины, серые — в окне и позади. Ключи — те же, что у целых групп `at` (`:whole`,
|
|
1900
|
-
* `:passed`): группа, перешедшая из одного состояния в другое, остаётся тем же объектом карты.
|
|
1901
|
-
*/
|
|
1902
|
-
passAt(progress: number | null, fadeM?: number): PassArea[];
|
|
1903
|
-
/**
|
|
1904
|
-
* МЕТР ТРАССЫ В ТОЧКАХ КУСКА группы `group` (кольца — как у `polygon`, в том числе после дробления кромок
|
|
1905
|
-
* `fadeRibbonArea`): метр ближайшей точки оси её фич (`stations` по точкам оси, между ними — линейно). Ищется
|
|
1906
|
-
* только по своей группе — трасса, вернувшаяся к тому же месту, чужого метра не даст. `null` — метров нет.
|
|
1907
|
-
*/
|
|
1908
|
-
stationsFor(group: number, polygon: LonLat[][]): number[][] | null;
|
|
1909
|
-
/** Куски ленты на метре ведения `progress` (`null` — ведения нет, лента целиком цветная). */
|
|
1910
|
-
at(progress: number | null): RibbonArea[];
|
|
1911
|
-
}
|
|
1912
|
-
/**
|
|
1913
|
-
* ШЕВРОНЫ ЛЕНТЫ — линиями маршрута (`Polyline`, та же программа и тот же рисунок стрелок, что у
|
|
1914
|
-
* линии), размер — в метрах на земле (как прежний слой: 6 px на z18 и вдвое на каждый зум).
|
|
1915
|
-
*/
|
|
1916
|
-
declare const RIBBON_CHEVRON: {
|
|
1917
|
-
readonly COLOR: "rgba(255,255,255,0)";
|
|
1918
|
-
readonly ARROW_COLOR: "rgba(255,255,255,0.95)";
|
|
1919
|
-
readonly WIDTH_M: 2.75;
|
|
1920
|
-
readonly PERIOD_M: 18.3;
|
|
1921
|
-
readonly SIZE_M: 1.37;
|
|
1922
|
-
/** Над лентой (16–17), под линией маршрута (20). */
|
|
1923
|
-
readonly Z: 18;
|
|
1924
|
-
};
|
|
1925
|
-
/** Шеврон ленты: постоянный ключ и ось. */
|
|
1926
|
-
interface RibbonChevron {
|
|
1927
|
-
key: string;
|
|
1928
|
-
line: LonLat[];
|
|
1929
|
-
}
|
|
1930
|
-
/** Шеврон в ведении с растворением: метры его концов (`null` — метров нет). */
|
|
1931
|
-
interface PassChevron extends RibbonChevron {
|
|
1932
|
-
stations: [number, number] | null;
|
|
1933
|
-
}
|
|
1934
|
-
/**
|
|
1935
|
-
* Шевроны в ведении С РАСТВОРЕНИЕМ (`passAt`): шеврон гаснет позади машины вместе с синей лентой (`MapObject.along`
|
|
1936
|
-
* с началом `chevronRunBase`), поэтому снимается, только когда целиком ушёл за окно растворения, — не на машине.
|
|
1937
|
-
*/
|
|
1938
|
-
declare function ribbonPassChevrons(ribbon: Ribbon, progress: number | null, fadeM?: number): PassChevron[];
|
|
1939
|
-
/**
|
|
1940
|
-
* Метр трассы первой точки куска шеврона (`fadeRibbonLine` режет шеврон на куски): по доле пути вдоль оси шеврона
|
|
1941
|
-
* до ближайшей к ней точки, между метрами его концов. `null` — у шеврона метров нет.
|
|
1942
|
-
*/
|
|
1943
|
-
declare function chevronRunBase(chevron: PassChevron, run: LonLat[]): number | null;
|
|
1944
|
-
/** Шевроны на метре ведения: целиком позади машины не рисуются, тот, на котором машина, — целый. */
|
|
1945
|
-
declare function ribbonChevrons(ribbon: Ribbon, progress: number | null): RibbonChevron[];
|
|
1946
|
-
/** Сетка детальных дорог (тайл `ldtiles` после `decodeMeshTile`): точки — абсолютные `[lon, lat]`. */
|
|
1947
|
-
interface SurfaceMesh {
|
|
1948
|
-
lonlat: ArrayLike<number>;
|
|
1949
|
-
z: ArrayLike<number>;
|
|
1950
|
-
normals: ArrayLike<number>;
|
|
1951
|
-
indices: ArrayLike<number>;
|
|
1952
|
-
}
|
|
1953
|
-
/**
|
|
1954
|
-
* Отметка верха полотна в точке: число — отметка сетки под точкой (метры, как в тайле сетки, без
|
|
1955
|
-
* подъёма отрисовки); `null` — сетка здесь загружена, но дороги из неё под точкой нет (земля);
|
|
1956
|
-
* `undefined` — сетки здесь нет вовсе (судить не по чему). `hint` — ожидаемая отметка: из нескольких
|
|
1957
|
-
* поверхностей одна над другой берётся ближайшая к ней.
|
|
1958
|
-
*/
|
|
1959
|
-
type SurfaceAt = (lng: number, lat: number, hint?: number) => number | null | undefined;
|
|
1960
|
-
/**
|
|
1961
|
-
* Высота полотна по сеткам детальных дорог. `boxes` — рамки загруженных тайлов сетки `[w, s, e, n]`:
|
|
1962
|
-
* внутри них «нет треугольника» значит «земля», снаружи — «не знаю». Учитываются только грани, глядящие
|
|
1963
|
-
* вверх (верх плиты, а не борт и не низ).
|
|
1964
|
-
*/
|
|
1965
|
-
declare function meshSurface(meshes: readonly SurfaceMesh[], boxes: readonly Box[]): SurfaceAt;
|
|
1966
|
-
/**
|
|
1967
|
-
* ВЫСОТА ПОЛОТНА ДЛЯ ВСЕГО МАРШРУТА (лента, линия, пройденная часть, стрелки поворотов — одна функция
|
|
1968
|
-
* на всех): отметка сетки под точкой (`surface`, ближайшая к отметке трассы), в зоне загруженной сетки
|
|
1969
|
-
* без дороги под точкой — земля (0), вне сетки — отметка трассы (`route`, по метру трассы).
|
|
1970
|
-
*/
|
|
1971
|
-
declare function routeSurfaceField(surface: SurfaceAt | null, route: LiftField | null): LiftField | null;
|
|
1972
|
-
|
|
1973
|
-
/**
|
|
1974
|
-
* ЛЕНТА ПО ПОЛОСАМ И ЛИНИЯ МАРШРУТА СМЕНЯЮТ ДРУГ ДРУГА ПЕРЕХОДОМ, А НЕ СТУПЕНЬКОЙ (22.10.2026, просьба
|
|
1975
|
-
* владельца «чтобы синий свет плавно уменьшался» и «лента пропадает, а линия не появляется»).
|
|
1976
|
-
*
|
|
1977
|
-
* Раньше смена «линия ↔ лента» была ступенькой, а по зуму — ещё и дырой:
|
|
1978
|
-
* · объекты ленты гасли с `LANE_MIN_ZOOM` (`minZoom`), а линия уступала ей куски на ЛЮБОМ зуме — камера
|
|
1979
|
-
* ведения на прямой держит z17.4, и на всём покрытии плана не было ни ленты, ни линии;
|
|
1980
|
-
* · ВДОЛЬ ТРАССЫ на краю покрытия широкая синяя лента обрывалась, а с того же метра шла тонкая линия.
|
|
1981
|
-
*
|
|
1982
|
-
* Теперь:
|
|
1983
|
-
* · ОДНО СОСТОЯНИЕ ВИДИМОСТИ (`RibbonBlend`): цель «лента / линия» по зуму с гистерезисом
|
|
1984
|
-
* (`LANE_ON_ZOOM` / `LANE_OFF_ZOOM`) и значение, которое идёт к цели за `RIBBON_BLEND_MS` по гладкой
|
|
1985
|
-
* кривой. Лента рисуется с множителем `ribbonAlpha`, а куски линии ПОД лентой — с `lineAlpha`
|
|
1986
|
-
* (`MapObject.fade`): линия гаснет, пока лента проявляется, и обратно. Куски линии вне ленты не
|
|
1987
|
-
* трогаются никогда. Карта будит кадры, только пока переход идёт (`animating`);
|
|
1988
|
-
* · у концов ленты, где её сменяет линия (не у начала и конца трассы), лента на `RIBBON_FADE_M` гаснет
|
|
1989
|
-
* гладкой ступенькой (прозрачность в вершине, `RouteArea.alphas`), а линия на том же отрезке лежит
|
|
1990
|
-
* поверх всегда (`ribbonLineHidden` — куски под лентой без зон растворения).
|
|
1991
|
-
*
|
|
1992
|
-
* Метры здесь — мера трассы ленты (`measureRoute`, та же, что у `Ribbon.hidden`).
|
|
1993
|
-
*/
|
|
1994
|
-
|
|
1995
|
-
/** Длина растворения ленты у конца, где её сменяет линия маршрута, метры. */
|
|
1996
|
-
declare const RIBBON_FADE_M = 20;
|
|
1997
|
-
/** Длительность перехода «линия ↔ лента», мс. */
|
|
1998
|
-
declare const RIBBON_BLEND_MS = 300;
|
|
1999
|
-
/**
|
|
2000
|
-
* НАИБОЛЬШИЙ ШАГ ПЕРЕХОДА ЗА ОДИН КАДР, мс часов (24.10.2026). Переход меряется НАРИСОВАННЫМИ кадрами: долгий кадр
|
|
2001
|
-
* (включение ленты на пороге зума давало на Redmi 110–357 мс) двигает его не больше, чем на этот шаг, а не проматывает
|
|
2002
|
-
* целиком — иначе весь кросс-фейд и съезд машины в полосу (`laneCarPose`, доля `ribbonAlpha`) приходились на один кадр.
|
|
2003
|
-
* 34 мс — два периода развёртки при 60 Гц и один при 30 Гц: на ровных кадрах переход идёт как раньше, за 300 мс; хуже
|
|
2004
|
-
* 30 кадров/с — растягивается, но не меньше чем на 9 кадров (шаг доли ≤ 0.11, шаг съезда ≤ 0.17 сдвига полосы).
|
|
2005
|
-
*/
|
|
2006
|
-
declare const RIBBON_BLEND_STEP_MAX_MS = 34;
|
|
2007
|
-
/** С этого зума лента включается (если была выключена). */
|
|
2008
|
-
declare const LANE_ON_ZOOM: number;
|
|
2009
|
-
/** Ниже этого зума лента выключается (если была включена). Между порогами состояние держится. */
|
|
2010
|
-
declare const LANE_OFF_ZOOM: number;
|
|
2011
|
-
/** Кромка в зоне растворения дробится не реже (метры): прозрачность GPU смешивает между вершинами. */
|
|
2012
|
-
declare const RIBBON_FADE_STEP_M = 2;
|
|
2013
|
-
/**
|
|
2014
|
-
* Дальше от оси трассы (метры) точка к концу ленты не относится: широкая лента разрешённых полос
|
|
2015
|
-
* отходит от оси на 10–15 м, а трасса, вернувшаяся к тому же месту (разворот), — не её конец.
|
|
2016
|
-
*/
|
|
2017
|
-
declare const RIBBON_FADE_REACH_M = 30;
|
|
2018
|
-
/** Растворение концов ленты по трассе: куда и в какую сторону гаснет. */
|
|
2019
|
-
interface RibbonFade {
|
|
2020
|
-
frame: Frame;
|
|
2021
|
-
route: Measured;
|
|
2022
|
-
/** Метр конца ленты и сторона ленты от него: +1 — лента дальше по трассе, −1 — ближе. */
|
|
2023
|
-
ends: {
|
|
2024
|
-
at: number;
|
|
2025
|
-
dir: 1 | -1;
|
|
2026
|
-
}[];
|
|
2027
|
-
fadeM: number;
|
|
2028
|
-
}
|
|
2029
|
-
/**
|
|
2030
|
-
* Концы ленты, которые сменяет линия маршрута, — по кускам `hidden` трассы `geometry`. Нет таких концов
|
|
2031
|
-
* (или `fadeM` = 0) — `null`: лента рисуется как раньше.
|
|
2032
|
-
*/
|
|
2033
|
-
declare function ribbonFade(geometry: LonLat[], hidden: [number, number][], fadeM?: number): RibbonFade | null;
|
|
2034
|
-
/** Прозрачность ленты в точке `[lon, lat]`. */
|
|
2035
|
-
declare function ribbonFadeAlpha(fade: RibbonFade, p: LonLat): number;
|
|
2036
|
-
/**
|
|
2037
|
-
* Кусок ленты (`RibbonArea`: кольца без замыкающей точки и отметки кромок) — с прозрачностью в
|
|
2038
|
-
* вершинах. Кромки рядом с концами дробятся через `RIBBON_FADE_STEP_M` (отметка кромки — та же у
|
|
2039
|
-
* всех её частей): полигон ленты после объединения держит вершины только на изломах и стыках
|
|
2040
|
-
* кусков, и без дробления 20 м растворения размазались бы на всю прямую кромку. Кусок, весь
|
|
2041
|
-
* видимый (альфа 1 везде), возвращается как есть и без `alphas`.
|
|
2042
|
-
*/
|
|
2043
|
-
declare function fadeRibbonArea(fade: RibbonFade | null, polygon: LonLat[][], feather: boolean[][]): {
|
|
2044
|
-
polygon: LonLat[][];
|
|
2045
|
-
feather: boolean[][];
|
|
2046
|
-
alphas: number[][] | null;
|
|
2047
|
-
};
|
|
2048
|
-
/**
|
|
2049
|
-
* Шевроны ленты (линия по оси полосы) — без частей в зоне растворения: белые стрелки над
|
|
2050
|
-
* погасшей лентой висели бы в воздухе. Части с прозрачностью ниже 0.999 выбрасываются, кромка
|
|
2051
|
-
* режется с шагом `RIBBON_FADE_STEP_M`. Ничего не осталось — пусто.
|
|
2052
|
-
*/
|
|
2053
|
-
declare function fadeRibbonLine(fade: RibbonFade | null, line: LonLat[]): LonLat[][];
|
|
2054
|
-
/**
|
|
2055
|
-
* Куски трассы, что линия маршрута уступает ленте, — без зон растворения: у конца, где ленту
|
|
2056
|
-
* сменяет линия, линия заходит под гаснущую ленту на `fadeM` (и лежит поверх неё). У начала и конца
|
|
2057
|
-
* трассы куски не укорачиваются. Кусок, короче двух зон, пропадает: линия там цела.
|
|
2058
|
-
*/
|
|
2059
|
-
declare function ribbonLineHidden(geometry: LonLat[], hidden: [number, number][], fadeM?: number): [number, number][];
|
|
2060
|
-
/**
|
|
2061
|
-
* Дополнение кусков до трассы `[0, length]`: где линия рисуется ВНЕ кусков. Куски — по возрастанию и не
|
|
2062
|
-
* пересекаются (`ribbonLineHidden`, `mergeRanges`).
|
|
2063
|
-
*/
|
|
2064
|
-
declare function outsideRanges(ranges: [number, number][], length: number): [number, number][];
|
|
2065
|
-
/**
|
|
2066
|
-
* СОСТОЯНИЕ ВИДИМОСТИ «ЛЕНТА ↔ ЛИНИЯ» — одно на карту. `update` — каждым кадром (зум кадра, часы кадра,
|
|
2067
|
-
* есть ли лента); возвращает `true`, пока переход идёт (карте нужен следующий кадр).
|
|
2068
|
-
*
|
|
2069
|
-
* · цель: лента есть и зум не ниже `LANE_ON_ZOOM` — включить; ниже `LANE_OFF_ZOOM` — выключить; между —
|
|
2070
|
-
* как была (гистерезис: камера, стоящая на пороге, не мигает);
|
|
2071
|
-
* · значение `t` идёт к цели с постоянной скоростью `1 / RIBBON_BLEND_MS`, но за кадр — не больше
|
|
2072
|
-
* `RIBBON_BLEND_STEP_MAX_MS` часов: долгий кадр переход не проматывает; видимая доля — `smoothstep(t)`;
|
|
2073
|
-
* · ленту сняли (новая трасса, план кончился) — цель «линия»: прежняя лента ГАСНЕТ тем же переходом (её объекты держит
|
|
2074
|
-
* слой, пока `t` не дошло до 0 — `retiring`), а линия новой трассы уже целая;
|
|
2075
|
-
* · первый кадр с лентой (и пропуск кадров дольше секунды, и часы назад) не двигает `t`: переход меряется
|
|
2076
|
-
* только живыми кадрами — лента, пришедшая на крупном зуме, проявляется, а не встаёт сразу.
|
|
2077
|
-
*/
|
|
2078
|
-
declare class RibbonBlend {
|
|
2079
|
-
/** Цель: лента видна. */
|
|
2080
|
-
on: boolean;
|
|
2081
|
-
/** Значение перехода 0…1 (0 — линия, 1 — лента). */
|
|
2082
|
-
t: number;
|
|
2083
|
-
private at;
|
|
2084
|
-
update(zoom: number, nowMs: number, hasRibbon: boolean): boolean;
|
|
2085
|
-
/** Множитель прозрачности ленты. */
|
|
2086
|
-
get ribbonAlpha(): number;
|
|
2087
|
-
/** Множитель прозрачности кусков линии под лентой. */
|
|
2088
|
-
get lineAlpha(): number;
|
|
2089
|
-
/** Переход ещё идёт. */
|
|
2090
|
-
get animating(): boolean;
|
|
2091
|
-
}
|
|
2092
|
-
|
|
2093
|
-
/**
|
|
2094
|
-
* ЛИНИЯ МАРШРУТА КАК У BAIDU — параметры движка (`docs/map-v2/ROUTE-LINE-BAIDU.md` монорепозитория):
|
|
2095
|
-
* широкая насыщенная синяя линия (пробки — раскраской по участкам) с белой обводкой и белыми
|
|
2096
|
-
* шевронами направления через равный шаг; невыбранные варианты — бледные и ниже; в ведении
|
|
2097
|
-
* пройденная часть — серая линия ПОВЕРХ целой синей (`passedPieces`, `route-progress.ts`). Лента по
|
|
2098
|
-
* полосам (`ld-roads.ts`) — того же синего: она продолжает линию.
|
|
2099
|
-
*
|
|
2100
|
-
* Перенесено из веб-карты (`src/WebMap/src/map/overlays.ts`) без изменения поведения: константы,
|
|
2101
|
-
* `trafficSegments`, `spansForPiece`, опции `Polyline`. Пара у портов — `RouteLineStyle.kt` /
|
|
2102
|
-
* `RouteLineStyle.swift`; сверка — общие фикстуры `kmp/fixtures/route-line/*.json`
|
|
2103
|
-
* (`node scripts/export-route-line-fixture.mjs`).
|
|
2104
|
-
*/
|
|
2105
|
-
|
|
2106
|
-
/** Константы линии маршрута (цвета — CSS, ширины и шаги — пиксели). */
|
|
2107
|
-
declare const ROUTE_LINE: {
|
|
2108
|
-
/** Выбранный вариант. */
|
|
2109
|
-
readonly BLUE: "#2f6bff";
|
|
2110
|
-
/**
|
|
2111
|
-
* Линия 10 px и белая обводка по 2 px с каждой стороны — всего 14, как у `navigator-main`
|
|
2112
|
-
* (`RouteMap.kt`: `LineLayer` 10.dp поверх обводки 14.dp, концы и стыки скруглены). Было 9 + 2.
|
|
2113
|
-
*/
|
|
2114
|
-
readonly WIDTH: 10;
|
|
2115
|
-
readonly STROKE_WIDTH: 2;
|
|
2116
|
-
readonly STROKE_COLOR: "#ffffff";
|
|
2117
|
-
/** Шевроны: шаг и размах в пикселях (движок вписывает стрелку в 0.72 полуширины линии). */
|
|
2118
|
-
readonly ARROW_COLOR: "#ffffff";
|
|
2119
|
-
readonly ARROW_PERIOD: 56;
|
|
2120
|
-
readonly ARROW_SIZE: 7;
|
|
2121
|
-
/** Насколько видна трасса там, где она за домом. */
|
|
2122
|
-
readonly GHOST: 0.7;
|
|
2123
|
-
/** Невыбранные варианты: бледные, уже и ниже. */
|
|
2124
|
-
readonly DIM: "#98a2b3";
|
|
2125
|
-
readonly DIM_WIDTH: 6;
|
|
2126
|
-
readonly DIM_STROKE_COLOR: "#e6e9ef";
|
|
2127
|
-
readonly DIM_OPACITY: 0.75;
|
|
2128
|
-
/**
|
|
2129
|
-
* Линия в режиме навигатора — НЕПРОЗРАЧНАЯ, как и в обычном (решение пользователя 07.10.2026:
|
|
2130
|
-
* сквозь полупрозрачную трассу просвечивали подложка, полотно и разметка, а цвета пробок
|
|
2131
|
-
* мутнели). Константа осталась — её читают веб-карта и приложение. Полупрозрачными остались
|
|
2132
|
-
* намеренно только «призрак» за домами (`GHOST`) и невыбранные варианты (`DIM_OPACITY`).
|
|
2133
|
-
*/
|
|
2134
|
-
readonly NAV_OPACITY: 1;
|
|
2135
|
-
/**
|
|
2136
|
-
* Пройденная часть в ведении — та же ширина и белая обводка, без шевронов. Цвет — `TRAVELED_COLOR`
|
|
2137
|
-
* навигатора `navigator-main` (`map/RouteMap.kt`): тот же синий, но выцветший, — линия читается как
|
|
2138
|
-
* «уже позади», а не как другая дорога.
|
|
2139
|
-
*/
|
|
2140
|
-
readonly PASSED: "#6e7a8a";
|
|
2141
|
-
/** Порядок среди объектов: невыбранные, выбранный, пройденная поверх выбранного. */
|
|
2142
|
-
readonly Z_ACTIVE: 20;
|
|
2143
|
-
readonly Z_DIM: 10;
|
|
2144
|
-
readonly Z_PASSED: 21;
|
|
2145
|
-
/** Чаще этого пройденная часть не перекладывается (мс): ≤ 10 Гц, метка машины прячет разницу. */
|
|
2146
|
-
readonly PROGRESS_MIN_MS: 100;
|
|
2147
|
-
/** Точки маршрута: старт (A), финиш (B), промежуточные. */
|
|
2148
|
-
readonly POINT_START: "#12a150";
|
|
2149
|
-
readonly POINT_FINISH: "#e5484d";
|
|
2150
|
-
readonly POINT_VIA: "#f5a524";
|
|
2151
|
-
};
|
|
2152
|
-
declare const ROUTE_BLUE: "#2f6bff";
|
|
2153
|
-
declare const ROUTE_NAV_OPACITY: 1;
|
|
2154
|
-
declare const ROUTE_PASSED: "#6e7a8a";
|
|
2155
|
-
declare const ROUTE_POINT_COLORS: {
|
|
2156
|
-
readonly start: "#12a150";
|
|
2157
|
-
readonly finish: "#e5484d";
|
|
2158
|
-
readonly via: "#f5a524";
|
|
2159
|
-
};
|
|
2160
|
-
/** Участок пробок: с точки `at` трассы — фактор скорости `factor` (как `trafficSpans` ответа `/route`). */
|
|
2161
|
-
interface TrafficSpan {
|
|
2162
|
-
at: number;
|
|
2163
|
-
factor: number;
|
|
2164
|
-
}
|
|
2165
|
-
/**
|
|
2166
|
-
* ЦВЕТА ПРОБОК НА ЛИНИИ МАРШРУТА — как у навигатора `navigator-main` (`map/RouteMap.kt`,
|
|
2167
|
-
* `trafficColor`; уровни — `congestionLevel` в `routing/RouterTraffic.kt`): уровень загруженности —
|
|
2168
|
-
* сколько порогов фактора (`LEVELS`: 1.15, 1.5, 2.3, 3.3) участок перешагнул; 0 — зелёный, 1 — жёлтый,
|
|
2169
|
-
* 2 — оранжевый, 3 и 4 — красный. Фактора нет (не число, не больше нуля) — синий линии: «данных нет»
|
|
2170
|
-
* не выдаём за «свободно».
|
|
2171
|
-
*
|
|
2172
|
-
* Свои цвета, а не ступени слоя пробок (`traffic.ts`): тот повторяет серверный растр и рисует улицы
|
|
2173
|
-
* города, а этот красит одну линию поверх них — ему нужен контраст с картой и с самим слоем.
|
|
2174
|
-
*/
|
|
2175
|
-
declare const ROUTE_TRAFFIC: {
|
|
2176
|
-
readonly LEVELS: readonly number[];
|
|
2177
|
-
readonly COLORS: readonly string[];
|
|
2178
|
-
/**
|
|
2179
|
-
* ПЛАВНЫЕ СТЫКИ: ширина перехода цвета — доля длины трассы. У `navigator-main` линия красится
|
|
2180
|
-
* `line-gradient` MapLibre Native по `line-progress`: выражение запекается в полоску текстуры
|
|
2181
|
-
* в 256 текселей с линейной выборкой, и каждая ступень `step` расплывается на один тексель, то есть
|
|
2182
|
-
* на 1/255 длины линии. Берём ту же ширину, но без квантования стыка на сетку текселей и в
|
|
2183
|
-
* разумных пределах (`BLEND_MIN_M`…`BLEND_MAX_M`): на коротком маршруте стык не схлопывается в
|
|
2184
|
-
* ступеньку, на длинном не размазывает квартал.
|
|
2185
|
-
*/
|
|
2186
|
-
readonly BLEND_FRACTION: number;
|
|
2187
|
-
readonly BLEND_MIN_M: 12;
|
|
2188
|
-
readonly BLEND_MAX_M: 150;
|
|
2189
|
-
};
|
|
2190
|
-
/** Ширина плавного стыка пробок, метры, для трассы длиной `lengthM` (`Polyline.segmentBlend`). */
|
|
2191
|
-
declare function routeTrafficBlendM(lengthM: number): number;
|
|
2192
|
-
/** Уровень загруженности 0…4 по фактору (сколько порогов `ROUTE_TRAFFIC.LEVELS` он перешагнул); нет фактора — `null`. */
|
|
2193
|
-
declare function routeTrafficLevel(factor: number): number | null;
|
|
2194
|
-
/** Цвет участка линии маршрута по фактору (`ROUTE_TRAFFIC`); нет фактора — синий линии. */
|
|
2195
|
-
declare function routeTrafficColor(factor: number): string;
|
|
2196
|
-
/**
|
|
2197
|
-
* Отрезки маршрута со своим цветом — из факторов пробок (`routeTrafficColor`).
|
|
2198
|
-
*
|
|
2199
|
-
* Соседние отрезки одного цвета сливаются: сервис даёт границу на каждом ребре графа, а цветов у
|
|
2200
|
-
* нас четыре, и без слияния сотня рёбер превратилась бы в сотню отдельных линий вместо десятка.
|
|
2201
|
-
* Свободная от начала до конца трасса — ОДИН зелёный отрезок, а не синяя линия: как у `navigator-main`,
|
|
2202
|
-
* раз пробки известны, линия их показывает. Пусто — только когда пробок нет вовсе (красит `color`).
|
|
2203
|
-
*/
|
|
2204
|
-
declare function trafficSegments(spans: readonly TrafficSpan[]): PolylineSegment[];
|
|
2205
|
-
/**
|
|
2206
|
-
* Отрезки пробок для куска трассы: `source[k]` — номер отрезка исходной трассы под точкой куска.
|
|
2207
|
-
* Первая точка получает цвет отрезка, на котором кусок начинается, дальше — смены по ходу.
|
|
2208
|
-
*/
|
|
2209
|
-
declare function spansForPiece(spans: readonly TrafficSpan[], source: readonly number[]): TrafficSpan[];
|
|
2210
|
-
/** Кусок линии маршрута: точки и раскраска пробок по номерам ЕГО точек. */
|
|
2211
|
-
interface RouteLinePiece {
|
|
2212
|
-
coords: LonLat[];
|
|
2213
|
-
spans: TrafficSpan[];
|
|
2214
|
-
/** Для каждой точки куска — номер отрезка исходной трассы (по нему — метры концов, `routeLineAlong`). */
|
|
2215
|
-
source: number[];
|
|
2216
|
-
}
|
|
2217
|
-
/**
|
|
2218
|
-
* Куски линии варианта: при пустом `hidden` — трасса целиком; иначе — куски ВНЕ ленты по полосам,
|
|
2219
|
-
* каждый со своей раскраской пробок (номера точек в кусках другие — отрезки пересчитываются).
|
|
2220
|
-
*/
|
|
2221
|
-
declare function routeLinePieces(coords: LonLat[], spans: readonly TrafficSpan[], hidden?: [number, number][]): RouteLinePiece[];
|
|
2222
|
-
/**
|
|
2223
|
-
* ПРОЙДЕННАЯ ЧАСТЬ ЛИНИИ — РАСТВОРЕНИЕМ, КАК У ЛЕНТЫ ПО ПОЛОСАМ (29.10.2026, просьба владельца «чтобы линии
|
|
2224
|
-
* маршрута тоже плавно сокращались, как лента»). Раньше серая линия резалась у машины ступенькой и
|
|
2225
|
-
* перекладывалась не чаще 10 раз в секунду. Теперь куски линии постоянны: синий гаснет позади машины на
|
|
2226
|
-
* `ROUTE_PASS_FADE_M` метров (`dir` +1), серый по тем же кускам проявляется (`dir` −1), а каждым кадром
|
|
2227
|
-
* меняется лишь метр машины в униформе (`MapObject.along`) — без пересборки геометрии.
|
|
2228
|
-
*/
|
|
2229
|
-
declare const ROUTE_PASS_FADE_M = 20;
|
|
2230
|
-
/**
|
|
2231
|
-
* Растворение куска линии позади машины на метре `at` (мера `line` — та же, что у прогресса ведения).
|
|
2232
|
-
* Метры концов куска берутся из `line` по отрезкам `source`, а масштаб «метров на единицу длины» — как
|
|
2233
|
-
* их разность на меркаторную длину куска: шейдер считает метр точки по расстоянию вдоль линии, и без своего
|
|
2234
|
-
* масштаба (длина окружности на широте) на длинном куске серая зона уезжала бы от машины на десятки метров.
|
|
2235
|
-
*/
|
|
2236
|
-
declare function routeLineAlong(line: RouteLine, piece: {
|
|
2237
|
-
coords: LonLat[];
|
|
2238
|
-
source: number[];
|
|
2239
|
-
}, at: number, dir: 1 | -1, length?: number): AlongFade;
|
|
2240
|
-
/** Опции `Polyline` линии маршрута без точек (`coordinates`) и раскраски (`segments`). */
|
|
2241
|
-
type RouteLineOptions = Omit<PolylineOptions, 'coordinates' | 'segments'>;
|
|
2242
|
-
/**
|
|
2243
|
-
* Опции линии варианта. Выбранный — синий, 9 px, белая обводка, шевроны, призрак за домами
|
|
2244
|
-
* (не ярче самой линии), zIndex 20; невыбранный — бледный, 6 px, без шевронов и призрака, zIndex 10.
|
|
2245
|
-
* `opacity` по умолчанию — 1 у выбранного (`ROUTE_NAV_OPACITY` в навигаторе), 0.75 у невыбранного.
|
|
2246
|
-
* `arrows: false` — без шевронов и у выбранного (как `arrows` у `RouteLineStyle.kt`/`RouteLineOverlay`).
|
|
2247
|
-
*/
|
|
2248
|
-
declare function routeLineOptions(active: boolean, opacity?: number, arrows?: boolean): RouteLineOptions;
|
|
2249
|
-
/** Опции пройденной (серой) части: та же ширина и обводка, без шевронов, непрозрачная, над синей. */
|
|
2250
|
-
declare function passedLineOptions(): RouteLineOptions;
|
|
2251
|
-
/** Цвет метки точки маршрута по её номеру (0 — старт, последняя — финиш, между — промежуточные). */
|
|
2252
|
-
declare function routePointColor(i: number, count: number): string;
|
|
2253
|
-
|
|
2254
|
-
/**
|
|
2255
|
-
* СКРУГЛЁННАЯ ТРАССА — одна геометрия на линию маршрута, стрелки поворотов и машину навигатора.
|
|
2256
|
-
*
|
|
2257
|
-
* Зачем. Сервер отдаёт ломаную: на перекрёстке — прямой угол. Стрелка поворота раньше сглаживалась
|
|
2258
|
-
* сама (своим ядром, с радиусом от ширины), а линия под ней оставалась углом — на повороте они
|
|
2259
|
-
* расходились (жалоба пользователя 07.10.2026). Теперь скругляется САМА ТРАССА, одним радиусом
|
|
2260
|
-
* `ROUTE_ROUND.RADIUS_M`, и всё, что лежит на линии, берёт эту же геометрию: линия, пройденная
|
|
2261
|
-
* часть, стрелки (их ось — кусок той же скруглённой трассы, без своего сглаживания), машина.
|
|
2262
|
-
*
|
|
2263
|
-
* Как. Каждый узел с изломом заменяется дугой окружности радиуса `RADIUS_M`, касательной к обоим
|
|
2264
|
-
* звеньям (сопряжение). Касательная длина `R·tg(θ/2)` не больше половины каждого из соседних звеньев
|
|
2265
|
-
* — дуги соседних узлов не наезжают друг на друга; где места мало, радиус уменьшается. Дуга — точками
|
|
2266
|
-
* через `ARC_STEP`, их число чётное: середина дуги — отдельная точка, «якорь» исходного узла.
|
|
2267
|
-
*
|
|
2268
|
-
* МЕТРЫ. Всё, что меряется по исходной трассе (метр ведения, манёвры, участки пробок, куски под
|
|
2269
|
-
* лентой по полосам), переводится на скруглённую через якоря: метр внутри исходного звена `i` —
|
|
2270
|
-
* та же доля пути между якорями `i` и `i+1` (`roundedMetre`). Перевод монотонный и непрерывный,
|
|
2271
|
-
* стыки пробок встают на середины дуг, пройденная часть кончается ровно под машиной.
|
|
2272
|
-
*
|
|
2273
|
-
* Чистые функции; порты — `RouteRound.kt`, `RouteRound.swift`, сверка — `kmp/fixtures/route-line/round.json`.
|
|
2274
|
-
*/
|
|
2275
|
-
|
|
2276
|
-
declare const ROUTE_ROUND: {
|
|
2277
|
-
/** Радиус скругления поворота, метры: около радиуса, по которому машина проходит городской перекрёсток. */
|
|
2278
|
-
readonly RADIUS_M: 15;
|
|
2279
|
-
/** Излом меньше этого (градусы) не скругляется — это уже гладкая кривая. */
|
|
2280
|
-
readonly MIN_TURN_DEG: 2;
|
|
2281
|
-
/** Шаг точек дуги, радианы. */
|
|
2282
|
-
readonly ARC_STEP: number;
|
|
2283
|
-
};
|
|
2284
|
-
/** Скруглённая трасса: точки, якоря исходных узлов и обе меры (исходная и скруглённая). */
|
|
2285
|
-
interface RoundedRoute {
|
|
2286
|
-
coords: LonLat[];
|
|
2287
|
-
/** Номер точки `coords` для каждого исходного узла (для узла с дугой — середина дуги). */
|
|
2288
|
-
anchors: number[];
|
|
2289
|
-
/** Скруглённая трасса с метрами. */
|
|
2290
|
-
line: RouteLine;
|
|
2291
|
-
/** Исходная трасса с метрами. */
|
|
2292
|
-
src: RouteLine;
|
|
2293
|
-
}
|
|
2294
|
-
/** Трасса `coords`, скруглённая радиусом `radiusM` (0 — как есть). */
|
|
2295
|
-
declare function roundRoute(coords: LonLat[], radiusM?: number): RoundedRoute;
|
|
2296
|
-
/** Метр исходной трассы → метр скруглённой (через якоря узлов). */
|
|
2297
|
-
declare function roundedMetre(rr: RoundedRoute, m: number): number;
|
|
2298
|
-
/** Точка скруглённой трассы на метре `m` ИСХОДНОЙ трассы — где рисовать машину. */
|
|
2299
|
-
declare function roundedPoint(rr: RoundedRoute, m: number): LonLat;
|
|
2300
|
-
/** Половина хорды, по которой берётся курс касательной (метры): гладко на дуге из точек через 11°. */
|
|
2301
|
-
declare const ROUTE_POSE_SPAN_M = 3;
|
|
2302
|
-
/**
|
|
2303
|
-
* ПОЗА МАРКЕРА на метре `m` ИСХОДНОЙ трассы: точка скруглённой линии и курс ПО КАСАТЕЛЬНОЙ к ней
|
|
2304
|
-
* в этой точке (хорда ±`ROUTE_POSE_SPAN_M`), градусы по часовой от севера. Маркер на повороте
|
|
2305
|
-
* разворачивается вокруг своей точки по ходу дуги — без «заноса»: курс с упреждением (камеры) у
|
|
2306
|
-
* маркера смотрел бы в выход из поворота ещё до него, и машина ехала бы боком.
|
|
2307
|
-
*/
|
|
2308
|
-
declare function roundedPose(rr: RoundedRoute, m: number): {
|
|
2309
|
-
point: LonLat;
|
|
2310
|
-
bearing: number;
|
|
2311
|
-
};
|
|
2312
|
-
/** Участки пробок исходной трассы → скруглённой: номер точки — якорь исходного узла. */
|
|
2313
|
-
declare function roundedSpans(rr: RoundedRoute, spans: readonly TrafficSpan[]): TrafficSpan[];
|
|
2314
|
-
/** Диапазоны метров исходной трассы (куски под лентой по полосам) → метры скруглённой. */
|
|
2315
|
-
declare function roundedRanges(rr: RoundedRoute, ranges: readonly [number, number][]): [number, number][];
|
|
2316
|
-
|
|
2317
|
-
/**
|
|
2318
|
-
* МАШИНА ПО ЛЕНТЕ ПОЛОС — этап 1 «как обычный режим полос Baidu/Amap» (23.10.2026): в навигаторе машина едет не по оси
|
|
2319
|
-
* линии маршрута, а по оси РЕКОМЕНДОВАННОЙ полосы — той, по которой идёт лента (`buildRibbon`), и перестраивается
|
|
2320
|
-
* вместе с лентой.
|
|
2321
|
-
*
|
|
2322
|
-
* ★ ТА ЖЕ ГЕОМЕТРИЯ, ЧТО РИСУЕТ ЛЕНТУ. Сдвиг берётся не из плана заново, а из оси нарисованной основной ленты
|
|
2323
|
-
* (`Ribbon.car` — точки `band.line` с метрами `band.stations`): на прямой машина стоит ровно на оси ленты, на
|
|
2324
|
-
* перестроении идёт её же S-переходом (smoothstep на длине перестроения сервера, 40 м на полосу), на повороте через
|
|
2325
|
-
* узел — по её же дуге.
|
|
2326
|
-
*
|
|
2327
|
-
* ★ СДВИГ — ВЕКТОРОМ ОТ СКРУГЛЁННОЙ ЛИНИИ МАРШРУТА (`roundedPoint`): машина без ленты стоит на скруглённой трассе
|
|
2328
|
-
* (`roundedPose` — та же дуга, что у линии и стрелки поворота), и вектор «ось ленты − точка скруглённой трассы» на
|
|
2329
|
-
* том же метре, прибавленный к ней, ставит машину ровно на ось ленты и на дуге поворота. Боковой сдвиг по нормали
|
|
2330
|
-
* дал бы на повороте метры расхождения: дуга трассы (радиус 15 м) и дуга ленты (гаусс оси полосы) — разные кривые.
|
|
2331
|
-
* Вектор непрерывен по метру (обе точки непрерывны), поэтому рывков нет и на изломах трассы.
|
|
2332
|
-
*
|
|
2333
|
-
* ★ КУРС С БОКОВОЙ СОСТАВЛЯЮЩЕЙ: направление движения = касательная трассы + производная сдвига по метру
|
|
2334
|
-
* (центральная разность на ±`LANE_CAR_SLOPE_M`, непрерывна для кусочно-линейного сдвига). На перестроении машина
|
|
2335
|
-
* поворачивает носом в сторону новой полосы (до ≈7° на 40 м перестроения в полосу 3.5 м) и выпрямляется к его концу;
|
|
2336
|
-
* на дуге с постоянным сдвигом поворота не добавляется (касательная параллельной кривой та же).
|
|
2337
|
-
*
|
|
2338
|
-
* ★ ВЕС ПЛАНА (`RibbonCar.weights`, `carWeight`): 1 на куске покрытия (машина на ленте и там, где лента ещё
|
|
2339
|
-
* переходит из ленты вне покрытия в полосу) и `CAR_OUTSIDE_WEIGHT` вне покрытия — с 24.10.2026 тоже 1: машина едет
|
|
2340
|
-
* по ленте «полполосы справа», а не по линии маршрута левее неё (решение владельца; было 0 с подъездом smoothstep на
|
|
2341
|
-
* `JOIN_M`). Плавность на краях покрытия — у самой оси ленты (`RAMP_SLOPE`). Плана нет вовсе (сервис не ответил) —
|
|
2342
|
-
* нет и дорожки: машина на линии.
|
|
2343
|
-
*
|
|
2344
|
-
* ★ ВМЕСТЕ С ПЕРЕХОДОМ «ЛЕНТА ↔ ЛИНИЯ» (`RibbonBlend`): сдвиг умножается на `ribbonAlpha` — ниже зума ленты машина на
|
|
2345
|
-
* линии маршрута, на пороге съезжает в полосу (и обратно) за те же `RIBBON_BLEND_MS`, что идёт кросс-фейд. Гаснущая
|
|
2346
|
-
* прежняя лента (новый план) — своим слоем с `ribbonAlpha` своего перехода: сумма долей — 1, машина не прыгает.
|
|
2347
|
-
*
|
|
2348
|
-
* ★ КАМЕРА ИДЁТ ЗА ЛИНИЕЙ МАРШРУТА, А НЕ ЗА СДВИНУТОЙ МАШИНОЙ. Центр и курс камеры ведения считаются, как раньше, по
|
|
2349
|
-
* скруглённой трассе: на перестроении дорога на экране стоит, а машина переезжает в соседнюю полосу (как у Baidu и в
|
|
2350
|
-
* жизни). Камера за машиной рыскала бы вбок на каждом перестроении и на каждом входе в ленту — на 3–5 м за полсекунды.
|
|
2351
|
-
*
|
|
2352
|
-
* Метры — исходной трассы мерой сервера (`linkM`), те же, что у `Ribbon.hidden`, пройденной части и подъёма ленты.
|
|
2353
|
-
* Чистые функции; порты — `LaneCar.kt`, `LaneCar.swift`, `navigram/lane_car.cpp`, сверка —
|
|
2354
|
-
* `kmp/fixtures/nav-car/lane.json` (`scripts/gen-car-models.mjs`).
|
|
2355
|
-
*/
|
|
2356
|
-
|
|
2357
|
-
/** Половина шага центральной разности для курса, метры (шаг точек ленты — метр, оси перехода — 2 м). */
|
|
2358
|
-
declare const LANE_CAR_SLOPE_M = 2;
|
|
2359
|
-
/**
|
|
2360
|
-
* Шаг дорожки по метру трассы, метры (плюс сами метры точек ленты). Сдвиг между точками дорожки линеен, а скруглённая
|
|
2361
|
-
* линия на дуге — ломаная через 11° (`ROUTE_ROUND.ARC_STEP`): у точек ленты (через метр её собственной длины) метр
|
|
2362
|
-
* трассы на повороте шагает до 5 м, и линейный сдвиг по такому шагу уводил машину с ленты на 12 см; сетка через
|
|
2363
|
-
* полметра без точек ленты срезала излом оси на повороте через узел (9 см). Сетка с точками ленты — до 2 см.
|
|
2364
|
-
*/
|
|
2365
|
-
declare const LANE_CAR_STEP_M = 0.5;
|
|
2366
|
-
/** Сдвиг машины от скруглённой линии маршрута по метрам трассы: метры на восток и на север, уже с весом плана. */
|
|
2367
|
-
interface LaneCarTrack {
|
|
2368
|
-
stations: number[];
|
|
2369
|
-
east: number[];
|
|
2370
|
-
north: number[];
|
|
2371
|
-
}
|
|
2372
|
-
/**
|
|
2373
|
-
* МЕТРЫ ТОЧЕК ЛЕНТЫ — СТРОГО ПО ВОЗРАСТАНИЮ. На дуге поворота через узел (`filletTurn`) несколько точек оси получают
|
|
2374
|
-
* один метр (проекция точки дуги на трассу пошла бы назад, и метр держится): «точка ленты на метре» там скакала бы через
|
|
2375
|
-
* эти точки — машина прыгала бы на 2 м. Такой повтор раскладывается по длине оси между соседними метрами.
|
|
2376
|
-
*/
|
|
2377
|
-
declare function spreadStations(stations: number[], line: LonLat[]): number[];
|
|
2378
|
-
/**
|
|
2379
|
-
* Дорожка машины из оси основной ленты (`Ribbon.car`) и скруглённой трассы `rr` той же геометрии (`roundRoute`): через
|
|
2380
|
-
* `LANE_CAR_STEP_M` по метру и в метрах точек ленты — вектор «точка ленты − точка скруглённой линии» с весом плана. Где сдвига нет (вне плана),
|
|
2381
|
-
* точки не хранятся — только нули на краях: дорожка весит столько, сколько покрытие. Нет основной ленты — `null`.
|
|
2382
|
-
*/
|
|
2383
|
-
declare function laneCarTrack(car: RibbonCar | null | undefined, rr: RoundedRoute): LaneCarTrack | null;
|
|
2384
|
-
/** Сдвиг на метре `s` и его производная по метру (центральная разность на ±`LANE_CAR_SLOPE_M`). */
|
|
2385
|
-
declare function laneCarShift(track: LaneCarTrack, s: number): {
|
|
2386
|
-
east: number;
|
|
2387
|
-
north: number;
|
|
2388
|
-
dEast: number;
|
|
2389
|
-
dNorth: number;
|
|
2390
|
-
};
|
|
2391
|
-
/** Слой дорожки: дорожка ленты и её доля в позе (`RibbonBlend.ribbonAlpha`). */
|
|
2392
|
-
interface LaneCarLayer {
|
|
2393
|
-
track: LaneCarTrack | null;
|
|
2394
|
-
alpha: number;
|
|
2395
|
-
}
|
|
2396
|
-
/**
|
|
2397
|
-
* ПОЗА МАШИНЫ НА ЛЕНТЕ: `point`/`bearing` — поза на скруглённой линии маршрута на метре `s` (`roundedPose`), слои —
|
|
2398
|
-
* дорожки показанной и гаснущей лент с долями. Ни одна дорожка не участвует (нет ленты, доли нулевые, метр не число)
|
|
2399
|
-
* — поза как есть, бит в бит.
|
|
2400
|
-
*/
|
|
2401
|
-
declare function laneCarPose(point: LonLat, bearing: number, s: number, layers: readonly LaneCarLayer[]): {
|
|
2402
|
-
point: LonLat;
|
|
2403
|
-
bearing: number;
|
|
2404
|
-
};
|
|
2405
|
-
|
|
2406
|
-
/**
|
|
2407
|
-
* СТРЕЛКИ ПОВОРОТОВ НА ЛИНИИ МАРШРУТА — расположение и размеры как у навигатора `navigator-main`
|
|
2408
|
-
* (`sdk/.../map/RouteArrows.kt`, `RouteArrowLayers.kt`), а тот — по Organic Maps
|
|
2409
|
-
* (`libs/drape_frontend/route_renderer.cpp`, форма — `data/styles/default/light/symbols/route-arrow.svg`;
|
|
2410
|
-
* Apache-2.0, см. `porting/navigator-main.md`). Чистая геометрия, без GL: веб рисует её своими
|
|
2411
|
-
* многоугольниками (`Polygon`: тень, обводка, заливка), порты (`ManeuverArrows.kt`,
|
|
2412
|
-
* `ManeuverArrows.swift`) — так же; сверка — общие фикстуры `kmp/fixtures/maneuver-arrows`
|
|
2413
|
-
* (`node scripts/export-maneuver-arrows-fixture.mjs`).
|
|
2414
|
-
*
|
|
2415
|
-
* ★ РАСПОЛОЖЕНИЕ. Хвост — `BEFORE_M` (22 м) до узла манёвра, конец древка — `AFTER_M` (18 м) после
|
|
2416
|
-
* него: длина как у стрелки Яндекс.Навигатора (~40 м), по просьбе пользователя 08.10.2026 — стрелка
|
|
2417
|
-
* navigator-main / Organic Maps (36 + 54 = 90 м) на городских поворотах была слишком длинной. Близкие
|
|
2418
|
-
* манёвры (не дальше `NEARBY_M`, 50 м, друг от друга) — ОДНА стрелка от хвоста первого до головы
|
|
2419
|
-
* последнего: две короткие стрелки на одном перекрёстке читаются хуже одной изогнутой. Манёвр ближе
|
|
2420
|
-
* `END_MARGIN_M` к началу или концу трассы стрелки не получает.
|
|
2421
|
-
*
|
|
2422
|
-
* ★ РАЗМЕР — В ПИКСЕЛЯХ ЭКРАНА ПО ЗУМУ (как слои MapLibre у `navigator-main`), а не в метрах: древко
|
|
2423
|
-
* 5 → 10 → 12 px на z14/16/18, обводка 8 → 16 → 19 px, наконечник (треугольник 30×18 px с белым
|
|
2424
|
-
* 22×12 px внутри) — ×0.5 → ×1 → ×1.15; между узлами — линейно, за краями — край. Ниже `MIN_ZOOM` (14)
|
|
2425
|
-
* стрелок нет. Пиксели переводятся в метры по `metersPerPixel` на широте трассы; геометрию держит
|
|
2426
|
-
* кэш по ступени зума `ZOOM_STEP` (⅛: ширина прыгает не больше чем на 9 %).
|
|
2427
|
-
*
|
|
2428
|
-
* ★ ФОРМА. Древко идёт РОВНО ПО ТРАССЕ — своего сглаживания нет: скругляется сама трасса
|
|
2429
|
-
* (`route-round.ts`, радиус `ROUTE_ROUND.RADIUS_M`), и стрелка, построенная по скруглённой трассе,
|
|
2430
|
-
* лежит на линии маршрута по всей дуге (раньше ось сглаживалась своим ядром, и на повороте стрелка
|
|
2431
|
-
* уходила с угловатой линии). Сзади древко кончается полукругом, как круглый конец линии MapLibre. Наконечник —
|
|
2432
|
-
* прямой треугольник ЗА концом древка по его последнему направлению: основание обводки — ровно на
|
|
2433
|
-
* конце древка, белый — на `HEAD_FILL_INSET_PX` дальше (у `navigator-main` это значок с якорем
|
|
2434
|
-
* `bottom` в конце линии). Оформление: белая заливка, синяя обводка `#055FCD` и лёгкая тень (обводка,
|
|
2435
|
-
* раздутая на `SHADOW_PX`) — тень наша, на объёмной карте стрелка без неё «прилипает» к асфальту.
|
|
2436
|
-
*
|
|
2437
|
-
* ★ МЕТРЫ — МЕРОЙ ЛИНИИ МАРШРУТА (`routeLine`, `linkM`): манёвры приходят метрами той же трассы
|
|
2438
|
-
* (`metresAlong` по точкам шагов).
|
|
2439
|
-
*
|
|
2440
|
-
* ★ ГАСНЕТ ПЛАВНО, КАК ЛЕНТА (26.10.2026, просьба владельца «стрелки в поворотах исчезали плавно, как лента
|
|
2441
|
-
* маршрута»). Раньше стрелка снималась целиком на метре конца древка (`toM`): машина ещё не доехала до острия,
|
|
2442
|
-
* а стрелка пропадала ступенькой; смена трассы, вида (линия ↔ лента) и порог `MIN_ZOOM` — тоже ступенькой.
|
|
2443
|
-
* Теперь два закона, оба — общие с лентой:
|
|
2444
|
-
* · ПРОЙДЕННОЕ РАСТВОРЯЕТСЯ ПОЗАДИ МАШИНЫ ПО МЕТРУ ТРАССЫ: у каждой точки колец — метр трассы
|
|
2445
|
-
* (`fillStations`/`casingStations`/`shadowStations`, проекция на ось стрелки), площади рисуются с
|
|
2446
|
-
* `MapObject.along` (метр машины, `PASS_FADE_M` = `RIBBON_PASS_FADE_M`, сторона +1) — тот же шейдер и тот же
|
|
2447
|
-
* `alongFadeFactor`, что у ленты (`RibbonAreas.passAt`), без пересборки. Стрелка видна, пока её дальний край
|
|
2448
|
-
* (`endM`, острие тени) не ушёл за длину растворения (`shownManeuverArrows(…, passFadeM)`) — к этому метру она
|
|
2449
|
-
* уже прозрачна вся;
|
|
2450
|
-
* · СНЯТИЕ ЦЕЛИКОМ — ПО ВРЕМЕНИ (`ArrowFades`): стрелка, ушедшая из набора (другая трасса, вид линия ↔ лента,
|
|
2451
|
-
* порог зума, выключатель), гаснет за `RIBBON_BLEND_MS` тем же законом, что кросс-фейд «лента ↔ линия»
|
|
2452
|
-
* (`RibbonBlend`: шаг за кадр не больше `RIBBON_BLEND_STEP_MAX_MS`, доля `smoothstep`), а новая так же
|
|
2453
|
-
* проявляется. Смена СТУПЕНИ зума — тот же ключ: множитель переходит к стрелке новой ступени сразу (стрелки
|
|
2454
|
-
* соседних ступеней стоят наготове, 1ddcb20a).
|
|
2455
|
-
*/
|
|
2456
|
-
|
|
2457
|
-
/** Константы стрелки: метры (`_M`), пиксели экрана (`_PX`) и узлы «зум → пиксели» (`[зум, px]`). */
|
|
2458
|
-
declare const MANEUVER_ARROW: {
|
|
2459
|
-
/** Хвост — столько до узла (первого) манёвра. */
|
|
2460
|
-
readonly BEFORE_M: 22;
|
|
2461
|
-
/** Конец древка — столько после узла (последнего) манёвра; наконечник — за ним. */
|
|
2462
|
-
readonly AFTER_M: 18;
|
|
2463
|
-
/** Манёвры не дальше этого друг от друга — одна стрелка. */
|
|
2464
|
-
readonly NEARBY_M: 50;
|
|
2465
|
-
/** Ближе этого к началу или концу трассы манёвр стрелки не получает. */
|
|
2466
|
-
readonly END_MARGIN_M: 3;
|
|
2467
|
-
/** Ниже этого зума стрелок нет. */
|
|
2468
|
-
readonly MIN_ZOOM: 14;
|
|
2469
|
-
/** Ширина белого древка, px по зуму. */
|
|
2470
|
-
readonly BODY_PX: ReadonlyArray<readonly [number, number]>;
|
|
2471
|
-
/** Ширина синей обводки древка (вся, не кайма), px по зуму. */
|
|
2472
|
-
readonly BORDER_PX: ReadonlyArray<readonly [number, number]>;
|
|
2473
|
-
/** Множитель наконечника по зуму. */
|
|
2474
|
-
readonly HEAD_SCALE: ReadonlyArray<readonly [number, number]>;
|
|
2475
|
-
/** Наконечник обводки: полуширина основания и длина, px при множителе 1. */
|
|
2476
|
-
readonly HEAD_BORDER_HALF_PX: 15;
|
|
2477
|
-
readonly HEAD_BORDER_LEN_PX: 18;
|
|
2478
|
-
/** Белый наконечник: полуширина, длина и отступ основания от конца древка, px при множителе 1. */
|
|
2479
|
-
readonly HEAD_FILL_HALF_PX: 11;
|
|
2480
|
-
readonly HEAD_FILL_LEN_PX: 12;
|
|
2481
|
-
readonly HEAD_FILL_INSET_PX: 3;
|
|
2482
|
-
/** Скругление углов (остриё остаётся острым) и тень, px. */
|
|
2483
|
-
readonly ROUND_PX: 0.75;
|
|
2484
|
-
readonly SHADOW_PX: 2.5;
|
|
2485
|
-
/** Шаг дуги скругления, радианы. */
|
|
2486
|
-
readonly ARC_STEP: number;
|
|
2487
|
-
/** Шаг переразбивки оси, метры (своего сглаживания нет — ось = трасса). */
|
|
2488
|
-
readonly STEP_M: 1;
|
|
2489
|
-
/** Цвета и прозрачности: белая стрелка, синяя обводка (`navigator-main`), лёгкая тень. */
|
|
2490
|
-
readonly FILL: "#ffffff";
|
|
2491
|
-
readonly CASING: "#055fcd";
|
|
2492
|
-
readonly SHADOW: "#0b1a3a";
|
|
2493
|
-
readonly FILL_OPACITY: 1;
|
|
2494
|
-
readonly CASING_OPACITY: 1;
|
|
2495
|
-
readonly SHADOW_OPACITY: 0.18;
|
|
2496
|
-
/**
|
|
2497
|
-
* Высота над отметкой трассы — ТА ЖЕ, ЧТО У ЛИНИИ МАРШРУТА и ленты по полосам (`OVERLAY_ALTITUDE`,
|
|
2498
|
-
* `ROUTE_TOP` в `ld-roads.ts`): стрелка лежит на одной с ними поверхности, на эстакаде — на настиле
|
|
2499
|
-
* (отметка трассы под каждой вершиной, `routeLiftField`). Над линией её держит порядок (`Z_*`), над
|
|
2500
|
-
* асфальтом — сдвиг глубины прохода объектов. Было 0.4 — над лентой на 0.34.
|
|
2501
|
-
*/
|
|
2502
|
-
readonly LIFT_M: 0.28;
|
|
2503
|
-
/** Порядок среди объектов: над пройденной линией (21). */
|
|
2504
|
-
readonly Z_SHADOW: 23;
|
|
2505
|
-
readonly Z_CASING: 24;
|
|
2506
|
-
readonly Z_FILL: 25;
|
|
2507
|
-
/** Ступень зума для кэша геометрии. */
|
|
2508
|
-
readonly ZOOM_STEP: 0.125;
|
|
2509
|
-
/** Длина растворения пройденной части позади машины, метры — та же, что у ленты (`RIBBON_PASS_FADE_M`). */
|
|
2510
|
-
readonly PASS_FADE_M: 20;
|
|
2511
|
-
};
|
|
2512
|
-
/** Манёвр на трассе: метр (мерой линии маршрута) и вид шага (`type` + `modifier`, как у `/route`). */
|
|
2513
|
-
interface ManeuverAt {
|
|
2514
|
-
atM: number;
|
|
2515
|
-
type: string;
|
|
2516
|
-
modifier?: string;
|
|
2517
|
-
}
|
|
2518
|
-
/** Стрелка манёвра (или группы близких манёвров). Кольца замкнуты (первая точка повторена в конце), против часовой. */
|
|
2519
|
-
interface ManeuverArrow {
|
|
2520
|
-
/** Номер первого манёвра группы во входном списке. */
|
|
2521
|
-
index: number;
|
|
2522
|
-
/** Номера всех манёвров группы (по ходу). */
|
|
2523
|
-
indices: number[];
|
|
2524
|
-
/** Метр первого манёвра группы. */
|
|
2525
|
-
atM: number;
|
|
2526
|
-
/** Метры трассы, которые занимает древко: от хвоста до основания наконечника. */
|
|
2527
|
-
fromM: number;
|
|
2528
|
-
toM: number;
|
|
2529
|
-
/** Сглаженная ось древка от хвоста до основания наконечника. */
|
|
2530
|
-
line: LonLat[];
|
|
2531
|
-
/** Сама стрелка (белая). */
|
|
2532
|
-
fill: LonLat[];
|
|
2533
|
-
/** Синяя обводка — шире древко и больше наконечник. */
|
|
2534
|
-
casing: LonLat[];
|
|
2535
|
-
/** Лёгкая тень — обводка, раздутая на `SHADOW_PX`. */
|
|
2536
|
-
shadow: LonLat[];
|
|
2537
|
-
/**
|
|
2538
|
-
* Метр трассы в каждой точке колец (`fill`, `casing`, `shadow`; та же длина, замыкающая точка — тоже): проекция на
|
|
2539
|
-
* ось стрелки, доля её длины — в метры `fromM…toM`, за концами оси — продолжение по прямой (хвост, острие). По ним
|
|
2540
|
-
* площадь растворяется позади машины (`RouteArea.stations` + `MapObject.along`). Мера — та же, что у `fromM`/`toM`.
|
|
2541
|
-
*/
|
|
2542
|
-
fillStations: number[];
|
|
2543
|
-
casingStations: number[];
|
|
2544
|
-
shadowStations: number[];
|
|
2545
|
-
/** Дальний край стрелки по трассе — наибольший метр точек тени (острие с тенью). */
|
|
2546
|
-
endM: number;
|
|
2547
|
-
}
|
|
2548
|
-
interface ManeuverArrowOptions {
|
|
2549
|
-
/** Зум, под который строятся размеры (по умолчанию 16 — множитель наконечника 1). */
|
|
2550
|
-
zoom?: number;
|
|
2551
|
-
/** Метры в пикселе экрана; по умолчанию — `metersPerPixel` на широте начала трассы и зуме `zoom`. */
|
|
2552
|
-
metersPerPixel?: number;
|
|
2553
|
-
}
|
|
2554
|
-
/** Размеры стрелки в метрах на зуме. */
|
|
2555
|
-
interface ManeuverArrowSize {
|
|
2556
|
-
bodyHalfM: number;
|
|
2557
|
-
borderHalfM: number;
|
|
2558
|
-
headBorderHalfM: number;
|
|
2559
|
-
headBorderLenM: number;
|
|
2560
|
-
headFillHalfM: number;
|
|
2561
|
-
headFillLenM: number;
|
|
2562
|
-
headFillInsetM: number;
|
|
2563
|
-
roundM: number;
|
|
2564
|
-
shadowM: number;
|
|
2565
|
-
}
|
|
2566
|
-
/**
|
|
2567
|
-
* Нужна ли манёвру стрелка — `hasRouteArrow` у `navigator-main`: настоящие повороты, развилки, съезды
|
|
2568
|
-
* и кольцо — всегда; `continue`/`new name` — только если дорога меняет направление (модификатор не
|
|
2569
|
-
* «прямо»); старт, финиш, полосы, уведомления — нет.
|
|
2570
|
-
*/
|
|
2571
|
-
declare function maneuverNeedsArrow(type: string, modifier?: string): boolean;
|
|
2572
|
-
/** Значение узлов `[зум, значение]` на зуме: между узлами — линейно, за краями — край (как `interpolate` MapLibre). */
|
|
2573
|
-
declare function zoomStops(stops: ReadonlyArray<readonly [number, number]>, zoom: number): number;
|
|
2574
|
-
/** Ступень зума для кэша геометрии (`ZOOM_STEP`); `Math.round` веба. */
|
|
2575
|
-
declare function maneuverArrowZoomStep(zoom: number): number;
|
|
2576
|
-
/** Размеры стрелки в метрах: пиксели узлов на зуме `zoom`, умноженные на метры в пикселе. */
|
|
2577
|
-
declare function maneuverArrowSize(zoom: number, metersPerPixel: number): ManeuverArrowSize;
|
|
2578
|
-
/**
|
|
2579
|
-
* Контур, раздутый наружу на `d` со СКРУГЛЁННЫМИ выпуклыми углами (сумма Минковского с кругом —
|
|
2580
|
-
* то же, что сдвиг порога знакового расстояния у шейдера пробок). Кольцо против часовой, без повтора
|
|
2581
|
-
* первой точки. Вогнутые углы — пересечением сдвинутых сторон.
|
|
2582
|
-
*/
|
|
2583
|
-
declare function inflateRound(ring: XY[], d: number): XY[];
|
|
2584
|
-
/**
|
|
2585
|
-
* Стрелки манёвров на трассе `geometry` (`[lon, lat]` по ходу). `maneuvers` — метры манёвров мерой
|
|
2586
|
-
* линии маршрута (по возрастанию не обязательно). Стрелка — каждому, кому она нужна
|
|
2587
|
-
* (`maneuverNeedsArrow`); манёвры не дальше `NEARBY_M` друг от друга — одной стрелкой.
|
|
2588
|
-
*/
|
|
2589
|
-
declare function maneuverArrows(geometry: LonLat[], maneuvers: ManeuverAt[], opts?: ManeuverArrowOptions): ManeuverArrow[];
|
|
2590
|
-
/**
|
|
2591
|
-
* СТРЕЛКА ЛЕНТЫ — доли ширины полосы ленты (как стрелки полосного вида Apple Maps и Google): белое
|
|
2592
|
-
* древко ≈ 60 % ширины ленты, синяя обводка ≈ 72 %, наконечник — почти во всю ширину, но внутри неё.
|
|
2593
|
-
*/
|
|
2594
|
-
declare const RIBBON_ARROW: {
|
|
2595
|
-
readonly BODY: 0.3;
|
|
2596
|
-
readonly BORDER: 0.36;
|
|
2597
|
-
readonly HEAD_FILL_HALF: 0.4;
|
|
2598
|
-
readonly HEAD_BORDER_HALF: 0.47;
|
|
2599
|
-
readonly HEAD_FILL_LEN: 0.9;
|
|
2600
|
-
readonly HEAD_BORDER_LEN: 1.1;
|
|
2601
|
-
readonly HEAD_FILL_INSET: 0.15;
|
|
2602
|
-
readonly ROUND: 0.05;
|
|
2603
|
-
readonly SHADOW: 0.04;
|
|
2604
|
-
/** Лента должна идти за узлом манёвра хотя бы столько, чтобы у стрелки была голова на ленте. */
|
|
2605
|
-
readonly MIN_AFTER_M: 8;
|
|
2606
|
-
/**
|
|
2607
|
-
* Голова — на выходе из поворота: если у конца древка лента ещё поворачивает (разворот, крутой
|
|
2608
|
-
* поворот — направление на `SETTLE_PROBE_M` вперёд меняется больше `SETTLE_DEG`), конец сдвигается
|
|
2609
|
-
* вперёд шагом `SETTLE_STEP_M`, но не дальше `SETTLE_MAX_M` за последним узлом.
|
|
2610
|
-
*/
|
|
2611
|
-
readonly SETTLE_PROBE_M: 4;
|
|
2612
|
-
/** Вперёд направление берётся на `SETTLE_AHEAD_M` — прямой кусок посреди разворота (через разделитель) не считается выходом. */
|
|
2613
|
-
readonly SETTLE_AHEAD_M: 12;
|
|
2614
|
-
readonly SETTLE_TAIL_M: 6;
|
|
2615
|
-
readonly SETTLE_DEG: 15;
|
|
2616
|
-
readonly SETTLE_STEP_M: 1;
|
|
2617
|
-
readonly SETTLE_MAX_M: 40;
|
|
2618
|
-
};
|
|
2619
|
-
/**
|
|
2620
|
-
* СТРЕЛКИ МАНЁВРОВ НА ЛЕНТЕ ПО ПОЛОСАМ: ось — сама основная лента (`band`: та же дорожка по полосам,
|
|
2621
|
-
* что рисует лента, — с поворотом и разворотом), ширина — доли ширины ленты у узла манёвра (`RIBBON_ARROW`),
|
|
2622
|
-
* голова — у выхода, внутри ленты (ось не продлевается за её конец). Группы манёвров и длины — как у
|
|
2623
|
-
* стрелок линии (`BEFORE_M`, `AFTER_M`, `NEARBY_M`). `maneuvers` — метры мерой ИСХОДНОЙ трассы ленты
|
|
2624
|
-
* (как станции её фич). Манёвр, у которого ленты нет (узел вне основной ленты или лента кончается
|
|
2625
|
-
* раньше `MIN_AFTER_M` за ним), стрелки ленты не получает — у него остаётся стрелка линии.
|
|
2626
|
-
*/
|
|
2627
|
-
declare function ribbonManeuverArrows(ribbon: Ribbon, maneuvers: ManeuverAt[]): ManeuverArrow[];
|
|
2628
|
-
/**
|
|
2629
|
-
* Какие стрелки показывать: ниже `MIN_ZOOM` — никакие; выше — все, кроме пройденных (`null` — ведения нет).
|
|
2630
|
-
* Пройденная без растворения (`passFadeM` = 0) — конец древка позади `progressM`; с растворением позади машины
|
|
2631
|
-
* (`passFadeM` > 0, обычно `PASS_FADE_M`) — дальний край стрелки (`endM`) позади `progressM − passFadeM`: там она
|
|
2632
|
-
* прозрачна вся, и снятие не видно. Возвращает номера в списке `arrows`.
|
|
2633
|
-
*/
|
|
2634
|
-
declare function shownManeuverArrows(arrows: ManeuverArrow[], progressM: number | null, zoom: number, passFadeM?: number): number[];
|
|
2635
|
-
/**
|
|
2636
|
-
* ПОЯВЛЕНИЕ И СНЯТИЕ СТРЕЛОК ПО ВРЕМЕНИ — тем же законом, что кросс-фейд «лента ↔ линия» (`RibbonBlend`). Ключ —
|
|
2637
|
-
* стрелка в своём виде (слой решает сам: поколение трассы, вид линия/лента, первый манёвр группы; ступень зума в ключ
|
|
2638
|
-
* НЕ входит — смена ступени мгновенна). У ключа значение `t` 0…1 и цель (видна / снята):
|
|
2639
|
-
* · `show(keys)` — видны ровно эти; новый ключ заводится с `t` = 0 и проявляется, прочие гаснут;
|
|
2640
|
-
* · `tick(nowMs)` — кадр: `t` идёт к цели со скоростью `1 / RIBBON_BLEND_MS`, за кадр не больше
|
|
2641
|
-
* `RIBBON_BLEND_STEP_MAX_MS` часов; первый кадр, пропуск дольше секунды и часы назад — без шага. Снятый ключ,
|
|
2642
|
-
* дошедший до нуля, убирается (`gone` — их список за этот кадр: слою пора снять его объекты). true — переход идёт;
|
|
2643
|
-
* · `settle()` — сразу к цели, без перехода (слой без часов: проверки);
|
|
2644
|
-
* · `alpha(key)` — множитель прозрачности объектов ключа: `smoothstep(t)`; нет ключа — 0.
|
|
2645
|
-
*/
|
|
2646
|
-
declare class ArrowFades {
|
|
2647
|
-
private items;
|
|
2648
|
-
private at;
|
|
2649
|
-
/** Ключи, снятые до нуля последним `tick`/`settle`. */
|
|
2650
|
-
gone: string[];
|
|
2651
|
-
show(keys: Iterable<string>): void;
|
|
2652
|
-
tick(nowMs: number): boolean;
|
|
2653
|
-
settle(): void;
|
|
2654
|
-
alpha(key: string): number;
|
|
2655
|
-
has(key: string): boolean;
|
|
2656
|
-
/** Переход идёт хоть у одного ключа. */
|
|
2657
|
-
get animating(): boolean;
|
|
2658
|
-
}
|
|
2659
|
-
|
|
2660
|
-
export { LD_MARK_PREFIX as $, ABSENT_RETRY_MS as A, type BuildOptions as B, CAP_SEGMENTS as C, DEFAULT_RIBBON_CAP as D, EMPTY_GEOJSON as E, FAR_VIEW as F, type Frame as G, GROUND_LAYERS as H, GROUND_TOP as I, GUIDANCE_URL as J, type GuideFrame as K, HINT_M as L, type HeightAt as M, type HintLane as N, JOIN_M as O, LANE_CAR_SLOPE_M as P, LANE_CAR_STEP_M as Q, LANE_MIN_ZOOM as R, LANE_OFF_ZOOM as S, LANE_ON_ZOOM as T, LANE_PROGRESS_MIN_MS as U, LANE_RIBBON_CHEVRON_LAYER as V, LANE_SOURCE as W, LD_AFTER as X, LD_INDEX_PATH as Y, LD_LAYER_PREFIX as Z, LD_MARK_FADE_ZOOM as _, ARROW_TIP_K as a, PUCK_GLIDE_MAX_MS as a$, LD_SOURCE as a0, LEVEL_HEIGHT_M as a1, type LaneCarLayer as a2, type LaneCarTrack as a3, LaneGuide as a4, type LaneHint as a5, type LanePlan as a6, type LanePlanRequest as a7, type LaneRoute as a8, type LaneState as a9, type NavCarPart as aA, type NavCarPose as aB, type NavFix as aC, NavFixFilter as aD, type NavFixVerdict as aE, NavProgress as aF, type NavProgressOut as aG, NavPuck as aH, OBJECTS3D_LAYER_ID as aI, OBJECTS3D_LAYOUT as aJ, OBJECTS3D_SOURCE as aK, OUTLINE_STEP_M as aL, OUTSIDE_LANE_M as aM, OVERLAY_ALTITUDE as aN, type OutsideOptions as aO, PASSED_MIN_M as aP, PROG_AHEAD as aQ, PROG_BACK_CONFIRM as aR, PROG_BACK_M as aS, PROG_BACK_MIN as aT, PROG_COARSE_HOLD_MS as aU, PROG_JUMP_CONFIRM as aV, PROG_NEAR_M as aW, PROG_NEAR_MPS as aX, PROG_SWITCH_M as aY, PROG_WIDE_M as aZ, PROG_WIDE_ON_M as a_, type LdIndex as aa, type LdStyle as ab, type LiftField as ac, type LiftProfile as ad, type LonLat as ae, MANEUVER_ARROW as af, type ManeuverArrow as ag, type ManeuverArrowOptions as ah, type ManeuverArrowSize as ai, type ManeuverAt as aj, type Mask as ak, type Measured as al, NAV_ARROW as am, NAV_ARROW_PALETTES as an, NAV_CAR as ao, NAV_CAR_BODIES as ap, NAV_CAR_KINDS as aq, NAV_CAR_LABELS as ar, type NavArrowPalette as as, type NavCarBody as at, type NavCarHost as au, type NavCarIcon as av, type NavCarKind as aw, type NavCarMaterial as ax, type NavCarModelKind as ay, NavCarOverlay as az, type AreaFrame as b, type RoutePiece as b$, PUCK_GLIDE_MIN_MS as b0, PUCK_STILL_MAX_M as b1, PUCK_STILL_MIN_M as b2, PUCK_STILL_MPS as b3, PUCK_TELEPORT_M as b4, type PassArea as b5, type PassChevron as b6, type PlanChange as b7, type PlanLane as b8, type PlanManeuver as b9, ROUTE_PASS_FADE_M as bA, ROUTE_POINT_COLORS as bB, ROUTE_POSE_SPAN_M as bC, ROUTE_ROUND as bD, ROUTE_TOP as bE, ROUTE_TRAFFIC as bF, type Ribbon as bG, type RibbonArea as bH, RibbonAreas as bI, RibbonBlend as bJ, type RibbonCap as bK, type RibbonCar as bL, type RibbonChevron as bM, type RibbonFade as bN, type RibbonFeature as bO, RibbonGeoJson as bP, type RibbonGeoJsonData as bQ, type RibbonGeoJsonFeature as bR, type RibbonKind as bS, type RibbonPiece as bT, type RoadbedMode as bU, type RoundedRoute as bV, type RouteLiftAt as bW, type RouteLine as bX, type RouteLineOptions as bY, type RouteLinePiece as bZ, type RouteManeuver as b_, type PlanSegment as ba, RAMP_SLOPE as bb, RIBBON_AREA_PAINT as bc, RIBBON_ARROW as bd, RIBBON_BLEND_MS as be, RIBBON_BLEND_STEP_MAX_MS as bf, RIBBON_CAPS as bg, RIBBON_CHEVRON as bh, RIBBON_FADE_M as bi, RIBBON_FADE_REACH_M as bj, RIBBON_FADE_STEP_M as bk, RIBBON_MARGIN_M as bl, RIBBON_PASS_FADE_M as bm, RIBBON_PASS_MARGIN_M as bn, RIBBON_STEP_M as bo, RIBBON_TILE_Z as bp, ROADBED_FIXED_PAINT as bq, ROADBED_LAYER_IDS as br, ROADBED_SOURCE as bs, ROADBED_URL as bt, ROADMARK_LAYER_IDS as bu, ROUTE_BLUE as bv, ROUTE_LIFT_REACH_M as bw, ROUTE_LINE as bx, ROUTE_NAV_OPACITY as by, ROUTE_PASSED as bz, type AreaSpan as c, lateralAt as c$, SITE_ENDPOINTS as c0, type SceneFeature as c1, type SurfaceAt as c2, type SurfaceMesh as c3, THEME_ATLAS_DAY as c4, THEME_ATLAS_NIGHT as c5, THEME_DARK as c6, THEME_DARK_TONE as c7, THEME_ICE as c8, THEME_ICE_TONE as c9, fetchLanePlan as cA, fmt1 as cB, fmt4 as cC, fracIndex as cD, frameAt as cE, fromUnits as cF, groundUnderBed as cG, guidanceCamera as cH, heightsFromScene as cI, hintAt as cJ, hintFor as cK, hintNear as cL, iceThemeFor as cM, inflateRound as cN, isAtlasTheme as cO, isDarkTheme as cP, isIceTheme as cQ, isNetworkFix as cR, isOldFix as cS, isRibbonCap as cT, laneCarPose as cU, laneCarShift as cV, laneCarTrack as cW, lanePlanRequest as cX, laneRibbonLayerIds as cY, laneRibbonLayers as cZ, laneTrack as c_, THEME_LIGHT as ca, THEME_LIGHT_TONE as cb, TILE_EXTENT as cc, TURN_MIN_DEG as cd, TURN_WINDOW_M as ce, type Track as cf, type TrafficSpan as cg, WIDTH_SMOOTH_PTS as ch, type XY as ci, areaFrame as cj, areaSpans as ck, bearingAt as cl, buildRibbon as cm, capPoints as cn, carWeight as co, chevronRunBase as cp, cityStyle as cq, closeness as cr, contiguousGroups as cs, cutInset as ct, densify as cu, edgesOf as cv, evenWidths as cw, fadeRibbonArea as cx, fadeRibbonLine as cy, fallbackHeight as cz, ArrowFades as d, ribbonProgressState as d$, ldLayerIds as d0, ldRoadbedPath as d1, ldSource as d2, ldStylePath as d3, liftProps as d4, liftPropsOf as d5, lineBetween as d6, linkM as d7, maneuverArrowSize as d8, maneuverArrowZoomStep as d9, normalsOf as dA, objects3dSource as dB, offsetLine as dC, offsetPoint as dD, originOf as dE, outlineOf as dF, outsideRanges as dG, parseLanePlan as dH, parseLdIndex as dI, parseLdStyle as dJ, passedKind as dK, passedLineOptions as dL, passedPieces as dM, pointAt as dN, pointOn as dO, project as dP, resampleLine as dQ, resetLanePlanAbsence as dR, resolveUrl as dS, ribbonAtProgress as dT, ribbonChevrons as dU, ribbonFade as dV, ribbonFadeAlpha as dW, ribbonGeoJson as dX, ribbonLineHidden as dY, ribbonManeuverArrows as dZ, ribbonPassChevrons as d_, maneuverArrows as da, maneuverNeedsArrow as db, maskOf as dc, measure as dd, measureRoute as de, mergeRanges as df, meshSurface as dg, metresAlong as dh, minusMask as di, mixLevel as dj, mixLonLat as dk, mixNum as dl, navArrowOutline as dm, navCarColor as dn, navCarGlb as dp, navCarHash as dq, navCarIcon as dr, navCarIconSvg as ds, navCarKind as dt, navCarLiftAt as du, navCarMesh as dv, navCarModelId as dw, navCarPose as dx, naviGramSources as dy, normalCdf as dz, CAR_OUTSIDE_WEIGHT as e, roadbedLayerIds as e0, roadbedModeFilters as e1, roadbedSource as e2, roadbedStyle as e3, roundRoute as e4, roundedMetre as e5, roundedPoint as e6, roundedPose as e7, roundedRanges as e8, roundedSpans as e9, stationsBetween as eA, tangentAt as eB, terrainStyle as eC, themeFor as eD, themeForRoadbed as eE, themeV2 as eF, tileParts as eG, toUnits as eH, trackAt as eI, trafficSegments as eJ, upcoming as eK, valueAt as eL, withAbsoluteTiles as eM, withLaneRibbon as eN, withLdRoads as eO, withObjects3D as eP, withWindowsInTone as eQ, zoomStops as eR, routeLiftAt as ea, routeLiftField as eb, routeLiftProfiles as ec, routeLine as ed, routeLineAlong as ee, routeLineOptions as ef, routeLinePieces as eg, routeMeasure as eh, routePieces as ei, routePointColor as ej, routeSurfaceField as ek, routeTrafficBlendM as el, routeTrafficColor as em, routeTrafficLevel as en, shownManeuverArrows as eo, simplifyIdx as ep, sliceAt as eq, sliceLine as er, smoothCorners as es, smoothWidths as et, smoothstep as eu, snapWindow as ev, spanLine as ew, spanOutline as ex, spansForPiece as ey, spreadStations as ez, CHEVRON_MIN_RUN_M as f, CHEVRON_TOLERANCE_M as g, CHUNK_M as h, CLOSE_M as i, CLOSE_VIEW as j, CORNER_DEG as k, CORNER_SMOOTH_M as l, CUT_BLEED as m, EVEN_WIDTH_M as n, Endpoints as o, FIX_ACC_MAX as p, FIX_ACC_ROUTE as q, FIX_MAX_AGE_MS as r, FIX_NET_ACC as s, FIX_NET_HOLD_MS as t, FIX_REJECT_RESET as u, FIX_SKEW_MIN_MS as v, FIX_STREAM_JITTER_MS as w, FIX_VMAX as x, type FetchLanePlanOptions as y, type FetchLike as z };
|